Auto merge of #141961 - matthiaskrgr:rollup-r09j2sp, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - rust-lang/rust#141724 (fix(rust-lang/rust#141141): When expanding `PartialEq`, check equality of scalar types first.) - rust-lang/rust#141833 (`tests/ui`: A New Order [2/N]) - rust-lang/rust#141861 (Switch `x86_64-msvc-{1,2}` back to Windows Server 2025 images) - rust-lang/rust#141914 (redesign stage 0 std follow-ups) - rust-lang/rust#141918 (Deconstruct values in the THIR visitor) - rust-lang/rust#141923 (Update books) - rust-lang/rust#141931 (Deconstruct values in the THIR visitor) - rust-lang/rust#141956 (Remove two trait methods from cg_ssa) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a124fb3cb7
34 changed files with 680 additions and 248 deletions
|
|
@ -2465,6 +2465,39 @@ impl TyKind {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this type is considered a scalar primitive (e.g.,
|
||||
/// `i32`, `u8`, `bool`, etc).
|
||||
///
|
||||
/// This check is based on **symbol equality** and does **not** remove any
|
||||
/// path prefixes or references. If a type alias or shadowing is present
|
||||
/// (e.g., `type i32 = CustomType;`), this method will still return `true`
|
||||
/// for `i32`, even though it may not refer to the primitive type.
|
||||
pub fn maybe_scalar(&self) -> bool {
|
||||
let Some(ty_sym) = self.is_simple_path() else {
|
||||
// unit type
|
||||
return self.is_unit();
|
||||
};
|
||||
matches!(
|
||||
ty_sym,
|
||||
sym::i8
|
||||
| sym::i16
|
||||
| sym::i32
|
||||
| sym::i64
|
||||
| sym::i128
|
||||
| sym::u8
|
||||
| sym::u16
|
||||
| sym::u32
|
||||
| sym::u64
|
||||
| sym::u128
|
||||
| sym::f16
|
||||
| sym::f32
|
||||
| sym::f64
|
||||
| sym::f128
|
||||
| sym::char
|
||||
| sym::bool
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A pattern type pattern.
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ use crate::deriving::generic::ty::*;
|
|||
use crate::deriving::generic::*;
|
||||
use crate::deriving::{path_local, path_std};
|
||||
|
||||
/// Expands a `#[derive(PartialEq)]` attribute into an implementation for the
|
||||
/// target item.
|
||||
pub(crate) fn expand_deriving_partial_eq(
|
||||
cx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
|
|
@ -16,62 +18,6 @@ pub(crate) fn expand_deriving_partial_eq(
|
|||
push: &mut dyn FnMut(Annotatable),
|
||||
is_const: bool,
|
||||
) {
|
||||
fn cs_eq(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
|
||||
let base = true;
|
||||
let expr = cs_fold(
|
||||
true, // use foldl
|
||||
cx,
|
||||
span,
|
||||
substr,
|
||||
|cx, fold| match fold {
|
||||
CsFold::Single(field) => {
|
||||
let [other_expr] = &field.other_selflike_exprs[..] else {
|
||||
cx.dcx()
|
||||
.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
|
||||
};
|
||||
|
||||
// We received arguments of type `&T`. Convert them to type `T` by stripping
|
||||
// any leading `&`. This isn't necessary for type checking, but
|
||||
// it results in better error messages if something goes wrong.
|
||||
//
|
||||
// Note: for arguments that look like `&{ x }`, which occur with packed
|
||||
// structs, this would cause expressions like `{ self.x } == { other.x }`,
|
||||
// which isn't valid Rust syntax. This wouldn't break compilation because these
|
||||
// AST nodes are constructed within the compiler. But it would mean that code
|
||||
// printed by `-Zunpretty=expanded` (or `cargo expand`) would have invalid
|
||||
// syntax, which would be suboptimal. So we wrap these in parens, giving
|
||||
// `({ self.x }) == ({ other.x })`, which is valid syntax.
|
||||
let convert = |expr: &P<Expr>| {
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) =
|
||||
&expr.kind
|
||||
{
|
||||
if let ExprKind::Block(..) = &inner.kind {
|
||||
// `&{ x }` form: remove the `&`, add parens.
|
||||
cx.expr_paren(field.span, inner.clone())
|
||||
} else {
|
||||
// `&x` form: remove the `&`.
|
||||
inner.clone()
|
||||
}
|
||||
} else {
|
||||
expr.clone()
|
||||
}
|
||||
};
|
||||
cx.expr_binary(
|
||||
field.span,
|
||||
BinOpKind::Eq,
|
||||
convert(&field.self_expr),
|
||||
convert(other_expr),
|
||||
)
|
||||
}
|
||||
CsFold::Combine(span, expr1, expr2) => {
|
||||
cx.expr_binary(span, BinOpKind::And, expr1, expr2)
|
||||
}
|
||||
CsFold::Fieldless => cx.expr_bool(span, base),
|
||||
},
|
||||
);
|
||||
BlockOrExpr::new_expr(expr)
|
||||
}
|
||||
|
||||
let structural_trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(marker::StructuralPartialEq),
|
||||
|
|
@ -97,7 +43,9 @@ pub(crate) fn expand_deriving_partial_eq(
|
|||
ret_ty: Path(path_local!(bool)),
|
||||
attributes: thin_vec![cx.attr_word(sym::inline, span)],
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))),
|
||||
combine_substructure: combine_substructure(Box::new(|a, b, c| {
|
||||
BlockOrExpr::new_expr(get_substructure_equality_expr(a, b, c))
|
||||
})),
|
||||
}];
|
||||
|
||||
let trait_def = TraitDef {
|
||||
|
|
@ -113,3 +61,156 @@ pub(crate) fn expand_deriving_partial_eq(
|
|||
};
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
||||
/// Generates the equality expression for a struct or enum variant when deriving
|
||||
/// `PartialEq`.
|
||||
///
|
||||
/// This function generates an expression that checks if all fields of a struct
|
||||
/// or enum variant are equal.
|
||||
/// - Scalar fields are compared first for efficiency, followed by compound
|
||||
/// fields.
|
||||
/// - If there are no fields, returns `true` (fieldless types are always equal).
|
||||
///
|
||||
/// Whether a field is considered "scalar" is determined by comparing the symbol
|
||||
/// of its type to a set of known scalar type symbols (e.g., `i32`, `u8`, etc).
|
||||
/// This check is based on the type's symbol.
|
||||
///
|
||||
/// ### Example 1
|
||||
/// ```
|
||||
/// #[derive(PartialEq)]
|
||||
/// struct i32;
|
||||
///
|
||||
/// // Here, `field_2` is of type `i32`, but since it's a user-defined type (not
|
||||
/// // the primitive), it will not be treated as scalar. The function will still
|
||||
/// // check equality of `field_2` first because the symbol matches `i32`.
|
||||
/// #[derive(PartialEq)]
|
||||
/// struct Struct {
|
||||
/// field_1: &'static str,
|
||||
/// field_2: i32,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ### Example 2
|
||||
/// ```
|
||||
/// mod ty {
|
||||
/// pub type i32 = i32;
|
||||
/// }
|
||||
///
|
||||
/// // Here, `field_2` is of type `ty::i32`, which is a type alias for `i32`.
|
||||
/// // However, the function will not reorder the fields because the symbol for
|
||||
/// // `ty::i32` does not match the symbol for the primitive `i32`
|
||||
/// // ("ty::i32" != "i32").
|
||||
/// #[derive(PartialEq)]
|
||||
/// struct Struct {
|
||||
/// field_1: &'static str,
|
||||
/// field_2: ty::i32,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// For enums, the discriminant is compared first, then the rest of the fields.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If called on static or all-fieldless enums/structs, which should not occur
|
||||
/// during derive expansion.
|
||||
fn get_substructure_equality_expr(
|
||||
cx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
substructure: &Substructure<'_>,
|
||||
) -> P<Expr> {
|
||||
use SubstructureFields::*;
|
||||
|
||||
match substructure.fields {
|
||||
EnumMatching(.., fields) | Struct(.., fields) => {
|
||||
let combine = move |acc, field| {
|
||||
let rhs = get_field_equality_expr(cx, field);
|
||||
if let Some(lhs) = acc {
|
||||
// Combine the previous comparison with the current field
|
||||
// using logical AND.
|
||||
return Some(cx.expr_binary(field.span, BinOpKind::And, lhs, rhs));
|
||||
}
|
||||
// Start the chain with the first field's comparison.
|
||||
Some(rhs)
|
||||
};
|
||||
|
||||
// First compare scalar fields, then compound fields, combining all
|
||||
// with logical AND.
|
||||
return fields
|
||||
.iter()
|
||||
.filter(|field| !field.maybe_scalar)
|
||||
.fold(fields.iter().filter(|field| field.maybe_scalar).fold(None, combine), combine)
|
||||
// If there are no fields, treat as always equal.
|
||||
.unwrap_or_else(|| cx.expr_bool(span, true));
|
||||
}
|
||||
EnumDiscr(disc, match_expr) => {
|
||||
let lhs = get_field_equality_expr(cx, disc);
|
||||
let Some(match_expr) = match_expr else {
|
||||
return lhs;
|
||||
};
|
||||
// Compare the discriminant first (cheaper), then the rest of the
|
||||
// fields.
|
||||
return cx.expr_binary(disc.span, BinOpKind::And, lhs, match_expr.clone());
|
||||
}
|
||||
StaticEnum(..) => cx.dcx().span_bug(
|
||||
span,
|
||||
"unexpected static enum encountered during `derive(PartialEq)` expansion",
|
||||
),
|
||||
StaticStruct(..) => cx.dcx().span_bug(
|
||||
span,
|
||||
"unexpected static struct encountered during `derive(PartialEq)` expansion",
|
||||
),
|
||||
AllFieldlessEnum(..) => cx.dcx().span_bug(
|
||||
span,
|
||||
"unexpected all-fieldless enum encountered during `derive(PartialEq)` expansion",
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates an equality comparison expression for a single struct or enum
|
||||
/// field.
|
||||
///
|
||||
/// This function produces an AST expression that compares the `self` and
|
||||
/// `other` values for a field using `==`. It removes any leading references
|
||||
/// from both sides for readability. If the field is a block expression, it is
|
||||
/// wrapped in parentheses to ensure valid syntax.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if there are not exactly two arguments to compare (should be `self`
|
||||
/// and `other`).
|
||||
fn get_field_equality_expr(cx: &ExtCtxt<'_>, field: &FieldInfo) -> P<Expr> {
|
||||
let [rhs] = &field.other_selflike_exprs[..] else {
|
||||
cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
|
||||
};
|
||||
|
||||
cx.expr_binary(
|
||||
field.span,
|
||||
BinOpKind::Eq,
|
||||
wrap_block_expr(cx, peel_refs(&field.self_expr)),
|
||||
wrap_block_expr(cx, peel_refs(rhs)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Removes all leading immutable references from an expression.
|
||||
///
|
||||
/// This is used to strip away any number of leading `&` from an expression
|
||||
/// (e.g., `&&&T` becomes `T`). Only removes immutable references; mutable
|
||||
/// references are preserved.
|
||||
fn peel_refs(mut expr: &P<Expr>) -> P<Expr> {
|
||||
while let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = &expr.kind {
|
||||
expr = &inner;
|
||||
}
|
||||
expr.clone()
|
||||
}
|
||||
|
||||
/// Wraps a block expression in parentheses to ensure valid AST in macro
|
||||
/// expansion output.
|
||||
///
|
||||
/// If the given expression is a block, it is wrapped in parentheses; otherwise,
|
||||
/// it is returned unchanged.
|
||||
fn wrap_block_expr(cx: &ExtCtxt<'_>, expr: P<Expr>) -> P<Expr> {
|
||||
if matches!(&expr.kind, ExprKind::Block(..)) {
|
||||
return cx.expr_paren(expr.span, expr);
|
||||
}
|
||||
expr
|
||||
}
|
||||
|
|
|
|||
|
|
@ -284,6 +284,7 @@ pub(crate) struct FieldInfo {
|
|||
/// The expressions corresponding to references to this field in
|
||||
/// the other selflike arguments.
|
||||
pub other_selflike_exprs: Vec<P<Expr>>,
|
||||
pub maybe_scalar: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
@ -1220,7 +1221,8 @@ impl<'a> MethodDef<'a> {
|
|||
|
||||
let self_expr = discr_exprs.remove(0);
|
||||
let other_selflike_exprs = discr_exprs;
|
||||
let discr_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };
|
||||
let discr_field =
|
||||
FieldInfo { span, name: None, self_expr, other_selflike_exprs, maybe_scalar: true };
|
||||
|
||||
let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args)
|
||||
.map(|(&ident, selflike_arg)| {
|
||||
|
|
@ -1533,6 +1535,7 @@ impl<'a> TraitDef<'a> {
|
|||
name: struct_field.ident,
|
||||
self_expr,
|
||||
other_selflike_exprs,
|
||||
maybe_scalar: struct_field.ty.peel_refs().kind.maybe_scalar(),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
|
|
|||
|
|
@ -52,10 +52,6 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
|
|||
fn clear_dbg_loc(&mut self) {
|
||||
self.location = None;
|
||||
}
|
||||
|
||||
fn get_dbg_loc(&self) -> Option<Self::DILocation> {
|
||||
self.location
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the `debug_context` in an MIR Body.
|
||||
|
|
|
|||
|
|
@ -524,11 +524,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
|
|||
cond
|
||||
}
|
||||
|
||||
fn type_test(&mut self, _pointer: Self::Value, _typeid: Self::Value) -> Self::Value {
|
||||
// Unsupported.
|
||||
self.context.new_rvalue_from_int(self.int_type, 0)
|
||||
}
|
||||
|
||||
fn type_checked_load(
|
||||
&mut self,
|
||||
_llvtable: Self::Value,
|
||||
|
|
|
|||
|
|
@ -1815,8 +1815,11 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap();
|
||||
let dbg_loc = self.get_dbg_loc();
|
||||
|
||||
// Test whether the function pointer is associated with the type identifier.
|
||||
let cond = self.type_test(llfn, typeid_metadata);
|
||||
// Test whether the function pointer is associated with the type identifier using the
|
||||
// llvm.type.test intrinsic. The LowerTypeTests link-time optimization pass replaces
|
||||
// calls to this intrinsic with code to test type membership.
|
||||
let typeid = self.get_metadata_value(typeid_metadata);
|
||||
let cond = self.call_intrinsic("llvm.type.test", &[llfn, typeid]);
|
||||
let bb_pass = self.append_sibling_block("type_test.pass");
|
||||
let bb_fail = self.append_sibling_block("type_test.fail");
|
||||
self.cond_br(cond, bb_pass, bb_fail);
|
||||
|
|
|
|||
|
|
@ -147,6 +147,12 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ll> Builder<'_, 'll, '_> {
|
||||
pub(crate) fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
|
||||
unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
|
||||
// FIXME(eddyb) find a common convention for all of the debuginfo-related
|
||||
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
|
||||
|
|
@ -209,10 +215,6 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
|
||||
unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
|
||||
}
|
||||
|
||||
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
|
||||
gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -636,13 +636,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value {
|
||||
// Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time
|
||||
// optimization pass replaces calls to this intrinsic with code to test type membership.
|
||||
let typeid = self.get_metadata_value(typeid);
|
||||
self.call_intrinsic("llvm.type.test", &[pointer, typeid])
|
||||
}
|
||||
|
||||
fn type_checked_load(
|
||||
&mut self,
|
||||
llvtable: &'ll Value,
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ pub trait DebugInfoBuilderMethods: BackendTypes {
|
|||
);
|
||||
fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation);
|
||||
fn clear_dbg_loc(&mut self);
|
||||
fn get_dbg_loc(&self) -> Option<Self::DILocation>;
|
||||
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self);
|
||||
fn set_var_name(&mut self, value: Self::Value, name: &str);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes {
|
|||
fn abort(&mut self);
|
||||
fn assume(&mut self, val: Self::Value);
|
||||
fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value;
|
||||
/// Trait method used to test whether a given pointer is associated with a type identifier.
|
||||
fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value;
|
||||
/// Trait method used to load a function while testing if it is associated with a type
|
||||
/// identifier.
|
||||
fn type_checked_load(
|
||||
|
|
|
|||
|
|
@ -527,13 +527,15 @@ pub trait VisitorExt<'v>: Visitor<'v> {
|
|||
impl<'v, V: Visitor<'v>> VisitorExt<'v> for V {}
|
||||
|
||||
pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(param.hir_id));
|
||||
visitor.visit_pat(param.pat)
|
||||
let Param { hir_id, pat, ty_span: _, span: _ } = param;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
visitor.visit_pat(pat)
|
||||
}
|
||||
|
||||
pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result {
|
||||
let Item { owner_id: _, kind, span: _, vis_span: _ } = item;
|
||||
try_visit!(visitor.visit_id(item.hir_id()));
|
||||
match item.kind {
|
||||
match *kind {
|
||||
ItemKind::ExternCrate(orig_name, ident) => {
|
||||
visit_opt!(visitor, visit_name, orig_name);
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
|
|
@ -631,8 +633,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
|
|||
}
|
||||
|
||||
pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &Body<'v>) -> V::Result {
|
||||
walk_list!(visitor, visit_param, body.params);
|
||||
visitor.visit_expr(body.value)
|
||||
let Body { params, value } = body;
|
||||
walk_list!(visitor, visit_param, *params);
|
||||
visitor.visit_expr(*value)
|
||||
}
|
||||
|
||||
pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> V::Result {
|
||||
|
|
@ -640,7 +643,8 @@ pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> V::Resul
|
|||
}
|
||||
|
||||
pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>) -> V::Result {
|
||||
walk_list!(visitor, visit_nested_item, module.item_ids.iter().copied());
|
||||
let Mod { spans: _, item_ids } = module;
|
||||
walk_list!(visitor, visit_nested_item, item_ids.iter().copied());
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
|
|
@ -648,10 +652,11 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
foreign_item: &'v ForeignItem<'v>,
|
||||
) -> V::Result {
|
||||
let ForeignItem { ident, kind, owner_id: _, span: _, vis_span: _ } = foreign_item;
|
||||
try_visit!(visitor.visit_id(foreign_item.hir_id()));
|
||||
try_visit!(visitor.visit_ident(foreign_item.ident));
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
|
||||
match foreign_item.kind {
|
||||
match *kind {
|
||||
ForeignItemKind::Fn(ref sig, param_idents, ref generics) => {
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
try_visit!(visitor.visit_fn_decl(sig.decl));
|
||||
|
|
@ -670,24 +675,27 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(
|
|||
pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v LetStmt<'v>) -> V::Result {
|
||||
// Intentionally visiting the expr first - the initialization expr
|
||||
// dominates the local's definition.
|
||||
visit_opt!(visitor, visit_expr, local.init);
|
||||
try_visit!(visitor.visit_id(local.hir_id));
|
||||
try_visit!(visitor.visit_pat(local.pat));
|
||||
visit_opt!(visitor, visit_block, local.els);
|
||||
visit_opt!(visitor, visit_ty_unambig, local.ty);
|
||||
let LetStmt { super_: _, pat, ty, init, els, hir_id, span: _, source: _ } = local;
|
||||
visit_opt!(visitor, visit_expr, *init);
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
try_visit!(visitor.visit_pat(*pat));
|
||||
visit_opt!(visitor, visit_block, *els);
|
||||
visit_opt!(visitor, visit_ty_unambig, *ty);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(block.hir_id));
|
||||
walk_list!(visitor, visit_stmt, block.stmts);
|
||||
visit_opt!(visitor, visit_expr, block.expr);
|
||||
let Block { stmts, expr, hir_id, rules: _, span: _, targeted_by_break: _ } = block;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
walk_list!(visitor, visit_stmt, *stmts);
|
||||
visit_opt!(visitor, visit_expr, *expr);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(statement.hir_id));
|
||||
match statement.kind {
|
||||
let Stmt { kind, hir_id, span: _ } = statement;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
match *kind {
|
||||
StmtKind::Let(ref local) => visitor.visit_local(local),
|
||||
StmtKind::Item(item) => visitor.visit_nested_item(item),
|
||||
StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
|
||||
|
|
@ -697,15 +705,17 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) -
|
|||
}
|
||||
|
||||
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(arm.hir_id));
|
||||
try_visit!(visitor.visit_pat(arm.pat));
|
||||
visit_opt!(visitor, visit_expr, arm.guard);
|
||||
visitor.visit_expr(arm.body)
|
||||
let Arm { hir_id, span: _, pat, guard, body } = arm;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
try_visit!(visitor.visit_pat(*pat));
|
||||
visit_opt!(visitor, visit_expr, *guard);
|
||||
visitor.visit_expr(*body)
|
||||
}
|
||||
|
||||
pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(pattern.hir_id));
|
||||
match pattern.kind {
|
||||
let TyPat { kind, hir_id, span: _ } = pattern;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
match *kind {
|
||||
TyPatKind::Range(lower_bound, upper_bound) => {
|
||||
try_visit!(visitor.visit_const_arg_unambig(lower_bound));
|
||||
try_visit!(visitor.visit_const_arg_unambig(upper_bound));
|
||||
|
|
@ -717,14 +727,15 @@ pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>)
|
|||
}
|
||||
|
||||
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(pattern.hir_id));
|
||||
match pattern.kind {
|
||||
let Pat { hir_id, kind, span, default_binding_modes: _ } = pattern;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
match *kind {
|
||||
PatKind::TupleStruct(ref qpath, children, _) => {
|
||||
try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
|
||||
try_visit!(visitor.visit_qpath(qpath, *hir_id, *span));
|
||||
walk_list!(visitor, visit_pat, children);
|
||||
}
|
||||
PatKind::Struct(ref qpath, fields, _) => {
|
||||
try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
|
||||
try_visit!(visitor.visit_qpath(qpath, *hir_id, *span));
|
||||
walk_list!(visitor, visit_pat_field, fields);
|
||||
}
|
||||
PatKind::Or(pats) => walk_list!(visitor, visit_pat, pats),
|
||||
|
|
@ -760,36 +771,41 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
|
|||
}
|
||||
|
||||
pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(field.hir_id));
|
||||
try_visit!(visitor.visit_ident(field.ident));
|
||||
visitor.visit_pat(field.pat)
|
||||
let PatField { hir_id, ident, pat, is_shorthand: _, span: _ } = field;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
visitor.visit_pat(*pat)
|
||||
}
|
||||
|
||||
pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(expr.hir_id));
|
||||
match &expr.kind {
|
||||
PatExprKind::Lit { lit, negated } => visitor.visit_lit(expr.hir_id, lit, *negated),
|
||||
let PatExpr { hir_id, span, kind } = expr;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
match kind {
|
||||
PatExprKind::Lit { lit, negated } => visitor.visit_lit(*hir_id, lit, *negated),
|
||||
PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c),
|
||||
PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, expr.hir_id, expr.span),
|
||||
PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, *span),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) -> V::Result {
|
||||
try_visit!(visitor.visit_id(constant.hir_id));
|
||||
visitor.visit_nested_body(constant.body)
|
||||
let AnonConst { hir_id, def_id: _, body, span: _ } = constant;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
visitor.visit_nested_body(*body)
|
||||
}
|
||||
|
||||
pub fn walk_inline_const<'v, V: Visitor<'v>>(
|
||||
visitor: &mut V,
|
||||
constant: &'v ConstBlock,
|
||||
) -> V::Result {
|
||||
try_visit!(visitor.visit_id(constant.hir_id));
|
||||
visitor.visit_nested_body(constant.body)
|
||||
let ConstBlock { hir_id, def_id: _, body } = constant;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
visitor.visit_nested_body(*body)
|
||||
}
|
||||
|
||||
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(expression.hir_id));
|
||||
match expression.kind {
|
||||
let Expr { hir_id, kind, span } = expression;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
match *kind {
|
||||
ExprKind::Array(subexpressions) => {
|
||||
walk_list!(visitor, visit_expr, subexpressions);
|
||||
}
|
||||
|
|
@ -801,7 +817,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
|||
try_visit!(visitor.visit_const_arg_unambig(count));
|
||||
}
|
||||
ExprKind::Struct(ref qpath, fields, ref optional_base) => {
|
||||
try_visit!(visitor.visit_qpath(qpath, expression.hir_id, expression.span));
|
||||
try_visit!(visitor.visit_qpath(qpath, *hir_id, *span));
|
||||
walk_list!(visitor, visit_expr_field, fields);
|
||||
match optional_base {
|
||||
StructTailExpr::Base(base) => try_visit!(visitor.visit_expr(base)),
|
||||
|
|
@ -869,7 +885,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
|||
constness: _,
|
||||
}) => {
|
||||
walk_list!(visitor, visit_generic_param, bound_generic_params);
|
||||
try_visit!(visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, def_id));
|
||||
try_visit!(visitor.visit_fn(FnKind::Closure, fn_decl, body, *span, def_id));
|
||||
}
|
||||
ExprKind::Block(ref block, ref opt_label) => {
|
||||
visit_opt!(visitor, visit_label, opt_label);
|
||||
|
|
@ -892,7 +908,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
|||
try_visit!(visitor.visit_expr(index_expression));
|
||||
}
|
||||
ExprKind::Path(ref qpath) => {
|
||||
try_visit!(visitor.visit_qpath(qpath, expression.hir_id, expression.span));
|
||||
try_visit!(visitor.visit_qpath(qpath, *hir_id, *span));
|
||||
}
|
||||
ExprKind::Break(ref destination, ref opt_expr) => {
|
||||
visit_opt!(visitor, visit_label, &destination.label);
|
||||
|
|
@ -906,7 +922,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
|||
}
|
||||
ExprKind::Become(ref expr) => try_visit!(visitor.visit_expr(expr)),
|
||||
ExprKind::InlineAsm(ref asm) => {
|
||||
try_visit!(visitor.visit_inline_asm(asm, expression.hir_id));
|
||||
try_visit!(visitor.visit_inline_asm(asm, *hir_id));
|
||||
}
|
||||
ExprKind::OffsetOf(ref container, ref fields) => {
|
||||
try_visit!(visitor.visit_ty_unambig(container));
|
||||
|
|
@ -919,16 +935,17 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
|||
try_visit!(visitor.visit_expr(expr));
|
||||
visit_opt!(visitor, visit_ty_unambig, ty);
|
||||
}
|
||||
ExprKind::Lit(lit) => try_visit!(visitor.visit_lit(expression.hir_id, lit, false)),
|
||||
ExprKind::Lit(lit) => try_visit!(visitor.visit_lit(*hir_id, lit, false)),
|
||||
ExprKind::Err(_) => {}
|
||||
}
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(field.hir_id));
|
||||
try_visit!(visitor.visit_ident(field.ident));
|
||||
visitor.visit_expr(field.expr)
|
||||
let ExprField { hir_id, ident, expr, span: _, is_shorthand: _ } = field;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
visitor.visit_expr(*expr)
|
||||
}
|
||||
/// We track whether an infer var is from a [`Ty`], [`ConstArg`], or [`GenericArg`] so that
|
||||
/// HIR visitors overriding [`Visitor::visit_infer`] can determine what kind of infer is being visited
|
||||
|
|
@ -946,7 +963,10 @@ pub fn walk_generic_arg<'v, V: Visitor<'v>>(
|
|||
GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
|
||||
GenericArg::Type(ty) => visitor.visit_ty(ty),
|
||||
GenericArg::Const(ct) => visitor.visit_const_arg(ct),
|
||||
GenericArg::Infer(inf) => visitor.visit_infer(inf.hir_id, inf.span, InferKind::Ambig(inf)),
|
||||
GenericArg::Infer(inf) => {
|
||||
let InferArg { hir_id, span } = inf;
|
||||
visitor.visit_infer(*hir_id, *span, InferKind::Ambig(inf))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -954,16 +974,18 @@ pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) ->
|
|||
match typ.try_as_ambig_ty() {
|
||||
Some(ambig_ty) => visitor.visit_ty(ambig_ty),
|
||||
None => {
|
||||
try_visit!(visitor.visit_id(typ.hir_id));
|
||||
visitor.visit_infer(typ.hir_id, typ.span, InferKind::Ty(typ))
|
||||
let Ty { hir_id, span, kind: _ } = typ;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
visitor.visit_infer(*hir_id, *span, InferKind::Ty(typ))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(typ.hir_id));
|
||||
let Ty { hir_id, span: _, kind } = typ;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
|
||||
match typ.kind {
|
||||
match *kind {
|
||||
TyKind::Slice(ref ty) => try_visit!(visitor.visit_ty_unambig(ty)),
|
||||
TyKind::Ptr(ref mutable_type) => try_visit!(visitor.visit_ty_unambig(mutable_type.ty)),
|
||||
TyKind::Ref(ref lifetime, ref mutable_type) => {
|
||||
|
|
@ -1018,8 +1040,9 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
|
|||
match const_arg.try_as_ambig_ct() {
|
||||
Some(ambig_ct) => visitor.visit_const_arg(ambig_ct),
|
||||
None => {
|
||||
try_visit!(visitor.visit_id(const_arg.hir_id));
|
||||
visitor.visit_infer(const_arg.hir_id, const_arg.span(), InferKind::Const(const_arg))
|
||||
let ConstArg { hir_id, kind: _ } = const_arg;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
visitor.visit_infer(*hir_id, const_arg.span(), InferKind::Const(const_arg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1028,9 +1051,10 @@ pub fn walk_ambig_const_arg<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
const_arg: &'v ConstArg<'v, AmbigArg>,
|
||||
) -> V::Result {
|
||||
try_visit!(visitor.visit_id(const_arg.hir_id));
|
||||
match &const_arg.kind {
|
||||
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, const_arg.hir_id, qpath.span()),
|
||||
let ConstArg { hir_id, kind } = const_arg;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
match kind {
|
||||
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()),
|
||||
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
|
||||
}
|
||||
}
|
||||
|
|
@ -1039,12 +1063,22 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
param: &'v GenericParam<'v>,
|
||||
) -> V::Result {
|
||||
try_visit!(visitor.visit_id(param.hir_id));
|
||||
match param.name {
|
||||
let GenericParam {
|
||||
hir_id,
|
||||
def_id: _,
|
||||
name,
|
||||
span: _,
|
||||
pure_wrt_drop: _,
|
||||
kind,
|
||||
colon_span: _,
|
||||
source: _,
|
||||
} = param;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
match *name {
|
||||
ParamName::Plain(ident) | ParamName::Error(ident) => try_visit!(visitor.visit_ident(ident)),
|
||||
ParamName::Fresh => {}
|
||||
}
|
||||
match param.kind {
|
||||
match *kind {
|
||||
GenericParamKind::Lifetime { .. } => {}
|
||||
GenericParamKind::Type { ref default, .. } => {
|
||||
visit_opt!(visitor, visit_ty_unambig, default)
|
||||
|
|
@ -1052,7 +1086,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
|
|||
GenericParamKind::Const { ref ty, ref default, synthetic: _ } => {
|
||||
try_visit!(visitor.visit_ty_unambig(ty));
|
||||
if let Some(default) = default {
|
||||
try_visit!(visitor.visit_const_param_default(param.hir_id, default));
|
||||
try_visit!(visitor.visit_const_param_default(*hir_id, default));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1067,8 +1101,15 @@ pub fn walk_const_param_default<'v, V: Visitor<'v>>(
|
|||
}
|
||||
|
||||
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) -> V::Result {
|
||||
walk_list!(visitor, visit_generic_param, generics.params);
|
||||
walk_list!(visitor, visit_where_predicate, generics.predicates);
|
||||
let &Generics {
|
||||
params,
|
||||
predicates,
|
||||
has_where_clause_predicates: _,
|
||||
where_clause_span: _,
|
||||
span: _,
|
||||
} = generics;
|
||||
walk_list!(visitor, visit_generic_param, params);
|
||||
walk_list!(visitor, visit_where_predicate, predicates);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
|
|
@ -1109,8 +1150,10 @@ pub fn walk_fn_decl<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
function_declaration: &'v FnDecl<'v>,
|
||||
) -> V::Result {
|
||||
walk_list!(visitor, visit_ty_unambig, function_declaration.inputs);
|
||||
visitor.visit_fn_ret_ty(&function_declaration.output)
|
||||
let FnDecl { inputs, output, c_variadic: _, implicit_self: _, lifetime_elision_allowed: _ } =
|
||||
function_declaration;
|
||||
walk_list!(visitor, visit_ty_unambig, *inputs);
|
||||
visitor.visit_fn_ret_ty(output)
|
||||
}
|
||||
|
||||
pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) -> V::Result {
|
||||
|
|
@ -1264,8 +1307,9 @@ pub fn walk_trait_ref<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
trait_ref: &'v TraitRef<'v>,
|
||||
) -> V::Result {
|
||||
try_visit!(visitor.visit_id(trait_ref.hir_ref_id));
|
||||
visitor.visit_path(trait_ref.path, trait_ref.hir_ref_id)
|
||||
let TraitRef { hir_ref_id, path } = trait_ref;
|
||||
try_visit!(visitor.visit_id(*hir_ref_id));
|
||||
visitor.visit_path(*path, *hir_ref_id)
|
||||
}
|
||||
|
||||
pub fn walk_param_bound<'v, V: Visitor<'v>>(
|
||||
|
|
@ -1288,7 +1332,10 @@ pub fn walk_precise_capturing_arg<'v, V: Visitor<'v>>(
|
|||
) -> V::Result {
|
||||
match *arg {
|
||||
PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt),
|
||||
PreciseCapturingArg::Param(param) => visitor.visit_id(param.hir_id),
|
||||
PreciseCapturingArg::Param(param) => {
|
||||
let PreciseCapturingNonLifetimeArg { hir_id, ident: _, res: _ } = param;
|
||||
visitor.visit_id(hir_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1296,8 +1343,9 @@ pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
trait_ref: &'v PolyTraitRef<'v>,
|
||||
) -> V::Result {
|
||||
walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params);
|
||||
visitor.visit_trait_ref(&trait_ref.trait_ref)
|
||||
let PolyTraitRef { bound_generic_params, modifiers: _, trait_ref, span: _ } = trait_ref;
|
||||
walk_list!(visitor, visit_generic_param, *bound_generic_params);
|
||||
visitor.visit_trait_ref(trait_ref)
|
||||
}
|
||||
|
||||
pub fn walk_opaque_ty<'v, V: Visitor<'v>>(visitor: &mut V, opaque: &'v OpaqueTy<'v>) -> V::Result {
|
||||
|
|
@ -1330,29 +1378,34 @@ pub fn walk_enum_def<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
enum_definition: &'v EnumDef<'v>,
|
||||
) -> V::Result {
|
||||
walk_list!(visitor, visit_variant, enum_definition.variants);
|
||||
let EnumDef { variants } = enum_definition;
|
||||
walk_list!(visitor, visit_variant, *variants);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_ident(variant.ident));
|
||||
try_visit!(visitor.visit_id(variant.hir_id));
|
||||
try_visit!(visitor.visit_variant_data(&variant.data));
|
||||
visit_opt!(visitor, visit_anon_const, &variant.disr_expr);
|
||||
let Variant { ident, hir_id, def_id: _, data, disr_expr, span: _ } = variant;
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
try_visit!(visitor.visit_variant_data(data));
|
||||
visit_opt!(visitor, visit_anon_const, disr_expr);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) -> V::Result {
|
||||
visitor.visit_ident(label.ident)
|
||||
let Label { ident } = label;
|
||||
visitor.visit_ident(*ident)
|
||||
}
|
||||
|
||||
pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) -> V::Result {
|
||||
visitor.visit_id(inf.hir_id)
|
||||
let InferArg { hir_id, span: _ } = inf;
|
||||
visitor.visit_id(*hir_id)
|
||||
}
|
||||
|
||||
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) -> V::Result {
|
||||
try_visit!(visitor.visit_id(lifetime.hir_id));
|
||||
visitor.visit_ident(lifetime.ident)
|
||||
let Lifetime { hir_id, ident, kind: _, source: _, syntax: _ } = lifetime;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
visitor.visit_ident(*ident)
|
||||
}
|
||||
|
||||
pub fn walk_qpath<'v, V: Visitor<'v>>(
|
||||
|
|
@ -1374,7 +1427,8 @@ pub fn walk_qpath<'v, V: Visitor<'v>>(
|
|||
}
|
||||
|
||||
pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &Path<'v>) -> V::Result {
|
||||
walk_list!(visitor, visit_path_segment, path.segments);
|
||||
let Path { segments, span: _, res: _ } = path;
|
||||
walk_list!(visitor, visit_path_segment, *segments);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
|
|
@ -1382,9 +1436,10 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
segment: &'v PathSegment<'v>,
|
||||
) -> V::Result {
|
||||
try_visit!(visitor.visit_ident(segment.ident));
|
||||
try_visit!(visitor.visit_id(segment.hir_id));
|
||||
visit_opt!(visitor, visit_generic_args, segment.args);
|
||||
let PathSegment { ident, hir_id, res: _, args, infer_args: _ } = segment;
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
visit_opt!(visitor, visit_generic_args, *args);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
|
|
@ -1392,8 +1447,9 @@ pub fn walk_generic_args<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
generic_args: &'v GenericArgs<'v>,
|
||||
) -> V::Result {
|
||||
walk_list!(visitor, visit_generic_arg, generic_args.args);
|
||||
walk_list!(visitor, visit_assoc_item_constraint, generic_args.constraints);
|
||||
let GenericArgs { args, constraints, parenthesized: _, span_ext: _ } = generic_args;
|
||||
walk_list!(visitor, visit_generic_arg, *args);
|
||||
walk_list!(visitor, visit_assoc_item_constraint, *constraints);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
|
|
@ -1401,9 +1457,10 @@ pub fn walk_assoc_item_constraint<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
constraint: &'v AssocItemConstraint<'v>,
|
||||
) -> V::Result {
|
||||
try_visit!(visitor.visit_id(constraint.hir_id));
|
||||
try_visit!(visitor.visit_ident(constraint.ident));
|
||||
try_visit!(visitor.visit_generic_args(constraint.gen_args));
|
||||
let AssocItemConstraint { hir_id, ident, gen_args, kind: _, span: _ } = constraint;
|
||||
try_visit!(visitor.visit_id(*hir_id));
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
try_visit!(visitor.visit_generic_args(*gen_args));
|
||||
match constraint.kind {
|
||||
AssocItemConstraintKind::Equality { ref term } => match term {
|
||||
Term::Ty(ty) => try_visit!(visitor.visit_ty_unambig(ty)),
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||
expr: &'thir Expr<'tcx>,
|
||||
) {
|
||||
use ExprKind::*;
|
||||
match expr.kind {
|
||||
let Expr { kind, ty: _, temp_lifetime: _, span: _ } = expr;
|
||||
match *kind {
|
||||
Scope { value, region_scope: _, lint_level: _ } => {
|
||||
visitor.visit_expr(&visitor.thir()[value])
|
||||
}
|
||||
|
|
@ -191,7 +192,8 @@ pub fn walk_stmt<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||
visitor: &mut V,
|
||||
stmt: &'thir Stmt<'tcx>,
|
||||
) {
|
||||
match &stmt.kind {
|
||||
let Stmt { kind } = stmt;
|
||||
match kind {
|
||||
StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
|
||||
StmtKind::Let {
|
||||
initializer,
|
||||
|
|
@ -217,11 +219,13 @@ pub fn walk_block<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||
visitor: &mut V,
|
||||
block: &'thir Block,
|
||||
) {
|
||||
for &stmt in &*block.stmts {
|
||||
let Block { stmts, expr, targeted_by_break: _, region_scope: _, span: _, safety_mode: _ } =
|
||||
block;
|
||||
for &stmt in &*stmts {
|
||||
visitor.visit_stmt(&visitor.thir()[stmt]);
|
||||
}
|
||||
if let Some(expr) = block.expr {
|
||||
visitor.visit_expr(&visitor.thir()[expr]);
|
||||
if let Some(expr) = expr {
|
||||
visitor.visit_expr(&visitor.thir()[*expr]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -229,11 +233,12 @@ pub fn walk_arm<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||
visitor: &mut V,
|
||||
arm: &'thir Arm<'tcx>,
|
||||
) {
|
||||
if let Some(expr) = arm.guard {
|
||||
visitor.visit_expr(&visitor.thir()[expr])
|
||||
let Arm { guard, pattern, body, lint_level: _, span: _, scope: _ } = arm;
|
||||
if let Some(expr) = guard {
|
||||
visitor.visit_expr(&visitor.thir()[*expr])
|
||||
}
|
||||
visitor.visit_pat(&arm.pattern);
|
||||
visitor.visit_expr(&visitor.thir()[arm.body]);
|
||||
visitor.visit_pat(pattern);
|
||||
visitor.visit_expr(&visitor.thir()[*body]);
|
||||
}
|
||||
|
||||
pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
||||
|
|
@ -249,7 +254,8 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
|
|||
pat: &'a Pat<'tcx>,
|
||||
mut callback: impl FnMut(&'a Pat<'tcx>),
|
||||
) {
|
||||
match &pat.kind {
|
||||
let Pat { kind, ty: _, span: _ } = pat;
|
||||
match kind {
|
||||
PatKind::Missing
|
||||
| PatKind::Wild
|
||||
| PatKind::Binding { subpattern: None, .. }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
# These defaults are meant for contributors to the standard library and documentation.
|
||||
[build]
|
||||
build-stage = 1
|
||||
test-stage = 1
|
||||
bench-stage = 1
|
||||
build-stage = 1
|
||||
check-stage = 1
|
||||
test-stage = 1
|
||||
|
||||
[rust]
|
||||
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ pub struct Std {
|
|||
}
|
||||
|
||||
impl Std {
|
||||
const CRATE_OR_DEPS: &[&str] = &["sysroot", "coretests", "alloctests"];
|
||||
|
||||
pub fn new(target: TargetSelection) -> Self {
|
||||
Self { target, crates: vec![], override_build_kind: None }
|
||||
}
|
||||
|
|
@ -46,12 +48,19 @@ impl Step for Std {
|
|||
const DEFAULT: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
let stage = run.builder.top_stage;
|
||||
run.crate_or_deps("sysroot")
|
||||
.crate_or_deps("coretests")
|
||||
.crate_or_deps("alloctests")
|
||||
.path("library")
|
||||
.default_condition(stage != 0)
|
||||
let builder = run.builder;
|
||||
let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 {
|
||||
builder.top_stage
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
let mut run = run;
|
||||
for c in Std::CRATE_OR_DEPS {
|
||||
run = run.crate_or_deps(c);
|
||||
}
|
||||
|
||||
run.path("library").default_condition(stage != 0)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
|
|
@ -62,10 +71,29 @@ impl Step for Std {
|
|||
fn run(self, builder: &Builder<'_>) {
|
||||
builder.require_submodule("library/stdarch", None);
|
||||
|
||||
let target = self.target;
|
||||
let compiler = builder.compiler(builder.top_stage, builder.config.build);
|
||||
let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 {
|
||||
builder.top_stage
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
let target = self.target;
|
||||
let compiler = builder.compiler(stage, builder.config.build);
|
||||
|
||||
if stage == 0 {
|
||||
let mut is_explicitly_called =
|
||||
builder.paths.iter().any(|p| p.starts_with("library") || p.starts_with("std"));
|
||||
|
||||
if !is_explicitly_called {
|
||||
for c in Std::CRATE_OR_DEPS {
|
||||
is_explicitly_called = builder.paths.iter().any(|p| p.starts_with(c));
|
||||
}
|
||||
}
|
||||
|
||||
if is_explicitly_called {
|
||||
eprintln!("WARNING: stage 0 std is precompiled and does nothing during `x check`.");
|
||||
}
|
||||
|
||||
if builder.top_stage == 0 {
|
||||
// Reuse the stage0 libstd
|
||||
builder.ensure(compile::Std::new(compiler, target));
|
||||
return;
|
||||
|
|
@ -93,6 +121,7 @@ impl Step for Std {
|
|||
let _guard = builder.msg_check(
|
||||
format_args!("library artifacts{}", crate_description(&self.crates)),
|
||||
target,
|
||||
Some(stage),
|
||||
);
|
||||
|
||||
let stamp = build_stamp::libstd_stamp(builder, compiler, target).with_prefix("check");
|
||||
|
|
@ -145,7 +174,7 @@ impl Step for Std {
|
|||
}
|
||||
|
||||
let stamp = build_stamp::libstd_stamp(builder, compiler, target).with_prefix("check-test");
|
||||
let _guard = builder.msg_check("library test/bench/example targets", target);
|
||||
let _guard = builder.msg_check("library test/bench/example targets", target, Some(stage));
|
||||
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -246,6 +275,7 @@ impl Step for Rustc {
|
|||
let _guard = builder.msg_check(
|
||||
format_args!("compiler artifacts{}", crate_description(&self.crates)),
|
||||
target,
|
||||
None,
|
||||
);
|
||||
|
||||
let stamp = build_stamp::librustc_stamp(builder, compiler, target).with_prefix("check");
|
||||
|
|
@ -306,7 +336,7 @@ impl Step for CodegenBackend {
|
|||
.arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
|
||||
rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
|
||||
|
||||
let _guard = builder.msg_check(backend, target);
|
||||
let _guard = builder.msg_check(backend, target, None);
|
||||
|
||||
let stamp = build_stamp::codegen_backend_stamp(builder, compiler, target, backend)
|
||||
.with_prefix("check");
|
||||
|
|
@ -373,7 +403,7 @@ impl Step for RustAnalyzer {
|
|||
let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target))
|
||||
.with_prefix("rust-analyzer-check");
|
||||
|
||||
let _guard = builder.msg_check("rust-analyzer artifacts", target);
|
||||
let _guard = builder.msg_check("rust-analyzer artifacts", target, None);
|
||||
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -436,7 +466,7 @@ impl Step for Compiletest {
|
|||
let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, self.target))
|
||||
.with_prefix("compiletest-check");
|
||||
|
||||
let _guard = builder.msg_check("compiletest artifacts", self.target);
|
||||
let _guard = builder.msg_check("compiletest artifacts", self.target, None);
|
||||
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -514,7 +544,7 @@ fn run_tool_check_step(
|
|||
let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target))
|
||||
.with_prefix(&format!("{}-check", step_type_name.to_lowercase()));
|
||||
|
||||
let _guard = builder.msg_check(format!("{display_name} artifacts"), target);
|
||||
let _guard = builder.msg_check(format!("{display_name} artifacts"), target, None);
|
||||
run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2531,9 +2531,8 @@ impl Config {
|
|||
|| bench_stage.is_some();
|
||||
// See https://github.com/rust-lang/compiler-team/issues/326
|
||||
config.stage = match config.cmd {
|
||||
Subcommand::Check { .. } | Subcommand::Clippy { .. } | Subcommand::Fix => {
|
||||
flags.stage.or(check_stage).unwrap_or(1)
|
||||
}
|
||||
Subcommand::Check { .. } => flags.stage.or(check_stage).unwrap_or(0),
|
||||
Subcommand::Clippy { .. } | Subcommand::Fix => flags.stage.or(check_stage).unwrap_or(1),
|
||||
// `download-rustc` only has a speed-up for stage2 builds. Default to stage2 unless explicitly overridden.
|
||||
Subcommand::Doc { .. } => {
|
||||
flags.stage.or(doc_stage).unwrap_or(if download_rustc { 2 } else { 1 })
|
||||
|
|
|
|||
|
|
@ -1104,8 +1104,15 @@ Executed at: {executed_at}"#,
|
|||
&self,
|
||||
what: impl Display,
|
||||
target: impl Into<Option<TargetSelection>>,
|
||||
custom_stage: Option<u32>,
|
||||
) -> Option<gha::Group> {
|
||||
self.msg(Kind::Check, self.config.stage, what, self.config.build, target)
|
||||
self.msg(
|
||||
Kind::Check,
|
||||
custom_stage.unwrap_or(self.config.stage),
|
||||
what,
|
||||
self.config.build,
|
||||
target,
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use = "Groups should not be dropped until the Step finishes running"]
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ COPY scripts/sccache.sh /scripts/
|
|||
RUN sh /scripts/sccache.sh
|
||||
|
||||
ENV SCRIPT \
|
||||
python3 ../x.py check && \
|
||||
python3 ../x.py clippy ci && \
|
||||
python3 ../x.py test --stage 1 core alloc std test proc_macro && \
|
||||
# Build both public and internal documentation.
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@ runners:
|
|||
os: windows-2022
|
||||
<<: *base-job
|
||||
|
||||
# FIXME(#141022): Windows Server 2025 20250504.1.0 currently experiences
|
||||
# insufficient disk space.
|
||||
- &job-windows-25
|
||||
os: windows-2025
|
||||
<<: *base-job
|
||||
|
|
@ -497,17 +495,13 @@ auto:
|
|||
env:
|
||||
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler
|
||||
SCRIPT: make ci-msvc-py
|
||||
# FIXME(#141022): Windows Server 2025 20250504.1.0 currently experiences
|
||||
# insufficient disk space.
|
||||
<<: *job-windows
|
||||
<<: *job-windows-25
|
||||
|
||||
- name: x86_64-msvc-2
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler
|
||||
SCRIPT: make ci-msvc-ps1
|
||||
# FIXME(#141022): Windows Server 2025 20250504.1.0 currently experiences
|
||||
# insufficient disk space.
|
||||
<<: *job-windows
|
||||
<<: *job-windows-25
|
||||
|
||||
# i686-msvc is split into two jobs to run tests in parallel.
|
||||
- name: i686-msvc-1
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 230c68bc1e08f5f3228384a28cc228c81dfbd10d
|
||||
Subproject commit 634724ea85ebb08a542970bf8871ac8b0f77fd15
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 0b8219ac23a3e09464e4e0166c768cf1c4bba0d5
|
||||
Subproject commit 10fa1e084365f23f24ad0000df541923385b73b6
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit c76a20f0d987145dcedf05c5c073ce8d91f2e82a
|
||||
Subproject commit 8b61acfaea822e9ac926190bc8f15791c33336e8
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 118fd1f1f0854f50e3ae1fe4b64862aad23009ca
|
||||
Subproject commit 8e0f593a30f3b56ddb0908fb7ab9249974e08738
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit c9d151f9147c4808c77f0375ba3fa5d54443cb9e
|
||||
Subproject commit 21f4e32b8b40d36453fae16ec07ad4b857c445b6
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
//! Tests that a `Vec<isize>` can call a method defined in a trait (`Foo`)
|
||||
//! implemented for `&[isize]` with a by-value receiver (`self`), relying on auto-dereferencing
|
||||
//! from `Vec` to `&[isize]` during method resolution.
|
||||
|
||||
//@ run-pass
|
||||
|
||||
trait Foo {
|
||||
fn foo(self);
|
||||
}
|
||||
|
||||
impl<'a> Foo for &'a [isize] {
|
||||
fn foo(self) {}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let items = vec![ 3, 5, 1, 2, 4 ];
|
||||
items.foo();
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
enum Color { Rgb(isize, isize, isize), Rgba(isize, isize, isize, isize), }
|
||||
|
||||
fn main() {
|
||||
let red: Color = Color::Rgb(255, 0, 0);
|
||||
match red {
|
||||
Color::Rgb(r, g, b) => { println!("rgb"); }
|
||||
Color::Hsl(h, s, l) => { println!("hsl"); }
|
||||
//~^ ERROR no variant
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
//@ run-pass
|
||||
|
||||
trait Foo {
|
||||
fn foo(self);
|
||||
}
|
||||
|
||||
impl<'a> Foo for &'a [isize] {
|
||||
fn foo(self) {}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let items = vec![ 3, 5, 1, 2, 4 ];
|
||||
items.foo();
|
||||
}
|
||||
|
|
@ -45,6 +45,22 @@ struct Big {
|
|||
b1: u32, b2: u32, b3: u32, b4: u32, b5: u32, b6: u32, b7: u32, b8: u32,
|
||||
}
|
||||
|
||||
// It is more efficient to compare scalar types before non-scalar types.
|
||||
#[derive(PartialEq, PartialOrd)]
|
||||
struct Reorder {
|
||||
b1: Option<f32>,
|
||||
b2: u16,
|
||||
b3: &'static str,
|
||||
b4: i8,
|
||||
b5: u128,
|
||||
_b: *mut &'static dyn FnMut() -> (),
|
||||
b6: f64,
|
||||
b7: &'static mut (),
|
||||
b8: char,
|
||||
b9: &'static [i64],
|
||||
b10: &'static *const bool,
|
||||
}
|
||||
|
||||
// A struct that doesn't impl `Copy`, which means it gets the non-simple
|
||||
// `clone` implemention that clones the fields individually.
|
||||
#[derive(Clone)]
|
||||
|
|
@ -130,6 +146,20 @@ enum Mixed {
|
|||
S { d1: Option<u32>, d2: Option<i32> },
|
||||
}
|
||||
|
||||
// When comparing enum variant it is more efficient to compare scalar types before non-scalar types.
|
||||
#[derive(PartialEq, PartialOrd)]
|
||||
enum ReorderEnum {
|
||||
A(i32),
|
||||
B,
|
||||
C(i8),
|
||||
D,
|
||||
E,
|
||||
F,
|
||||
G(&'static mut str, *const u8, *const dyn Fn() -> ()),
|
||||
H,
|
||||
I,
|
||||
}
|
||||
|
||||
// An enum with no fieldless variants. Note that `Default` cannot be derived
|
||||
// for this enum.
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
|
|
|||
|
|
@ -419,6 +419,100 @@ impl ::core::cmp::Ord for Big {
|
|||
}
|
||||
}
|
||||
|
||||
// It is more efficient to compare scalar types before non-scalar types.
|
||||
struct Reorder {
|
||||
b1: Option<f32>,
|
||||
b2: u16,
|
||||
b3: &'static str,
|
||||
b4: i8,
|
||||
b5: u128,
|
||||
_b: *mut &'static dyn FnMut() -> (),
|
||||
b6: f64,
|
||||
b7: &'static mut (),
|
||||
b8: char,
|
||||
b9: &'static [i64],
|
||||
b10: &'static *const bool,
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::marker::StructuralPartialEq for Reorder { }
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::PartialEq for Reorder {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Reorder) -> bool {
|
||||
self.b2 == other.b2 && self.b4 == other.b4 && self.b5 == other.b5 &&
|
||||
self.b6 == other.b6 && self.b7 == other.b7 &&
|
||||
self.b8 == other.b8 && self.b10 == other.b10 &&
|
||||
self.b1 == other.b1 && self.b3 == other.b3 &&
|
||||
self._b == other._b && self.b9 == other.b9
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::PartialOrd for Reorder {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Reorder)
|
||||
-> ::core::option::Option<::core::cmp::Ordering> {
|
||||
match ::core::cmp::PartialOrd::partial_cmp(&self.b1, &other.b1) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
|
||||
match ::core::cmp::PartialOrd::partial_cmp(&self.b2,
|
||||
&other.b2) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal)
|
||||
=>
|
||||
match ::core::cmp::PartialOrd::partial_cmp(&self.b3,
|
||||
&other.b3) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal)
|
||||
=>
|
||||
match ::core::cmp::PartialOrd::partial_cmp(&self.b4,
|
||||
&other.b4) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal)
|
||||
=>
|
||||
match ::core::cmp::PartialOrd::partial_cmp(&self.b5,
|
||||
&other.b5) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal)
|
||||
=>
|
||||
match ::core::cmp::PartialOrd::partial_cmp(&self._b,
|
||||
&other._b) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal)
|
||||
=>
|
||||
match ::core::cmp::PartialOrd::partial_cmp(&self.b6,
|
||||
&other.b6) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal)
|
||||
=>
|
||||
match ::core::cmp::PartialOrd::partial_cmp(&self.b7,
|
||||
&other.b7) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal)
|
||||
=>
|
||||
match ::core::cmp::PartialOrd::partial_cmp(&self.b8,
|
||||
&other.b8) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal)
|
||||
=>
|
||||
match ::core::cmp::PartialOrd::partial_cmp(&self.b9,
|
||||
&other.b9) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal)
|
||||
=>
|
||||
::core::cmp::PartialOrd::partial_cmp(&self.b10, &other.b10),
|
||||
cmp => cmp,
|
||||
},
|
||||
cmp => cmp,
|
||||
},
|
||||
cmp => cmp,
|
||||
},
|
||||
cmp => cmp,
|
||||
},
|
||||
cmp => cmp,
|
||||
},
|
||||
cmp => cmp,
|
||||
},
|
||||
cmp => cmp,
|
||||
},
|
||||
cmp => cmp,
|
||||
},
|
||||
cmp => cmp,
|
||||
},
|
||||
cmp => cmp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A struct that doesn't impl `Copy`, which means it gets the non-simple
|
||||
// `clone` implemention that clones the fields individually.
|
||||
struct NonCopy(u32);
|
||||
|
|
@ -1167,6 +1261,77 @@ impl ::core::cmp::Ord for Mixed {
|
|||
}
|
||||
}
|
||||
|
||||
// When comparing enum variant it is more efficient to compare scalar types before non-scalar types.
|
||||
enum ReorderEnum {
|
||||
A(i32),
|
||||
B,
|
||||
C(i8),
|
||||
D,
|
||||
E,
|
||||
F,
|
||||
G(&'static mut str, *const u8, *const dyn Fn() -> ()),
|
||||
H,
|
||||
I,
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::marker::StructuralPartialEq for ReorderEnum { }
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::PartialEq for ReorderEnum {
|
||||
#[inline]
|
||||
fn eq(&self, other: &ReorderEnum) -> bool {
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
__self_discr == __arg1_discr &&
|
||||
match (self, other) {
|
||||
(ReorderEnum::A(__self_0), ReorderEnum::A(__arg1_0)) =>
|
||||
__self_0 == __arg1_0,
|
||||
(ReorderEnum::C(__self_0), ReorderEnum::C(__arg1_0)) =>
|
||||
__self_0 == __arg1_0,
|
||||
(ReorderEnum::G(__self_0, __self_1, __self_2),
|
||||
ReorderEnum::G(__arg1_0, __arg1_1, __arg1_2)) =>
|
||||
__self_1 == __arg1_1 && __self_0 == __arg1_0 &&
|
||||
__self_2 == __arg1_2,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::PartialOrd for ReorderEnum {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &ReorderEnum)
|
||||
-> ::core::option::Option<::core::cmp::Ordering> {
|
||||
let __self_discr = ::core::intrinsics::discriminant_value(self);
|
||||
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
|
||||
match ::core::cmp::PartialOrd::partial_cmp(&__self_discr,
|
||||
&__arg1_discr) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
|
||||
match (self, other) {
|
||||
(ReorderEnum::A(__self_0), ReorderEnum::A(__arg1_0)) =>
|
||||
::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
|
||||
(ReorderEnum::C(__self_0), ReorderEnum::C(__arg1_0)) =>
|
||||
::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
|
||||
(ReorderEnum::G(__self_0, __self_1, __self_2),
|
||||
ReorderEnum::G(__arg1_0, __arg1_1, __arg1_2)) =>
|
||||
match ::core::cmp::PartialOrd::partial_cmp(__self_0,
|
||||
__arg1_0) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal)
|
||||
=>
|
||||
match ::core::cmp::PartialOrd::partial_cmp(__self_1,
|
||||
__arg1_1) {
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal)
|
||||
=> ::core::cmp::PartialOrd::partial_cmp(__self_2, __arg1_2),
|
||||
cmp => cmp,
|
||||
},
|
||||
cmp => cmp,
|
||||
},
|
||||
_ =>
|
||||
::core::option::Option::Some(::core::cmp::Ordering::Equal),
|
||||
},
|
||||
cmp => cmp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An enum with no fieldless variants. Note that `Default` cannot be derived
|
||||
// for this enum.
|
||||
enum Fielded { X(u32), Y(bool), Z(Option<i32>), }
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! Tests invalid lifetime bounds and generic parameters in higher-ranked types.
|
||||
|
||||
type A = for<'b, 'a: 'b> fn(); //~ ERROR bounds cannot be used in this context
|
||||
type B = for<'b, 'a: 'b,> fn(); //~ ERROR bounds cannot be used in this context
|
||||
type C = for<'b, 'a: 'b +> fn(); //~ ERROR bounds cannot be used in this context
|
||||
|
|
@ -1,23 +1,23 @@
|
|||
error: bounds cannot be used in this context
|
||||
--> $DIR/bounds-lifetime.rs:1:22
|
||||
--> $DIR/higher-ranked-invalid-bounds.rs:3:22
|
||||
|
|
||||
LL | type A = for<'b, 'a: 'b> fn();
|
||||
| ^^
|
||||
|
||||
error: bounds cannot be used in this context
|
||||
--> $DIR/bounds-lifetime.rs:2:22
|
||||
--> $DIR/higher-ranked-invalid-bounds.rs:4:22
|
||||
|
|
||||
LL | type B = for<'b, 'a: 'b,> fn();
|
||||
| ^^
|
||||
|
||||
error: bounds cannot be used in this context
|
||||
--> $DIR/bounds-lifetime.rs:3:22
|
||||
--> $DIR/higher-ranked-invalid-bounds.rs:5:22
|
||||
|
|
||||
LL | type C = for<'b, 'a: 'b +> fn();
|
||||
| ^^
|
||||
|
||||
error[E0658]: only lifetime parameters can be used in this context
|
||||
--> $DIR/bounds-lifetime.rs:4:18
|
||||
--> $DIR/higher-ranked-invalid-bounds.rs:6:18
|
||||
|
|
||||
LL | type D = for<'a, T> fn();
|
||||
| ^
|
||||
|
|
@ -27,7 +27,7 @@ LL | type D = for<'a, T> fn();
|
|||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: only lifetime parameters can be used in this context
|
||||
--> $DIR/bounds-lifetime.rs:5:18
|
||||
--> $DIR/higher-ranked-invalid-bounds.rs:7:18
|
||||
|
|
||||
LL | type E = dyn for<T, U> Fn();
|
||||
| ^ ^
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Tests bitwise operations with platform-specific and negative number behavior.
|
||||
|
||||
//@ run-pass
|
||||
|
||||
#[cfg(any(target_pointer_width = "32"))]
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Tests moving an `Arc` value out of an `Option` in a match expression.
|
||||
|
||||
//@ run-pass
|
||||
|
||||
use std::sync::Arc;
|
||||
19
tests/ui/pattern/pattern-match-invalid-variant.rs
Normal file
19
tests/ui/pattern/pattern-match-invalid-variant.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
//! Tests invalid enum variant in a match expression.
|
||||
|
||||
enum Color {
|
||||
Rgb(isize, isize, isize),
|
||||
Rgba(isize, isize, isize, isize),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let red: Color = Color::Rgb(255, 0, 0);
|
||||
match red {
|
||||
Color::Rgb(r, g, b) => {
|
||||
println!("rgb");
|
||||
}
|
||||
Color::Hsl(h, s, l) => {
|
||||
//~^ ERROR no variant
|
||||
println!("hsl");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
error[E0599]: no variant or associated item named `Hsl` found for enum `Color` in the current scope
|
||||
--> $DIR/bogus-tag.rs:7:16
|
||||
--> $DIR/pattern-match-invalid-variant.rs:14:16
|
||||
|
|
||||
LL | enum Color { Rgb(isize, isize, isize), Rgba(isize, isize, isize, isize), }
|
||||
LL | enum Color {
|
||||
| ---------- variant or associated item `Hsl` not found for this enum
|
||||
...
|
||||
LL | Color::Hsl(h, s, l) => { println!("hsl"); }
|
||||
LL | Color::Hsl(h, s, l) => {
|
||||
| ^^^ variant or associated item not found in `Color`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
Loading…
Add table
Add a link
Reference in a new issue