From: bors Date: Tue, 31 Jan 2023 02:46:11 +0000 (+0000) Subject: Auto merge of #107443 - cjgillot:generator-less-query, r=compiler-errors X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=dc3e59cb3fe05ebd752d3a2269f501c00327be22;hp=1d3f5b49d6bdfb2a051ddbfb7ad4b4ad603e9908;p=rust.git Auto merge of #107443 - cjgillot:generator-less-query, r=compiler-errors Test drop_tracking_mir before querying generator. r? `@ghost` --- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f77656e5c1..552680f06f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -418,14 +418,14 @@ jobs: os: windows-latest-xl - name: i686-mingw-1 env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain" + RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu" SCRIPT: make ci-mingw-subset-1 NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 os: windows-latest-xl - name: i686-mingw-2 env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain" + RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu" SCRIPT: make ci-mingw-subset-2 NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 @@ -433,21 +433,21 @@ jobs: - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-subset-1 - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 os: windows-latest-xl - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-subset-2 - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 os: windows-latest-xl - name: dist-x86_64-msvc env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler --set rust.lto=thin" - SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths + SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 os: windows-latest-xl - name: dist-i686-msvc @@ -465,7 +465,7 @@ jobs: os: windows-latest-xl - name: dist-i686-mingw env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain" + RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler" NO_DOWNLOAD_CI_LLVM: 1 SCRIPT: python x.py dist bootstrap --include-default-paths CUSTOM_MINGW: 1 @@ -474,7 +474,7 @@ jobs: - name: dist-x86_64-mingw env: SCRIPT: python x.py dist bootstrap --include-default-paths - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler" NO_DOWNLOAD_CI_LLVM: 1 CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 1011794d7b3..8c579bac7e8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1128,8 +1128,12 @@ fn explain_captures( "{place_name} {partially_str}moved due to this method call{loop_message}", ), ); + let infcx = tcx.infer_ctxt().build(); + // Erase and shadow everything that could be passed to the new infcx. let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty); + let method_substs = tcx.erase_regions(method_substs); + if let ty::Adt(def, substs) = ty.kind() && Some(def.did()) == tcx.lang_items().pin_type() && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind() diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 11729e2c83f..2b81a35052d 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -181,9 +181,6 @@ pub(super) fn ascribe_user_type( user_ty: ty::UserType<'tcx>, span: Span, ) { - // FIXME: Ideally MIR types are normalized, but this is not always true. - let mir_ty = self.normalize(mir_ty, Locations::All(span)); - self.fully_perform_op( Locations::All(span), ConstraintCategory::Boring, @@ -217,7 +214,9 @@ pub(super) fn ascribe_user_type_skip_wf( return; } + // FIXME: Ideally MIR types are normalized, but this is not always true. let mir_ty = self.normalize(mir_ty, Locations::All(span)); + let cause = ObligationCause::dummy_with_span(span); let param_env = self.param_env; let op = |infcx: &'_ _| { diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 240167146e1..0481a118906 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -17,6 +17,7 @@ pub fn expand_deriving_copy( span, path: path_std!(marker::Copy), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: false, additional_bounds: Vec::new(), supports_unions: true, methods: Vec::new(), diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index ef5a75f428d..42f50d8ade2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -73,6 +73,7 @@ pub fn expand_deriving_clone( span, path: path_std!(clone::Clone), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: bounds, supports_unions: true, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 3e994f037ad..424719f9795 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -27,6 +27,7 @@ pub fn expand_deriving_eq( span, path: path_std!(cmp::Eq), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: true, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index a926fca4e65..671f32550d2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -20,6 +20,7 @@ pub fn expand_deriving_ord( span, path: path_std!(cmp::Ord), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 9051fe0b28a..88d454fbc11 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -84,6 +84,7 @@ fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOr span, path: path_std!(cmp::PartialEq), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 2fc30d8e05f..bcc90442eb7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -59,6 +59,7 @@ pub fn expand_deriving_partial_ord( span, path: path_std!(cmp::PartialOrd), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: vec![], supports_unions: false, methods: vec![partial_cmp_def], diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index e0f487e8648..897048f6421 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -23,6 +23,7 @@ pub fn expand_deriving_debug( span, path: path_std!(fmt::Debug), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 5f9519dad1b..c783e46eda9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -25,6 +25,7 @@ pub fn expand_deriving_rustc_decodable( span, path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 18270747296..a6c8b111527 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -25,6 +25,7 @@ pub fn expand_deriving_default( span, path: Path::new(vec![kw::Default, sym::Default]), skip_path_as_bound: has_a_default_variant(item), + needs_copy_as_bound_if_packed: false, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 2afeed927ac..a5e2b599df4 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -109,6 +109,7 @@ pub fn expand_deriving_rustc_encodable( span, path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 17b7ac0eba1..97de40bac34 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -165,11 +165,12 @@ use crate::deriving; use rustc_ast::ptr::P; use rustc_ast::{ - self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind, + self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, + Mutability, PatKind, TyKind, VariantData, }; -use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::cell::RefCell; @@ -191,6 +192,9 @@ pub struct TraitDef<'a> { /// Whether to skip adding the current trait as a bound to the type parameters of the type. pub skip_path_as_bound: bool, + /// Whether `Copy` is needed as an additional bound on type parameters in a packed struct. + pub needs_copy_as_bound_if_packed: bool, + /// Additional bounds required of any type parameters of the type, /// other than the current trait pub additional_bounds: Vec, @@ -455,18 +459,6 @@ pub fn expand_ext( } false }); - let has_no_type_params = match &item.kind { - ast::ItemKind::Struct(_, generics) - | ast::ItemKind::Enum(_, generics) - | ast::ItemKind::Union(_, generics) => !generics - .params - .iter() - .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })), - _ => unreachable!(), - }; - let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); - let copy_fields = - is_packed && has_no_type_params && cx.resolver.has_derive_copy(container_id); let newitem = match &item.kind { ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def( @@ -475,7 +467,7 @@ pub fn expand_ext( item.ident, generics, from_scratch, - copy_fields, + is_packed, ), ast::ItemKind::Enum(enum_def, generics) => { // We ignore `is_packed` here, because `repr(packed)` @@ -493,7 +485,7 @@ pub fn expand_ext( item.ident, generics, from_scratch, - copy_fields, + is_packed, ) } else { cx.span_err(mitem.span, "this trait cannot be derived for unions"); @@ -565,6 +557,7 @@ fn create_derived_impl( generics: &Generics, field_tys: Vec>, methods: Vec>, + is_packed: bool, ) -> P { let trait_path = self.path.to_path(cx, self.span, type_ident, generics); @@ -607,20 +600,32 @@ fn create_derived_impl( .map(|param| match ¶m.kind { GenericParamKind::Lifetime { .. } => param.clone(), GenericParamKind::Type { .. } => { - // I don't think this can be moved out of the loop, since - // a GenericBound requires an ast id - let bounds: Vec<_> = - // extra restrictions on the generics parameters to the - // type being derived upon - self.additional_bounds.iter().map(|p| { - cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)) - }).chain( - // require the current trait - self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone())) - ).chain( - // also add in any bounds from the declaration - param.bounds.iter().cloned() - ).collect(); + // Extra restrictions on the generics parameters to the + // type being derived upon. + let bounds: Vec<_> = self + .additional_bounds + .iter() + .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) + .chain( + // Add a bound for the current trait. + self.skip_path_as_bound + .not() + .then(|| cx.trait_bound(trait_path.clone())), + ) + .chain({ + // Add a `Copy` bound if required. + if is_packed && self.needs_copy_as_bound_if_packed { + let p = deriving::path_std!(marker::Copy); + Some(cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) + } else { + None + } + }) + .chain( + // Also add in any bounds from the declaration. + param.bounds.iter().cloned(), + ) + .collect(); cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None) } @@ -692,9 +697,17 @@ fn create_derived_impl( .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) .collect(); - // require the current trait + // Require the current trait. bounds.push(cx.trait_bound(trait_path.clone())); + // Add a `Copy` bound if required. + if is_packed && self.needs_copy_as_bound_if_packed { + let p = deriving::path_std!(marker::Copy); + bounds.push( + cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)), + ); + } + let predicate = ast::WhereBoundPredicate { span: self.span, bound_generic_params: field_ty_param.bound_generic_params, @@ -762,7 +775,7 @@ fn expand_struct_def( type_ident: Ident, generics: &Generics, from_scratch: bool, - copy_fields: bool, + is_packed: bool, ) -> P { let field_tys: Vec> = struct_def.fields().iter().map(|field| field.ty.clone()).collect(); @@ -790,7 +803,7 @@ fn expand_struct_def( type_ident, &selflike_args, &nonselflike_args, - copy_fields, + is_packed, ) }; @@ -806,7 +819,7 @@ fn expand_struct_def( }) .collect(); - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) + self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed) } fn expand_enum_def( @@ -861,7 +874,8 @@ fn expand_enum_def( }) .collect(); - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) + let is_packed = false; // enums are never packed + self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed) } } @@ -1011,8 +1025,8 @@ fn create_method( /// ``` /// But if the struct is `repr(packed)`, we can't use something like /// `&self.x` because that might cause an unaligned ref. So for any trait - /// method that takes a reference, if the struct impls `Copy` then we use a - /// local block to force a copy: + /// method that takes a reference, we use a local block to force a copy. + /// This requires that the field impl `Copy`. /// ``` /// # struct A { x: u8, y: u8 } /// impl PartialEq for A { @@ -1027,10 +1041,6 @@ fn create_method( /// ::core::hash::Hash::hash(&{ self.y }, state) /// } /// } - /// ``` - /// If the struct doesn't impl `Copy`, we use the normal `&self.x`. This - /// only works if the fields match the alignment required by the - /// `packed(N)` attribute. (We'll get errors later on if not.) fn expand_struct_method_body<'b>( &self, cx: &mut ExtCtxt<'_>, @@ -1039,12 +1049,12 @@ fn expand_struct_method_body<'b>( type_ident: Ident, selflike_args: &[P], nonselflike_args: &[P], - copy_fields: bool, + is_packed: bool, ) -> BlockOrExpr { assert!(selflike_args.len() == 1 || selflike_args.len() == 2); let selflike_fields = - trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, copy_fields); + trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, is_packed); self.call_substructure_method( cx, trait_, @@ -1514,7 +1524,7 @@ fn create_struct_field_access_fields( cx: &mut ExtCtxt<'_>, selflike_args: &[P], struct_def: &'a VariantData, - copy_fields: bool, + is_packed: bool, ) -> Vec { self.create_fields(struct_def, |i, struct_field, sp| { selflike_args @@ -1533,10 +1543,39 @@ fn create_struct_field_access_fields( }), ), ); - if copy_fields { - field_expr = cx.expr_block( - cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]), - ); + // In general, fields in packed structs are copied via a + // block, e.g. `&{self.0}`. The one exception is `[u8]` + // fields, which cannot be copied and also never cause + // unaligned references. This exception is allowed to + // handle the `FlexZeroSlice` type in the `zerovec` crate + // within `icu4x-0.9.0`. + // + // Once use of `icu4x-0.9.0` has dropped sufficiently, this + // exception should be removed. + let is_u8_slice = if let TyKind::Slice(ty) = &struct_field.ty.kind && + let TyKind::Path(None, rustc_ast::Path { segments, .. }) = &ty.kind && + let [seg] = segments.as_slice() && + seg.ident.name == sym::u8 && seg.args.is_none() + { + true + } else { + false + }; + if is_packed { + if is_u8_slice { + cx.sess.parse_sess.buffer_lint_with_diagnostic( + BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, + sp, + ast::CRATE_NODE_ID, + "byte slice in a packed struct that derives a built-in trait", + rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive + ); + } else { + // Wrap the expression in `{...}`, causing a copy. + field_expr = cx.expr_block( + cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]), + ); + } } cx.expr_addr_of(sp, field_expr) }) diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index f8570d8f86a..5c2e89c5697 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -24,6 +24,7 @@ pub fn expand_deriving_hash( span, path, skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index d9ccba07a34..32cd3a4efa2 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -191,7 +191,7 @@ pub unsafe fn create_module<'ll>( // // FIXME(#34960) let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); - let custom_llvm_used = cfg_llvm_root.trim() != ""; + let custom_llvm_used = !cfg_llvm_root.trim().is_empty(); if !custom_llvm_used && target_data_layout != llvm_data_layout { bug!( diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index dd1ac2c74ae..95aad10fdb0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -36,7 +36,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Arguments get assigned to by means of the function being called for arg in mir.args_iter() { - analyzer.assign(arg, mir::START_BLOCK.start_location()); + analyzer.assign(arg, DefLocation::Argument); } // If there exists a local definition that dominates all uses of that local, @@ -64,7 +64,22 @@ enum LocalKind { /// A scalar or a scalar pair local that is neither defined nor used. Unused, /// A scalar or a scalar pair local with a single definition that dominates all uses. - SSA(mir::Location), + SSA(DefLocation), +} + +#[derive(Copy, Clone, PartialEq, Eq)] +enum DefLocation { + Argument, + Body(Location), +} + +impl DefLocation { + fn dominates(self, location: Location, dominators: &Dominators) -> bool { + match self { + DefLocation::Argument => true, + DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators), + } + } } struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { @@ -74,17 +89,13 @@ struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { } impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { - fn assign(&mut self, local: mir::Local, location: Location) { + fn assign(&mut self, local: mir::Local, location: DefLocation) { let kind = &mut self.locals[local]; match *kind { LocalKind::ZST => {} LocalKind::Memory => {} - LocalKind::Unused => { - *kind = LocalKind::SSA(location); - } - LocalKind::SSA(_) => { - *kind = LocalKind::Memory; - } + LocalKind::Unused => *kind = LocalKind::SSA(location), + LocalKind::SSA(_) => *kind = LocalKind::Memory, } } @@ -166,7 +177,7 @@ fn visit_assign( debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue); if let Some(local) = place.as_local() { - self.assign(local, location); + self.assign(local, DefLocation::Body(location)); if self.locals[local] != LocalKind::Memory { let decl_span = self.fx.mir.local_decls[local].source_info.span; if !self.fx.rvalue_creates_operand(rvalue, decl_span) { @@ -189,7 +200,7 @@ fn visit_local(&mut self, local: mir::Local, context: PlaceContext, location: Lo match context { PlaceContext::MutatingUse(MutatingUseContext::Call) | PlaceContext::MutatingUse(MutatingUseContext::Yield) => { - self.assign(local, location); + self.assign(local, DefLocation::Body(location)); } PlaceContext::NonUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {} diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index 022051e008e..446c6832cb7 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -498,6 +498,21 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante out } + ThirFlat => { + let mut out = String::new(); + abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); + debug!("pretty printing THIR flat"); + for did in tcx.hir().body_owners() { + let _ = writeln!( + out, + "{:?}:\n{}\n", + did, + tcx.thir_flat(ty::WithOptConstParam::unknown(did)) + ); + } + out + } + _ => unreachable!(), }; diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index d63ff77d8e2..dca678dff7a 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -100,6 +100,8 @@ lint_cstring_ptr = getting the inner pointer of a temporary `CString` .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned .help = for more information, see https://doc.rust-lang.org/reference/destructors.html +lint_multple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits + lint_identifier_non_ascii_char = identifier contains non-ASCII characters lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_error_messages/locales/en-US/parse.ftl index a3e2002da78..1728ef70cba 100644 --- a/compiler/rustc_error_messages/locales/en-US/parse.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl @@ -199,6 +199,17 @@ parse_match_arm_body_without_braces = `match` arm body without braces } with a body .suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression +parse_inclusive_range_extra_equals = unexpected `=` after inclusive range + .suggestion_remove_eq = use `..=` instead + .note = inclusive ranges end with a single equals sign (`..=`) + +parse_inclusive_range_match_arrow = unexpected `=>` after open range + .suggestion_add_space = add a space between the pattern and `=>` + +parse_inclusive_range_no_end = inclusive range with no end + .suggestion_open_range = use `..` instead + .note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`) + parse_struct_literal_not_allowed_here = struct literals are not allowed here .suggestion = surround the struct literal with parentheses diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 196c31302a0..af9c40a3ba5 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -160,6 +160,8 @@ pub fn set(&self, features: &mut Features, span: Span) { (active, intrinsics, "1.0.0", None, None), /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. (active, lang_items, "1.0.0", None, None), + /// Allows the `multiple_supertrait_upcastable` lint. + (active, multiple_supertrait_upcastable, "CURRENT_RUSTC_VERSION", None, None), /// Allows using `#[omit_gdb_pretty_printer_section]`. (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), /// Allows using `#[prelude_import]` on glob `use` items. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4696a4bd9ab..a063307af0c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2263,7 +2263,7 @@ pub struct TraitItem<'hir> { pub defaultness: Defaultness, } -impl TraitItem<'_> { +impl<'hir> TraitItem<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -2273,6 +2273,32 @@ pub fn hir_id(&self) -> HirId { pub fn trait_item_id(&self) -> TraitItemId { TraitItemId { owner_id: self.owner_id } } + + /// Expect an [`TraitItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, Option) { + let TraitItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; + (ty, body) + } + + /// Expect an [`TraitItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, &TraitFn<'hir>) { + let TraitItemKind::Fn(ty, trfn) = &self.kind else { self.expect_failed("a function") }; + (ty, trfn) + } + + /// Expect an [`TraitItemKind::Type`] or panic. + #[track_caller] + pub fn expect_type(&self) -> (GenericBounds<'hir>, Option<&'hir Ty<'hir>>) { + let TraitItemKind::Type(bounds, ty) = self.kind else { self.expect_failed("a type") }; + (bounds, ty) + } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } /// Represents a trait method's body (or just argument names). @@ -2325,7 +2351,7 @@ pub struct ImplItem<'hir> { pub vis_span: Span, } -impl ImplItem<'_> { +impl<'hir> ImplItem<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -2335,6 +2361,32 @@ pub fn hir_id(&self) -> HirId { pub fn impl_item_id(&self) -> ImplItemId { ImplItemId { owner_id: self.owner_id } } + + /// Expect an [`ImplItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { + let ImplItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; + (ty, body) + } + + /// Expect an [`ImplItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, BodyId) { + let ImplItemKind::Fn(ty, body) = &self.kind else { self.expect_failed("a function") }; + (ty, *body) + } + + /// Expect an [`ImplItemKind::Type`] or panic. + #[track_caller] + pub fn expect_type(&self) -> &'hir Ty<'hir> { + let ImplItemKind::Type(ty) = self.kind else { self.expect_failed("a type") }; + ty + } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } /// Represents various kinds of content within an `impl`. @@ -2995,7 +3047,7 @@ pub struct Item<'hir> { pub vis_span: Span, } -impl Item<'_> { +impl<'hir> Item<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -3005,6 +3057,132 @@ pub fn hir_id(&self) -> HirId { pub fn item_id(&self) -> ItemId { ItemId { owner_id: self.owner_id } } + + /// Expect an [`ItemKind::ExternCrate`] or panic. + #[track_caller] + pub fn expect_extern_crate(&self) -> Option { + let ItemKind::ExternCrate(s) = self.kind else { self.expect_failed("an extern crate") }; + s + } + + /// Expect an [`ItemKind::Use`] or panic. + #[track_caller] + pub fn expect_use(&self) -> (&'hir UsePath<'hir>, UseKind) { + let ItemKind::Use(p, uk) = self.kind else { self.expect_failed("a use") }; + (p, uk) + } + + /// Expect an [`ItemKind::Static`] or panic. + #[track_caller] + pub fn expect_static(&self) -> (&'hir Ty<'hir>, Mutability, BodyId) { + let ItemKind::Static(ty, mutbl, body) = self.kind else { self.expect_failed("a static") }; + (ty, mutbl, body) + } + /// Expect an [`ItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { + let ItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; + (ty, body) + } + /// Expect an [`ItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, &'hir Generics<'hir>, BodyId) { + let ItemKind::Fn(sig, gen, body) = &self.kind else { self.expect_failed("a function") }; + (sig, gen, *body) + } + + /// Expect an [`ItemKind::Macro`] or panic. + #[track_caller] + pub fn expect_macro(&self) -> (&ast::MacroDef, MacroKind) { + let ItemKind::Macro(def, mk) = &self.kind else { self.expect_failed("a macro") }; + (def, *mk) + } + + /// Expect an [`ItemKind::Mod`] or panic. + #[track_caller] + pub fn expect_mod(&self) -> &'hir Mod<'hir> { + let ItemKind::Mod(m) = self.kind else { self.expect_failed("a module") }; + m + } + + /// Expect an [`ItemKind::ForeignMod`] or panic. + #[track_caller] + pub fn expect_foreign_mod(&self) -> (Abi, &'hir [ForeignItemRef]) { + let ItemKind::ForeignMod { abi, items } = self.kind else { self.expect_failed("a foreign module") }; + (abi, items) + } + + /// Expect an [`ItemKind::GlobalAsm`] or panic. + #[track_caller] + pub fn expect_global_asm(&self) -> &'hir InlineAsm<'hir> { + let ItemKind::GlobalAsm(asm) = self.kind else { self.expect_failed("a global asm") }; + asm + } + + /// Expect an [`ItemKind::TyAlias`] or panic. + #[track_caller] + pub fn expect_ty_alias(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>) { + let ItemKind::TyAlias(ty, gen) = self.kind else { self.expect_failed("a type alias") }; + (ty, gen) + } + + /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`. + /// Expect an [`ItemKind::OpaqueTy`] or panic. + #[track_caller] + pub fn expect_opaque_ty(&self) -> &OpaqueTy<'hir> { + let ItemKind::OpaqueTy(ty) = &self.kind else { self.expect_failed("an opaque type") }; + ty + } + + /// Expect an [`ItemKind::Enum`] or panic. + #[track_caller] + pub fn expect_enum(&self) -> (&EnumDef<'hir>, &'hir Generics<'hir>) { + let ItemKind::Enum(def, gen) = &self.kind else { self.expect_failed("an enum") }; + (def, gen) + } + + /// Expect an [`ItemKind::Struct`] or panic. + #[track_caller] + pub fn expect_struct(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { + let ItemKind::Struct(data, gen) = &self.kind else { self.expect_failed("a struct") }; + (data, gen) + } + + /// A union definition, e.g., `union Foo {x: A, y: B}`. + /// Expect an [`ItemKind::Union`] or panic. + #[track_caller] + pub fn expect_union(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { + let ItemKind::Union(data, gen) = &self.kind else { self.expect_failed("a union") }; + (data, gen) + } + + /// Expect an [`ItemKind::Trait`] or panic. + #[track_caller] + pub fn expect_trait( + self, + ) -> (IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]) { + let ItemKind::Trait(is_auto, unsafety, gen, bounds, items) = self.kind else { self.expect_failed("a trait") }; + (is_auto, unsafety, gen, bounds, items) + } + + /// Expect an [`ItemKind::TraitAlias`] or panic. + #[track_caller] + pub fn expect_trait_alias(&self) -> (&'hir Generics<'hir>, GenericBounds<'hir>) { + let ItemKind::TraitAlias(gen, bounds) = self.kind else { self.expect_failed("a trait alias") }; + (gen, bounds) + } + + /// Expect an [`ItemKind::Impl`] or panic. + #[track_caller] + pub fn expect_impl(&self) -> &'hir Impl<'hir> { + let ItemKind::Impl(imp) = self.kind else { self.expect_failed("an impl") }; + imp + } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -3597,6 +3775,185 @@ pub fn fn_kind(self) -> Option> { pub fn tuple_fields(&self) -> Option<&'hir [FieldDef<'hir>]> { if let Node::Ctor(&VariantData::Tuple(fields, _, _)) = self { Some(fields) } else { None } } + + /// Expect a [`Node::Param`] or panic. + #[track_caller] + pub fn expect_param(self) -> &'hir Param<'hir> { + let Node::Param(this) = self else { self.expect_failed("a parameter") }; + this + } + + /// Expect a [`Node::Item`] or panic. + #[track_caller] + pub fn expect_item(self) -> &'hir Item<'hir> { + let Node::Item(this) = self else { self.expect_failed("a item") }; + this + } + + /// Expect a [`Node::ForeignItem`] or panic. + #[track_caller] + pub fn expect_foreign_item(self) -> &'hir ForeignItem<'hir> { + let Node::ForeignItem(this) = self else { self.expect_failed("a foreign item") }; + this + } + + /// Expect a [`Node::TraitItem`] or panic. + #[track_caller] + pub fn expect_trait_item(self) -> &'hir TraitItem<'hir> { + let Node::TraitItem(this) = self else { self.expect_failed("a trait item") }; + this + } + + /// Expect a [`Node::ImplItem`] or panic. + #[track_caller] + pub fn expect_impl_item(self) -> &'hir ImplItem<'hir> { + let Node::ImplItem(this) = self else { self.expect_failed("an implementation item") }; + this + } + + /// Expect a [`Node::Variant`] or panic. + #[track_caller] + pub fn expect_variant(self) -> &'hir Variant<'hir> { + let Node::Variant(this) = self else { self.expect_failed("a variant") }; + this + } + + /// Expect a [`Node::Field`] or panic. + #[track_caller] + pub fn expect_field(self) -> &'hir FieldDef<'hir> { + let Node::Field(this) = self else { self.expect_failed("a field definition") }; + this + } + + /// Expect a [`Node::AnonConst`] or panic. + #[track_caller] + pub fn expect_anon_const(self) -> &'hir AnonConst { + let Node::AnonConst(this) = self else { self.expect_failed("an anonymous constant") }; + this + } + + /// Expect a [`Node::Expr`] or panic. + #[track_caller] + pub fn expect_expr(self) -> &'hir Expr<'hir> { + let Node::Expr(this) = self else { self.expect_failed("an expression") }; + this + } + /// Expect a [`Node::ExprField`] or panic. + #[track_caller] + pub fn expect_expr_field(self) -> &'hir ExprField<'hir> { + let Node::ExprField(this) = self else { self.expect_failed("an expression field") }; + this + } + + /// Expect a [`Node::Stmt`] or panic. + #[track_caller] + pub fn expect_stmt(self) -> &'hir Stmt<'hir> { + let Node::Stmt(this) = self else { self.expect_failed("a statement") }; + this + } + + /// Expect a [`Node::PathSegment`] or panic. + #[track_caller] + pub fn expect_path_segment(self) -> &'hir PathSegment<'hir> { + let Node::PathSegment(this) = self else { self.expect_failed("a path segment") }; + this + } + + /// Expect a [`Node::Ty`] or panic. + #[track_caller] + pub fn expect_ty(self) -> &'hir Ty<'hir> { + let Node::Ty(this) = self else { self.expect_failed("a type") }; + this + } + + /// Expect a [`Node::TypeBinding`] or panic. + #[track_caller] + pub fn expect_type_binding(self) -> &'hir TypeBinding<'hir> { + let Node::TypeBinding(this) = self else { self.expect_failed("a type binding") }; + this + } + + /// Expect a [`Node::TraitRef`] or panic. + #[track_caller] + pub fn expect_trait_ref(self) -> &'hir TraitRef<'hir> { + let Node::TraitRef(this) = self else { self.expect_failed("a trait reference") }; + this + } + + /// Expect a [`Node::Pat`] or panic. + #[track_caller] + pub fn expect_pat(self) -> &'hir Pat<'hir> { + let Node::Pat(this) = self else { self.expect_failed("a pattern") }; + this + } + + /// Expect a [`Node::PatField`] or panic. + #[track_caller] + pub fn expect_pat_field(self) -> &'hir PatField<'hir> { + let Node::PatField(this) = self else { self.expect_failed("a pattern field") }; + this + } + + /// Expect a [`Node::Arm`] or panic. + #[track_caller] + pub fn expect_arm(self) -> &'hir Arm<'hir> { + let Node::Arm(this) = self else { self.expect_failed("an arm") }; + this + } + + /// Expect a [`Node::Block`] or panic. + #[track_caller] + pub fn expect_block(self) -> &'hir Block<'hir> { + let Node::Block(this) = self else { self.expect_failed("a block") }; + this + } + + /// Expect a [`Node::Local`] or panic. + #[track_caller] + pub fn expect_local(self) -> &'hir Local<'hir> { + let Node::Local(this) = self else { self.expect_failed("a local") }; + this + } + + /// Expect a [`Node::Ctor`] or panic. + #[track_caller] + pub fn expect_ctor(self) -> &'hir VariantData<'hir> { + let Node::Ctor(this) = self else { self.expect_failed("a constructor") }; + this + } + + /// Expect a [`Node::Lifetime`] or panic. + #[track_caller] + pub fn expect_lifetime(self) -> &'hir Lifetime { + let Node::Lifetime(this) = self else { self.expect_failed("a lifetime") }; + this + } + + /// Expect a [`Node::GenericParam`] or panic. + #[track_caller] + pub fn expect_generic_param(self) -> &'hir GenericParam<'hir> { + let Node::GenericParam(this) = self else { self.expect_failed("a generic parameter") }; + this + } + + /// Expect a [`Node::Crate`] or panic. + #[track_caller] + pub fn expect_crate(self) -> &'hir Mod<'hir> { + let Node::Crate(this) = self else { self.expect_failed("a crate") }; + this + } + + /// Expect a [`Node::Infer`] or panic. + #[track_caller] + pub fn expect_infer(self) -> &'hir InferArg { + let Node::Infer(this) = self else { self.expect_failed("an infer") }; + this + } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} node, found {self:?}") + } } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index caf26a75d3c..bec9f0ff077 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -3140,8 +3140,7 @@ fn suggest_trait_fn_ty_for_impl_fn_infer( let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) = hir.get(fn_hir_id) else { return None }; - let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) = - hir.get_parent(fn_hir_id) else { bug!("ImplItem should have Impl parent") }; + let i = hir.get_parent(fn_hir_id).expect_item().expect_impl(); let trait_ref = self.instantiate_mono_trait_ref( i.of_trait.as_ref()?, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 780d5271619..3115f5f464a 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; -use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; +use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; @@ -918,7 +918,7 @@ fn report_trait_method_mismatch<'tcx>( // When the `impl` receiver is an arbitrary self type, like `self: Box`, the // span points only at the type `Box, but we want to cover the whole // argument pattern and type. - let ImplItemKind::Fn(ref sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{impl_m:?} is not a method") }; + let (sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let span = tcx .hir() .body_param_names(body) @@ -1080,12 +1080,12 @@ fn extract_spans_for_error_reporting<'tcx>( ) -> (Span, Option) { let tcx = infcx.tcx; let mut impl_args = { - let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + let (sig, _) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }; let trait_args = trait_m.def_id.as_local().map(|def_id| { - let TraitItemKind::Fn(sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a TraitItemKind::Fn", trait_m) }; + let (sig, _) = tcx.hir().expect_trait_item(def_id).expect_fn(); sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }); @@ -1358,7 +1358,7 @@ fn compare_number_of_method_arguments<'tcx>( .def_id .as_local() .and_then(|def_id| { - let TraitItemKind::Fn(trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a method", impl_m) }; + let (trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).expect_fn(); let pos = trait_number_args.saturating_sub(1); trait_m_sig.decl.inputs.get(pos).map(|arg| { if pos == 0 { @@ -1370,7 +1370,7 @@ fn compare_number_of_method_arguments<'tcx>( }) .or(trait_item_span); - let ImplItemKind::Fn(impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + let (impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let pos = impl_number_args.saturating_sub(1); let impl_span = impl_m_sig .decl @@ -1506,7 +1506,7 @@ fn compare_synthetic_generics<'tcx>( let _: Option<_> = try { let impl_m = impl_m.def_id.as_local()?; let impl_m = tcx.hir().expect_impl_item(impl_m); - let hir::ImplItemKind::Fn(sig, _) = &impl_m.kind else { unreachable!() }; + let (sig, _) = impl_m.expect_fn(); let input_tys = sig.decl.inputs; struct Visitor(Option, hir::def_id::LocalDefId); @@ -1704,7 +1704,7 @@ pub(super) fn compare_impl_const_raw( ); // Locate the Span containing just the type of the offending impl - let ImplItemKind::Const(ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).kind else { bug!("{impl_const_item:?} is not a impl const") }; + let (ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).expect_const(); cause.span = ty.span; let mut diag = struct_span_err!( @@ -1717,7 +1717,7 @@ pub(super) fn compare_impl_const_raw( let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| { // Add a label to the Span containing just the type of the const - let TraitItemKind::Const(ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).kind else { bug!("{trait_const_item:?} is not a trait const") }; + let (ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).expect_const(); ty.span }); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index e15b7c89730..5b9b57da382 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -841,7 +841,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem _ => {} } if !trait_should_be_self.is_empty() { - if tcx.object_safety_violations(trait_def_id).is_empty() { + if tcx.check_is_object_safe(trait_def_id) { return; } let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect(); @@ -1072,8 +1072,8 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b // All field types must be well-formed. for field in &variant.fields { let field_id = field.did.expect_local(); - let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id) - else { bug!() }; + let hir::FieldDef { ty: hir_ty, .. } = + tcx.hir().get_by_def_id(field_id).expect_field(); let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did)); wfcx.register_wf_obligation( hir_ty.span, @@ -1106,8 +1106,8 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b { let last = idx == variant.fields.len() - 1; let field_id = field.did.expect_local(); - let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id) - else { bug!() }; + let hir::FieldDef { ty: hir_ty, .. } = + tcx.hir().get_by_def_id(field_id).expect_field(); let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did)); wfcx.register_bound( traits::ObligationCause::new( diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index ebb78213a63..5716be4f1a9 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -29,7 +29,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { if item.span.is_dummy() { continue; } - let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() }; + let (path, _) = item.expect_use(); let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { format!("unused import: `{}`", snippet) } else { diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 76668f7e9ac..6600e4216bd 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -56,7 +56,7 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { _ => {} } - let ItemKind::Impl(impl_) = tcx.hir().expect_item(impl_did).kind else { bug!("expected Drop impl item") }; + let impl_ = tcx.hir().expect_item(impl_did).expect_impl(); tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span }); } diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index d3b5778ba3b..bbde59c953a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -169,7 +169,7 @@ fn check_object_overlap<'tcx>( }); for component_def_id in component_def_ids { - if !tcx.is_object_safe(component_def_id) { + if !tcx.check_is_object_safe(component_def_id) { // Without the 'object_safe_for_dispatch' feature this is an error // which will be reported by wfcheck. Ignore it here. // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index fe6119dce87..c6b16171311 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -3,15 +3,13 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::Unsafety; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { - debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl)); let item = tcx.hir().expect_item(def_id); - let hir::ItemKind::Impl(impl_) = item.kind else { bug!() }; + let impl_ = item.expect_impl(); if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) { let trait_ref = trait_ref.subst_identity(); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f5a1e51c07b..cc7235a61c0 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1348,8 +1348,7 @@ fn suggest_impl_trait<'tcx>( fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option>> { let icx = ItemCtxt::new(tcx, def_id); - let item = tcx.hir().expect_item(def_id.expect_local()); - let hir::ItemKind::Impl(impl_) = item.kind else { bug!() }; + let impl_ = tcx.hir().expect_item(def_id.expect_local()).expect_impl(); impl_ .of_trait .as_ref() diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 1a0715a91cb..ade9c037c51 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1823,7 +1823,7 @@ fn add_impl_trait_explanation<'a>( .trait_ref() .and_then(|t| t.trait_def_id()) .map_or(false, |def_id| { - fcx.tcx.object_safety_violations(def_id).is_empty() + fcx.tcx.check_is_object_safe(def_id) }) }) } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 8046cc21cea..d1d4bb37528 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -882,6 +882,9 @@ fn lookup_with_diagnostics( ); } } + BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive => { + db.help("consider implementing the trait by hand, or remove the `packed` attribute"); + } } // Rewrap `db`, and pass control to the user. decorate(db) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index d6be4da0328..ba15dbd86cf 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -64,6 +64,7 @@ mod levels; mod lints; mod methods; +mod multiple_supertrait_upcastable; mod non_ascii_idents; mod non_fmt_panic; mod nonstandard_style; @@ -98,6 +99,7 @@ use internal::*; use let_underscore::*; use methods::*; +use multiple_supertrait_upcastable::*; use non_ascii_idents::*; use non_fmt_panic::NonPanicFmt; use nonstandard_style::*; @@ -232,6 +234,7 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { InvalidAtomicOrdering: InvalidAtomicOrdering, NamedAsmLabels: NamedAsmLabels, OpaqueHiddenInferredBound: OpaqueHiddenInferredBound, + MultipleSupertraitUpcastable: MultipleSupertraitUpcastable, ] ] ); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c997d8945d1..0c1019545f3 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -917,6 +917,13 @@ pub struct CStringPtr { pub unwrap: Span, } +// multiple_supertrait_upcastable.rs +#[derive(LintDiagnostic)] +#[diag(lint_multple_supertrait_upcastable)] +pub struct MultipleSupertraitUpcastable { + pub ident: Ident, +} + // non_ascii_idents.rs #[derive(LintDiagnostic)] #[diag(lint_identifier_non_ascii_char)] diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs new file mode 100644 index 00000000000..c2ed0e19f40 --- /dev/null +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -0,0 +1,60 @@ +use crate::{LateContext, LateLintPass, LintContext}; + +use rustc_hir as hir; +use rustc_span::sym; + +declare_lint! { + /// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple + /// supertraits. + /// + /// ### Example + /// + /// ```rust + /// trait A {} + /// trait B {} + /// + /// #[warn(multiple_supertrait_upcastable)] + /// trait C: A + B {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To support upcasting with multiple supertraits, we need to store multiple vtables and this + /// can result in extra space overhead, even if no code actually uses upcasting. + /// This lint allows users to identify when such scenarios occur and to decide whether the + /// additional overhead is justified. + pub MULTIPLE_SUPERTRAIT_UPCASTABLE, + Allow, + "detect when an object-safe trait has multiple supertraits", + @feature_gate = sym::multiple_supertrait_upcastable; +} + +declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]); + +impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { + let def_id = item.owner_id.to_def_id(); + // NOTE(nbdd0121): use `object_safety_violations` instead of `check_is_object_safe` because + // the latter will report `where_clause_object_safety` lint. + if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind + && cx.tcx.object_safety_violations(def_id).is_empty() + { + let direct_super_traits_iter = cx.tcx + .super_predicates_of(def_id) + .predicates + .into_iter() + .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred()); + if direct_super_traits_iter.count() > 1 { + cx.emit_spanned_lint( + MULTIPLE_SUPERTRAIT_UPCASTABLE, + cx.tcx.def_span(def_id), + crate::lints::MultipleSupertraitUpcastable { + ident: item.ident + }, + ); + } + } + } +} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b6481d70bc8..d731c10f46e 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3381,6 +3381,7 @@ REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, NAMED_ARGUMENTS_USED_POSITIONALLY, IMPLIED_BOUNDS_ENTAILMENT, + BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, ] } @@ -3531,9 +3532,15 @@ /// /// ### Explanation /// - /// Previously, there were very like checks being performed on `#[doc(..)]` - /// unlike the other attributes. It'll now catch all the issues that it - /// silently ignored previously. + /// Previously, incorrect usage of the `#[doc(..)]` attribute was not + /// being validated. Usually these should be rejected as a hard error, + /// but this lint was introduced to avoid breaking any existing + /// crates which included them. + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #82730] for more details. + /// + /// [issue #82730]: https://github.com/rust-lang/rust/issues/82730 pub INVALID_DOC_ATTRIBUTES, Warn, "detects invalid `#[doc(...)]` attributes", @@ -4109,3 +4116,35 @@ reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } + +declare_lint! { + /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field + /// (`[u8]`) is used in a `packed` struct that derives one or more built-in traits. + /// + /// ### Example + /// + /// ```rust + /// #[repr(packed)] + /// #[derive(Hash)] + /// struct FlexZeroSlice { + /// width: u8, + /// data: [u8], + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This was previously accepted but is being phased out, because fields in packed structs are + /// now required to implement `Copy` for `derive` to work. Byte slices are a temporary + /// exception because certain crates depended on them. + pub BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, + Warn, + "`[u8]` slice used in a packed struct with `derive`", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #107457 ", + reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, + }; + report_in_external_macro +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 7054d1e9f10..6efbf5ce9ee 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -521,6 +521,7 @@ pub enum BuiltinLintDiagnostics { /// Indicates if the named argument is used as a width/precision for formatting is_formatting_arg: bool, }, + ByteSliceInPackedStructWithDerive, } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 1e8d5f7eae8..7a05ee2ff37 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -318,16 +318,19 @@ pub fn mangle_name(human_readable_name: &str) -> String { base_n::encode(hash, base_n::CASE_INSENSITIVE) } - pub fn estimate_size(&mut self, tcx: TyCtxt<'tcx>) { + pub fn create_size_estimate(&mut self, tcx: TyCtxt<'tcx>) { // Estimate the size of a codegen unit as (approximately) the number of MIR // statements it corresponds to. self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum()); } #[inline] + /// Should only be called if [`create_size_estimate`] has previously been called. + /// + /// [`create_size_estimate`]: Self::create_size_estimate pub fn size_estimate(&self) -> usize { - // Should only be called if `estimate_size` has previously been called. - self.size_estimate.expect("estimate_size must be called before getting a size_estimate") + self.size_estimate + .expect("create_size_estimate must be called before getting a size_estimate") } pub fn modify_size_estimate(&mut self, delta: usize) { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 460a5147766..4cebe416354 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -183,6 +183,15 @@ separate_provide_extern } + query unsizing_params_for_adt(key: DefId) -> rustc_index::bit_set::BitSet + { + arena_cache + desc { |tcx| + "determining what parameters of `{}` can participate in unsizing", + tcx.def_path_str(key), + } + } + query analysis(key: ()) -> Result<(), ErrorGuaranteed> { eval_always desc { "running analysis passes on this crate" } @@ -361,6 +370,13 @@ desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) } } + /// Create a list-like THIR representation for debugging. + query thir_flat(key: ty::WithOptConstParam) -> String { + no_hash + arena_cache + desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) } + } + /// Set of all the `DefId`s in this crate that have MIR associated with /// them. This includes all the body owners, but also things like struct /// constructors. @@ -807,15 +823,6 @@ } } - /// HACK: when evaluated, this reports an "unsafe derive on repr(packed)" error. - /// - /// Unsafety checking is executed for each method separately, but we only want - /// to emit this error once per derive. As there are some impls with multiple - /// methods, we use a query for deduplication. - query unsafe_derive_on_repr_packed(key: LocalDefId) -> () { - desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) } - } - /// Returns the types assumed to be well formed while "inside" of the given item. /// /// Note that we've liberated the late bound regions of function signatures, so @@ -1274,6 +1281,9 @@ query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] { desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) } } + query check_is_object_safe(trait_id: DefId) -> bool { + desc { |tcx| "checking if trait `{}` is object safe", tcx.def_path_str(trait_id) } + } /// Gets the ParameterEnvironment for a given item; this environment /// will be in "user-facing" mode, meaning that it is suitable for diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 5f320708c84..6f2dac46753 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -29,6 +29,7 @@ use std::fmt; use std::ops::Index; +pub mod print; pub mod visit; macro_rules! thir_with_elements { diff --git a/compiler/rustc_middle/src/thir/print.rs b/compiler/rustc_middle/src/thir/print.rs new file mode 100644 index 00000000000..60b903e9906 --- /dev/null +++ b/compiler/rustc_middle/src/thir/print.rs @@ -0,0 +1,881 @@ +use crate::thir::*; +use crate::ty::{self, TyCtxt}; + +use std::fmt::{self, Write}; + +impl<'tcx> TyCtxt<'tcx> { + pub fn thir_tree_representation<'a>(self, thir: &'a Thir<'tcx>) -> String { + let mut printer = ThirPrinter::new(thir); + printer.print(); + printer.into_buffer() + } +} + +struct ThirPrinter<'a, 'tcx> { + thir: &'a Thir<'tcx>, + fmt: String, +} + +const INDENT: &str = " "; + +macro_rules! print_indented { + ($writer:ident, $s:expr, $indent_lvl:expr) => { + let indent = (0..$indent_lvl).map(|_| INDENT).collect::>().concat(); + writeln!($writer, "{}{}", indent, $s).expect("unable to write to ThirPrinter"); + }; +} + +impl<'a, 'tcx> Write for ThirPrinter<'a, 'tcx> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.fmt.push_str(s); + Ok(()) + } +} + +impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { + fn new(thir: &'a Thir<'tcx>) -> Self { + Self { thir, fmt: String::new() } + } + + fn print(&mut self) { + print_indented!(self, "params: [", 0); + for param in self.thir.params.iter() { + self.print_param(param, 1); + } + print_indented!(self, "]", 0); + + print_indented!(self, "body:", 0); + let expr = ExprId::from_usize(self.thir.exprs.len() - 1); + self.print_expr(expr, 1); + } + + fn into_buffer(self) -> String { + self.fmt + } + + fn print_param(&mut self, param: &Param<'tcx>, depth_lvl: usize) { + let Param { pat, ty, ty_span, self_kind, hir_id } = param; + + print_indented!(self, "Param {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("ty_span: {:?}", ty_span), depth_lvl + 1); + print_indented!(self, format!("self_kind: {:?}", self_kind), depth_lvl + 1); + print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 1); + + if let Some(pat) = pat { + print_indented!(self, "param: Some( ", depth_lvl + 1); + self.print_pat(pat, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } else { + print_indented!(self, "param: None", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_block(&mut self, block_id: BlockId, depth_lvl: usize) { + let Block { + targeted_by_break, + opt_destruction_scope, + span, + region_scope, + stmts, + expr, + safety_mode, + } = &self.thir.blocks[block_id]; + + print_indented!(self, "Block {", depth_lvl); + print_indented!(self, format!("targeted_by_break: {}", targeted_by_break), depth_lvl + 1); + print_indented!( + self, + format!("opt_destruction_scope: {:?}", opt_destruction_scope), + depth_lvl + 1 + ); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1); + print_indented!(self, format!("safety_mode: {:?}", safety_mode), depth_lvl + 1); + + if stmts.len() > 0 { + print_indented!(self, "stmts: [", depth_lvl + 1); + for stmt in stmts.iter() { + self.print_stmt(*stmt, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "stmts: []", depth_lvl + 1); + } + + if let Some(expr_id) = expr { + print_indented!(self, "expr:", depth_lvl + 1); + self.print_expr(*expr_id, depth_lvl + 2); + } else { + print_indented!(self, "expr: []", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_stmt(&mut self, stmt_id: StmtId, depth_lvl: usize) { + let Stmt { kind, opt_destruction_scope } = &self.thir.stmts[stmt_id]; + + print_indented!(self, "Stmt {", depth_lvl); + print_indented!( + self, + format!("opt_destruction_scope: {:?}", opt_destruction_scope), + depth_lvl + 1 + ); + + match kind { + StmtKind::Expr { scope, expr } => { + print_indented!(self, "kind: Expr {", depth_lvl + 1); + print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 2); + print_indented!(self, "expr:", depth_lvl + 2); + self.print_expr(*expr, depth_lvl + 3); + print_indented!(self, "}", depth_lvl + 1); + } + StmtKind::Let { + remainder_scope, + init_scope, + pattern, + initializer, + else_block, + lint_level, + } => { + print_indented!(self, "kind: Let {", depth_lvl + 1); + print_indented!( + self, + format!("remainder_scope: {:?}", remainder_scope), + depth_lvl + 2 + ); + print_indented!(self, format!("init_scope: {:?}", init_scope), depth_lvl + 2); + + print_indented!(self, "pattern: ", depth_lvl + 2); + self.print_pat(pattern, depth_lvl + 3); + print_indented!(self, ",", depth_lvl + 2); + + if let Some(init) = initializer { + print_indented!(self, "initializer: Some(", depth_lvl + 2); + self.print_expr(*init, depth_lvl + 3); + print_indented!(self, ")", depth_lvl + 2); + } else { + print_indented!(self, "initializer: None", depth_lvl + 2); + } + + if let Some(else_block) = else_block { + print_indented!(self, "else_block: Some(", depth_lvl + 2); + self.print_block(*else_block, depth_lvl + 3); + print_indented!(self, ")", depth_lvl + 2); + } else { + print_indented!(self, "else_block: None", depth_lvl + 2); + } + + print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_expr(&mut self, expr: ExprId, depth_lvl: usize) { + let Expr { ty, temp_lifetime, span, kind } = &self.thir[expr]; + print_indented!(self, "Expr {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("temp_lifetime: {:?}", temp_lifetime), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "kind: ", depth_lvl + 1); + self.print_expr_kind(kind, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + + fn print_expr_kind(&mut self, expr_kind: &ExprKind<'tcx>, depth_lvl: usize) { + use rustc_middle::thir::ExprKind::*; + + match expr_kind { + Scope { region_scope, value, lint_level } => { + print_indented!(self, "Scope {", depth_lvl); + print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1); + print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Box { value } => { + print_indented!(self, "Box {", depth_lvl); + self.print_expr(*value, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + If { if_then_scope, cond, then, else_opt } => { + print_indented!(self, "If {", depth_lvl); + print_indented!(self, format!("if_then_scope: {:?}", if_then_scope), depth_lvl + 1); + print_indented!(self, "cond:", depth_lvl + 1); + self.print_expr(*cond, depth_lvl + 2); + print_indented!(self, "then:", depth_lvl + 1); + self.print_expr(*then, depth_lvl + 2); + + if let Some(else_expr) = else_opt { + print_indented!(self, "else:", depth_lvl + 1); + self.print_expr(*else_expr, depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl); + } + Call { fun, args, ty, from_hir_call, fn_span } => { + print_indented!(self, "Call {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("from_hir_call: {}", from_hir_call), depth_lvl + 1); + print_indented!(self, format!("fn_span: {:?}", fn_span), depth_lvl + 1); + print_indented!(self, "fun:", depth_lvl + 1); + self.print_expr(*fun, depth_lvl + 2); + + if args.len() > 0 { + print_indented!(self, "args: [", depth_lvl + 1); + for arg in args.iter() { + self.print_expr(*arg, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "args: []", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + Deref { arg } => { + print_indented!(self, "Deref {", depth_lvl); + self.print_expr(*arg, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Binary { op, lhs, rhs } => { + print_indented!(self, "Binary {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + LogicalOp { op, lhs, rhs } => { + print_indented!(self, "LogicalOp {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Unary { op, arg } => { + print_indented!(self, "Unary {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "arg:", depth_lvl + 1); + self.print_expr(*arg, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Cast { source } => { + print_indented!(self, "Cast {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Use { source } => { + print_indented!(self, "Use {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + NeverToAny { source } => { + print_indented!(self, "NeverToAny {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Pointer { cast, source } => { + print_indented!(self, "Pointer {", depth_lvl); + print_indented!(self, format!("cast: {:?}", cast), depth_lvl + 1); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Loop { body } => { + print_indented!(self, "Loop (", depth_lvl); + print_indented!(self, "body:", depth_lvl + 1); + self.print_expr(*body, depth_lvl + 2); + print_indented!(self, ")", depth_lvl); + } + Let { expr, pat } => { + print_indented!(self, "Let {", depth_lvl); + print_indented!(self, "expr:", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, format!("pat: {:?}", pat), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Match { scrutinee, arms } => { + print_indented!(self, "Match {", depth_lvl); + print_indented!(self, "scrutinee:", depth_lvl + 1); + self.print_expr(*scrutinee, depth_lvl + 2); + + print_indented!(self, "arms: [", depth_lvl + 1); + for arm_id in arms.iter() { + self.print_arm(*arm_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Block { block } => self.print_block(*block, depth_lvl), + Assign { lhs, rhs } => { + print_indented!(self, "Assign {", depth_lvl); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + AssignOp { op, lhs, rhs } => { + print_indented!(self, "AssignOp {", depth_lvl); + print_indented!(self, format!("op: {:?}", op), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "rhs:", depth_lvl + 1); + self.print_expr(*rhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Field { lhs, variant_index, name } => { + print_indented!(self, "Field {", depth_lvl); + print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 1); + print_indented!(self, format!("name: {:?}", name), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Index { lhs, index } => { + print_indented!(self, "Index {", depth_lvl); + print_indented!(self, format!("index: {:?}", index), depth_lvl + 1); + print_indented!(self, "lhs:", depth_lvl + 1); + self.print_expr(*lhs, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + VarRef { id } => { + print_indented!(self, "VarRef {", depth_lvl); + print_indented!(self, format!("id: {:?}", id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + UpvarRef { closure_def_id, var_hir_id } => { + print_indented!(self, "UpvarRef {", depth_lvl); + print_indented!( + self, + format!("closure_def_id: {:?}", closure_def_id), + depth_lvl + 1 + ); + print_indented!(self, format!("var_hir_id: {:?}", var_hir_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Borrow { borrow_kind, arg } => { + print_indented!(self, "Borrow (", depth_lvl); + print_indented!(self, format!("borrow_kind: {:?}", borrow_kind), depth_lvl + 1); + print_indented!(self, "arg:", depth_lvl + 1); + self.print_expr(*arg, depth_lvl + 2); + print_indented!(self, ")", depth_lvl); + } + AddressOf { mutability, arg } => { + print_indented!(self, "AddressOf {", depth_lvl); + print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 1); + print_indented!(self, "arg:", depth_lvl + 1); + self.print_expr(*arg, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Break { label, value } => { + print_indented!(self, "Break (", depth_lvl); + print_indented!(self, format!("label: {:?}", label), depth_lvl + 1); + + if let Some(value) = value { + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + } + + print_indented!(self, ")", depth_lvl); + } + Continue { label } => { + print_indented!(self, "Continue {", depth_lvl); + print_indented!(self, format!("label: {:?}", label), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Return { value } => { + print_indented!(self, "Return {", depth_lvl); + print_indented!(self, "value:", depth_lvl + 1); + + if let Some(value) = value { + self.print_expr(*value, depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl); + } + ConstBlock { did, substs } => { + print_indented!(self, "ConstBlock {", depth_lvl); + print_indented!(self, format!("did: {:?}", did), depth_lvl + 1); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Repeat { value, count } => { + print_indented!(self, "Repeat {", depth_lvl); + print_indented!(self, format!("count: {:?}", count), depth_lvl + 1); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Array { fields } => { + print_indented!(self, "Array {", depth_lvl); + print_indented!(self, "fields: [", depth_lvl + 1); + for field_id in fields.iter() { + self.print_expr(*field_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Tuple { fields } => { + print_indented!(self, "Tuple {", depth_lvl); + print_indented!(self, "fields: [", depth_lvl + 1); + for field_id in fields.iter() { + self.print_expr(*field_id, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Adt(adt_expr) => { + print_indented!(self, "Adt {", depth_lvl); + self.print_adt_expr(&**adt_expr, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + PlaceTypeAscription { source, user_ty } => { + print_indented!(self, "PlaceTypeAscription {", depth_lvl); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + ValueTypeAscription { source, user_ty } => { + print_indented!(self, "ValueTypeAscription {", depth_lvl); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Closure(closure_expr) => { + print_indented!(self, "Closure {", depth_lvl); + print_indented!(self, "closure_expr:", depth_lvl + 1); + self.print_closure_expr(&**closure_expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + Literal { lit, neg } => { + print_indented!( + self, + format!("Literal( lit: {:?}, neg: {:?})\n", lit, neg), + depth_lvl + ); + } + NonHirLiteral { lit, user_ty } => { + print_indented!(self, "NonHirLiteral {", depth_lvl); + print_indented!(self, format!("lit: {:?}", lit), depth_lvl + 1); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + ZstLiteral { user_ty } => { + print_indented!(self, format!("ZstLiteral(user_ty: {:?})", user_ty), depth_lvl); + } + NamedConst { def_id, substs, user_ty } => { + print_indented!(self, "NamedConst {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, format!("user_ty: {:?}", user_ty), depth_lvl + 1); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + ConstParam { param, def_id } => { + print_indented!(self, "ConstParam {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, format!("param: {:?}", param), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + StaticRef { alloc_id, ty, def_id } => { + print_indented!(self, "StaticRef {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("alloc_id: {:?}", alloc_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + InlineAsm(expr) => { + print_indented!(self, "InlineAsm {", depth_lvl); + print_indented!(self, "expr:", depth_lvl + 1); + self.print_inline_asm_expr(&**expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + ThreadLocalRef(def_id) => { + print_indented!(self, "ThreadLocalRef {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + Yield { value } => { + print_indented!(self, "Yield {", depth_lvl); + print_indented!(self, "value:", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + } + } + + fn print_adt_expr(&mut self, adt_expr: &AdtExpr<'tcx>, depth_lvl: usize) { + print_indented!(self, "adt_def:", depth_lvl); + self.print_adt_def(adt_expr.adt_def, depth_lvl + 1); + print_indented!( + self, + format!("variant_index: {:?}", adt_expr.variant_index), + depth_lvl + 1 + ); + print_indented!(self, format!("substs: {:?}", adt_expr.substs), depth_lvl + 1); + print_indented!(self, format!("user_ty: {:?}", adt_expr.user_ty), depth_lvl + 1); + + for (i, field_expr) in adt_expr.fields.iter().enumerate() { + print_indented!(self, format!("field {}:", i), depth_lvl + 1); + self.print_expr(field_expr.expr, depth_lvl + 2); + } + + if let Some(ref base) = adt_expr.base { + print_indented!(self, "base:", depth_lvl + 1); + self.print_fru_info(base, depth_lvl + 2); + } else { + print_indented!(self, "base: None", depth_lvl + 1); + } + } + + fn print_adt_def(&mut self, adt_def: ty::AdtDef<'tcx>, depth_lvl: usize) { + print_indented!(self, "AdtDef {", depth_lvl); + print_indented!(self, format!("did: {:?}", adt_def.did()), depth_lvl + 1); + print_indented!(self, format!("variants: {:?}", adt_def.variants()), depth_lvl + 1); + print_indented!(self, format!("flags: {:?}", adt_def.flags()), depth_lvl + 1); + print_indented!(self, format!("repr: {:?}", adt_def.repr()), depth_lvl + 1); + } + + fn print_fru_info(&mut self, fru_info: &FruInfo<'tcx>, depth_lvl: usize) { + print_indented!(self, "FruInfo {", depth_lvl); + print_indented!(self, "base: ", depth_lvl + 1); + self.print_expr(fru_info.base, depth_lvl + 2); + print_indented!(self, "field_types: [", depth_lvl + 1); + for ty in fru_info.field_types.iter() { + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); + } + print_indented!(self, "}", depth_lvl); + } + + fn print_arm(&mut self, arm_id: ArmId, depth_lvl: usize) { + print_indented!(self, "Arm {", depth_lvl); + + let arm = &self.thir.arms[arm_id]; + let Arm { pattern, guard, body, lint_level, scope, span } = arm; + + print_indented!(self, "pattern: ", depth_lvl + 1); + self.print_pat(pattern, depth_lvl + 2); + + if let Some(guard) = guard { + print_indented!(self, "guard: ", depth_lvl + 1); + self.print_guard(guard, depth_lvl + 2); + } else { + print_indented!(self, "guard: None", depth_lvl + 1); + } + + print_indented!(self, "body: ", depth_lvl + 1); + self.print_expr(*body, depth_lvl + 2); + print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 1); + print_indented!(self, format!("scope: {:?}", scope), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + + fn print_pat(&mut self, pat: &Box>, depth_lvl: usize) { + let Pat { ty, span, kind } = &**pat; + + print_indented!(self, "Pat: {", depth_lvl); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + self.print_pat_kind(kind, depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } + + fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) { + print_indented!(self, "kind: PatKind {", depth_lvl); + + match pat_kind { + PatKind::Wild => { + print_indented!(self, "Wild", depth_lvl + 1); + } + PatKind::AscribeUserType { ascription, subpattern } => { + print_indented!(self, "AscribeUserType: {", depth_lvl + 1); + print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2); + print_indented!(self, "subpattern: ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 3); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Binding { mutability, name, mode, var, ty, subpattern, is_primary } => { + print_indented!(self, "Binding {", depth_lvl + 1); + print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 2); + print_indented!(self, format!("name: {:?}", name), depth_lvl + 2); + print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2); + print_indented!(self, format!("var: {:?}", var), depth_lvl + 2); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); + print_indented!(self, format!("is_primary: {:?}", is_primary), depth_lvl + 2); + + if let Some(subpattern) = subpattern { + print_indented!(self, "subpattern: Some( ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 3); + print_indented!(self, ")", depth_lvl + 2); + } else { + print_indented!(self, "subpattern: None", depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Variant { adt_def, substs, variant_index, subpatterns } => { + print_indented!(self, "Variant {", depth_lvl + 1); + print_indented!(self, "adt_def: ", depth_lvl + 2); + self.print_adt_def(*adt_def, depth_lvl + 3); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 2); + print_indented!(self, format!("variant_index: {:?}", variant_index), depth_lvl + 2); + + if subpatterns.len() > 0 { + print_indented!(self, "subpatterns: [", depth_lvl + 2); + for field_pat in subpatterns.iter() { + self.print_pat(&field_pat.pattern, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + } else { + print_indented!(self, "subpatterns: []", depth_lvl + 2); + } + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Leaf { subpatterns } => { + print_indented!(self, "Leaf { ", depth_lvl + 1); + print_indented!(self, "subpatterns: [", depth_lvl + 2); + for field_pat in subpatterns.iter() { + self.print_pat(&field_pat.pattern, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Deref { subpattern } => { + print_indented!(self, "Deref { ", depth_lvl + 1); + print_indented!(self, "subpattern: ", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Constant { value } => { + print_indented!(self, "Constant {", depth_lvl + 1); + print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Range(pat_range) => { + print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1); + } + PatKind::Slice { prefix, slice, suffix } => { + print_indented!(self, "Slice {", depth_lvl + 1); + + print_indented!(self, "prefix: [", depth_lvl + 2); + for prefix_pat in prefix.iter() { + self.print_pat(prefix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + if let Some(slice) = slice { + print_indented!(self, "slice: ", depth_lvl + 2); + self.print_pat(slice, depth_lvl + 3); + } + + print_indented!(self, "suffix: [", depth_lvl + 2); + for suffix_pat in suffix.iter() { + self.print_pat(suffix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Array { prefix, slice, suffix } => { + print_indented!(self, "Array {", depth_lvl + 1); + + print_indented!(self, "prefix: [", depth_lvl + 2); + for prefix_pat in prefix.iter() { + self.print_pat(prefix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + if let Some(slice) = slice { + print_indented!(self, "slice: ", depth_lvl + 2); + self.print_pat(slice, depth_lvl + 3); + } + + print_indented!(self, "suffix: [", depth_lvl + 2); + for suffix_pat in suffix.iter() { + self.print_pat(suffix_pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::Or { pats } => { + print_indented!(self, "Or {", depth_lvl + 1); + print_indented!(self, "pats: [", depth_lvl + 2); + for pat in pats.iter() { + self.print_pat(pat, depth_lvl + 3); + } + print_indented!(self, "]", depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_guard(&mut self, guard: &Guard<'tcx>, depth_lvl: usize) { + print_indented!(self, "Guard {", depth_lvl); + + match guard { + Guard::If(expr_id) => { + print_indented!(self, "If (", depth_lvl + 1); + self.print_expr(*expr_id, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } + Guard::IfLet(pat, expr_id) => { + print_indented!(self, "IfLet (", depth_lvl + 1); + self.print_pat(pat, depth_lvl + 2); + print_indented!(self, ",", depth_lvl + 1); + self.print_expr(*expr_id, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_closure_expr(&mut self, expr: &ClosureExpr<'tcx>, depth_lvl: usize) { + let ClosureExpr { closure_id, substs, upvars, movability, fake_reads } = expr; + + print_indented!(self, "ClosureExpr {", depth_lvl); + print_indented!(self, format!("closure_id: {:?}", closure_id), depth_lvl + 1); + print_indented!(self, format!("substs: {:?}", substs), depth_lvl + 1); + + if upvars.len() > 0 { + print_indented!(self, "upvars: [", depth_lvl + 1); + for upvar in upvars.iter() { + self.print_expr(*upvar, depth_lvl + 2); + print_indented!(self, ",", depth_lvl + 1); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "upvars: []", depth_lvl + 1); + } + + print_indented!(self, format!("movability: {:?}", movability), depth_lvl + 1); + + if fake_reads.len() > 0 { + print_indented!(self, "fake_reads: [", depth_lvl + 1); + for (fake_read_expr, cause, hir_id) in fake_reads.iter() { + print_indented!(self, "(", depth_lvl + 2); + self.print_expr(*fake_read_expr, depth_lvl + 3); + print_indented!(self, ",", depth_lvl + 2); + print_indented!(self, format!("cause: {:?}", cause), depth_lvl + 3); + print_indented!(self, ",", depth_lvl + 2); + print_indented!(self, format!("hir_id: {:?}", hir_id), depth_lvl + 3); + print_indented!(self, "),", depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + } else { + print_indented!(self, "fake_reads: []", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl); + } + + fn print_inline_asm_expr(&mut self, expr: &InlineAsmExpr<'tcx>, depth_lvl: usize) { + let InlineAsmExpr { template, operands, options, line_spans } = expr; + + print_indented!(self, "InlineAsmExpr {", depth_lvl); + + print_indented!(self, "template: [", depth_lvl + 1); + for template_piece in template.iter() { + print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + + print_indented!(self, "operands: [", depth_lvl + 1); + for operand in operands.iter() { + self.print_inline_operand(operand, depth_lvl + 2); + } + print_indented!(self, "]", depth_lvl + 1); + + print_indented!(self, format!("options: {:?}", options), depth_lvl + 1); + print_indented!(self, format!("line_spans: {:?}", line_spans), depth_lvl + 1); + } + + fn print_inline_operand(&mut self, operand: &InlineAsmOperand<'tcx>, depth_lvl: usize) { + match operand { + InlineAsmOperand::In { reg, expr } => { + print_indented!(self, "InlineAsmOperand::In {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, "expr: ", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::Out { reg, late, expr } => { + print_indented!(self, "InlineAsmOperand::Out {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, format!("late: {:?}", late), depth_lvl + 1); + + if let Some(out) = expr { + print_indented!(self, "place: Some( ", depth_lvl + 1); + self.print_expr(*out, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } else { + print_indented!(self, "place: None", depth_lvl + 1); + } + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::InOut { reg, late, expr } => { + print_indented!(self, "InlineAsmOperand::InOut {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, format!("late: {:?}", late), depth_lvl + 1); + print_indented!(self, "expr: ", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => { + print_indented!(self, "InlineAsmOperand::SplitInOut {", depth_lvl); + print_indented!(self, format!("reg: {:?}", reg), depth_lvl + 1); + print_indented!(self, format!("late: {:?}", late), depth_lvl + 1); + print_indented!(self, "in_expr: ", depth_lvl + 1); + self.print_expr(*in_expr, depth_lvl + 2); + + if let Some(out_expr) = out_expr { + print_indented!(self, "out_expr: Some( ", depth_lvl + 1); + self.print_expr(*out_expr, depth_lvl + 2); + print_indented!(self, ")", depth_lvl + 1); + } else { + print_indented!(self, "out_expr: None", depth_lvl + 1); + } + + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::Const { value, span } => { + print_indented!(self, "InlineAsmOperand::Const {", depth_lvl); + print_indented!(self, format!("value: {:?}", value), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::SymFn { value, span } => { + print_indented!(self, "InlineAsmOperand::SymFn {", depth_lvl); + print_indented!(self, format!("value: {:?}", *value), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } + InlineAsmOperand::SymStatic { def_id } => { + print_indented!(self, "InlineAsmOperand::SymStatic {", depth_lvl); + print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } + } + } +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 7001f81aa77..25c6777a14c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2458,10 +2458,6 @@ pub fn should_collapse_debuginfo(self, span: Span) -> bool { } } - pub fn is_object_safe(self, key: DefId) -> bool { - self.object_safety_violations(key).is_empty() - } - #[inline] pub fn is_const_fn_raw(self, def_id: DefId) -> bool { matches!( diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index f85831b4fc6..1655e224ddb 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -439,6 +439,10 @@ fn construct_fn<'tcx>( let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did); let generator_kind = tcx.generator_kind(fn_def.did); + // The representation of thir for `-Zunpretty=thir-tree` relies on + // the entry expression being the last element of `thir.exprs`. + assert_eq!(expr.as_usize(), thir.exprs.len() - 1); + // Figure out what primary body this item has. let body_id = tcx.hir().body_owned_by(fn_def.did); let span_with_body = tcx.hir().span_with_body(fn_id); diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index a428180a4fa..94dae36154c 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -34,4 +34,5 @@ pub fn provide(providers: &mut Providers) { providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg; providers.thir_body = thir::cx::thir_body; providers.thir_tree = thir::cx::thir_tree; + providers.thir_flat = thir::cx::thir_flat; } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index a355e1bdab5..10df4b22952 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -53,6 +53,16 @@ pub(crate) fn thir_body( } pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam) -> String { + match thir_body(tcx, owner_def) { + Ok((thir, _)) => { + let thir = thir.steal(); + tcx.thir_tree_representation(&thir) + } + Err(_) => "error".into(), + } +} + +pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam) -> String { match thir_body(tcx, owner_def) { Ok((thir, _)) => format!("{:#?}", thir.steal()), Err(_) => "error".into(), diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 51abcf51189..3e7571aa7a2 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -1,17 +1,11 @@ -use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::UNALIGNED_REFERENCES; use crate::util; use crate::MirLint; -pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { unsafe_derive_on_repr_packed, ..*providers }; -} - pub struct CheckPackedRef; impl<'tcx> MirLint<'tcx> for CheckPackedRef { @@ -30,32 +24,6 @@ struct PackedRefChecker<'a, 'tcx> { source_info: SourceInfo, } -fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - - // FIXME: when we make this a hard error, this should have its - // own error code. - - let extra = if tcx.generics_of(def_id).own_requires_monomorphization() { - "with type or const parameters" - } else { - "that does not derive `Copy`" - }; - let message = format!( - "`{}` can't be derived on this `#[repr(packed)]` struct {}", - tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")), - extra - ); - - tcx.struct_span_lint_hir( - UNALIGNED_REFERENCES, - lint_hir_id, - tcx.def_span(def_id), - message, - |lint| lint, - ); -} - impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { // Make sure we know where in the MIR we are. @@ -73,14 +41,13 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: if context.is_borrow() { if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { let def_id = self.body.source.instance.def_id(); - if let Some(impl_def_id) = self - .tcx - .impl_of_method(def_id) - .filter(|&def_id| self.tcx.is_builtin_derive(def_id)) + if let Some(impl_def_id) = self.tcx.impl_of_method(def_id) + && self.tcx.is_builtin_derive(impl_def_id) { - // If a method is defined in the local crate, - // the impl containing that method should also be. - self.tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local()); + // If we ever reach here it means that the generated derive + // code is somehow doing an unaligned reference, which it + // shouldn't do. + unreachable!(); } else { let source_info = self.source_info; let lint_root = self.body.source_scopes[source_info.scope] diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs new file mode 100644 index 00000000000..182b3015dd7 --- /dev/null +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -0,0 +1,178 @@ +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::visit::*; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::impls::borrowed_locals; + +use crate::ssa::SsaLocals; +use crate::MirPass; + +/// Unify locals that copy each other. +/// +/// We consider patterns of the form +/// _a = rvalue +/// _b = move? _a +/// _c = move? _a +/// _d = move? _c +/// where each of the locals is only assigned once. +/// +/// We want to replace all those locals by `_a`, either copied or moved. +pub struct CopyProp; + +impl<'tcx> MirPass<'tcx> for CopyProp { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 4 + } + + #[instrument(level = "trace", skip(self, tcx, body))] + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + debug!(def_id = ?body.source.def_id()); + propagate_ssa(tcx, body); + } +} + +fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let borrowed_locals = borrowed_locals(body); + let ssa = SsaLocals::new(tcx, param_env, body, &borrowed_locals); + + let fully_moved = fully_moved_locals(&ssa, body); + debug!(?fully_moved); + + let mut storage_to_remove = BitSet::new_empty(fully_moved.domain_size()); + for (local, &head) in ssa.copy_classes().iter_enumerated() { + if local != head { + storage_to_remove.insert(head); + } + } + + let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h); + + Replacer { + tcx, + copy_classes: &ssa.copy_classes(), + fully_moved, + borrowed_locals, + storage_to_remove, + } + .visit_body_preserves_cfg(body); + + if any_replacement { + crate::simplify::remove_unused_definitions(body); + } +} + +/// `SsaLocals` computed equivalence classes between locals considering copy/move assignments. +/// +/// This function also returns whether all the `move?` in the pattern are `move` and not copies. +/// A local which is in the bitset can be replaced by `move _a`. Otherwise, it must be +/// replaced by `copy _a`, as we cannot move multiple times from `_a`. +/// +/// If an operand copies `_c`, it must happen before the assignment `_d = _c`, otherwise it is UB. +/// This means that replacing it by a copy of `_a` if ok, since this copy happens before `_c` is +/// moved, and therefore that `_d` is moved. +#[instrument(level = "trace", skip(ssa, body))] +fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet { + let mut fully_moved = BitSet::new_filled(body.local_decls.len()); + + for (_, rvalue) in ssa.assignments(body) { + let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place)) + = rvalue + else { continue }; + + let Some(rhs) = place.as_local() else { continue }; + if !ssa.is_ssa(rhs) { + continue; + } + + if let Rvalue::Use(Operand::Copy(_)) | Rvalue::CopyForDeref(_) = rvalue { + fully_moved.remove(rhs); + } + } + + ssa.meet_copy_equivalence(&mut fully_moved); + + fully_moved +} + +/// Utility to help performing subtitution of `*pattern` by `target`. +struct Replacer<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + fully_moved: BitSet, + storage_to_remove: BitSet, + borrowed_locals: BitSet, + copy_classes: &'a IndexVec, +} + +impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, local: &mut Local, ctxt: PlaceContext, _: Location) { + let new_local = self.copy_classes[*local]; + match ctxt { + // Do not modify the local in storage statements. + PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => {} + // The local should have been marked as non-SSA. + PlaceContext::MutatingUse(_) => assert_eq!(*local, new_local), + // We access the value. + _ => *local = new_local, + } + } + + fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) { + if let Some(new_projection) = self.process_projection(&place.projection, loc) { + place.projection = self.tcx().intern_place_elems(&new_projection); + } + + let observes_address = match ctxt { + PlaceContext::NonMutatingUse( + NonMutatingUseContext::SharedBorrow + | NonMutatingUseContext::ShallowBorrow + | NonMutatingUseContext::UniqueBorrow + | NonMutatingUseContext::AddressOf, + ) => true, + // For debuginfo, merging locals is ok. + PlaceContext::NonUse(NonUseContext::VarDebugInfo) => { + self.borrowed_locals.contains(place.local) + } + _ => false, + }; + if observes_address && !place.is_indirect() { + // We observe the address of `place.local`. Do not replace it. + } else { + self.visit_local( + &mut place.local, + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), + loc, + ) + } + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { + if let Operand::Move(place) = *operand + && let Some(local) = place.as_local() + && !self.fully_moved.contains(local) + { + *operand = Operand::Copy(place); + } + self.super_operand(operand, loc); + } + + fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) { + if let StatementKind::StorageDead(l) = stmt.kind + && self.storage_to_remove.contains(l) + { + stmt.make_nop(); + } else if let StatementKind::Assign(box (ref place, ref mut rvalue)) = stmt.kind + && place.as_local().is_some() + { + // Do not replace assignments. + self.visit_rvalue(rvalue, loc) + } else { + self.super_statement(stmt, loc); + } + } +} diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 20ffb0ab334..5c5baa68e58 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -328,7 +328,8 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio match &statement.kind { StatementKind::Assign(box (dest, rvalue)) => { match rvalue { - Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => { + Rvalue::CopyForDeref(place) + | Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => { // These might've been turned into self-assignments by the replacement // (this includes the original statement we wanted to eliminate). if dest == place { @@ -755,7 +756,7 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { if let StatementKind::Assign(box ( lhs, - Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)), + Rvalue::CopyForDeref(rhs) | Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)), )) = &statement.kind { let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index efeefdcaabb..6815289776e 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -55,6 +55,7 @@ mod const_goto; mod const_prop; mod const_prop_lint; +mod copy_prop; mod coverage; mod ctfe_limit; mod dataflow_const_prop; @@ -88,6 +89,7 @@ mod reveal_all; mod separate_const_switch; mod shim; +mod ssa; // This pass is public to allow external drivers to perform MIR cleanup pub mod simplify; mod simplify_branches; @@ -103,7 +105,6 @@ pub fn provide(providers: &mut Providers) { check_unsafety::provide(providers); - check_packed_ref::provide(providers); coverage::query::provide(providers); ffi_unwind_calls::provide(providers); shim::provide(providers); @@ -550,13 +551,13 @@ fn o1(x: T) -> WithMinOptLevel { &[ &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode. &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first - &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering &unreachable_prop::UnreachablePropagation, &uninhabited_enum_branching::UninhabitedEnumBranching, &o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")), &inline::Inline, &remove_storage_markers::RemoveStorageMarkers, &remove_zsts::RemoveZsts, + &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering &const_goto::ConstGoto, &remove_unneeded_drops::RemoveUnneededDrops, &sroa::ScalarReplacementOfAggregates, @@ -566,6 +567,7 @@ fn o1(x: T) -> WithMinOptLevel { &instcombine::InstCombine, &separate_const_switch::SeparateConstSwitch, &simplify::SimplifyLocals::new("before-const-prop"), + ©_prop::CopyProp, // // FIXME(#70073): This pass is responsible for both optimization as well as some lints. &const_prop::ConstProp, diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 1708b287e56..b36c8a0bd53 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -1,288 +1,104 @@ //! This pass eliminates casting of arrays into slices when their length //! is taken using `.len()` method. Handy to preserve information in MIR for const prop +use crate::ssa::SsaLocals; use crate::MirPass; -use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::intern::Interned; -use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; +use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::{self, ReErased, Region, TyCtxt}; - -const MAX_NUM_BLOCKS: usize = 800; -const MAX_NUM_LOCALS: usize = 3000; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_mir_dataflow::impls::borrowed_locals; pub struct NormalizeArrayLen; impl<'tcx> MirPass<'tcx> for NormalizeArrayLen { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - // See #105929 - sess.mir_opt_level() >= 4 && sess.opts.unstable_opts.unsound_mir_opts + sess.mir_opt_level() >= 3 } + #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // early returns for edge cases of highly unrolled functions - if body.basic_blocks.len() > MAX_NUM_BLOCKS { - return; - } - if body.local_decls.len() > MAX_NUM_LOCALS { - return; - } + debug!(def_id = ?body.source.def_id()); normalize_array_len_calls(tcx, body) } } -pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // We don't ever touch terminators, so no need to invalidate the CFG cache - let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); - let local_decls = &mut body.local_decls; +fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let borrowed_locals = borrowed_locals(body); + let ssa = SsaLocals::new(tcx, param_env, body, &borrowed_locals); - // do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]` - let mut interesting_locals = BitSet::new_empty(local_decls.len()); - for (local, decl) in local_decls.iter_enumerated() { - match decl.ty.kind() { - ty::Array(..) => { - interesting_locals.insert(local); - } - ty::Ref(.., ty, Mutability::Not) => match ty.kind() { - ty::Array(..) => { - interesting_locals.insert(local); - } - _ => {} - }, - _ => {} - } - } - if interesting_locals.is_empty() { - // we have found nothing to analyze - return; - } - let num_intesting_locals = interesting_locals.count(); - let mut state = FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default()); - let mut patches_scratchpad = - FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default()); - let mut replacements_scratchpad = - FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default()); - for block in basic_blocks { - // make length calls for arrays [T; N] not to decay into length calls for &[T] - // that forbids constant propagation - normalize_array_len_call( - tcx, - block, - local_decls, - &interesting_locals, - &mut state, - &mut patches_scratchpad, - &mut replacements_scratchpad, - ); - state.clear(); - patches_scratchpad.clear(); - replacements_scratchpad.clear(); - } -} + let slice_lengths = compute_slice_length(tcx, &ssa, body); + debug!(?slice_lengths); -struct Patcher<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - patches_scratchpad: &'a FxIndexMap, - replacements_scratchpad: &'a mut FxIndexMap, - local_decls: &'a mut IndexVec>, - statement_idx: usize, + Replacer { tcx, slice_lengths }.visit_body_preserves_cfg(body); } -impl<'tcx> Patcher<'_, 'tcx> { - fn patch_expand_statement( - &mut self, - statement: &mut Statement<'tcx>, - ) -> Option>> { - let idx = self.statement_idx; - if let Some(len_statemnt_idx) = self.patches_scratchpad.get(&idx).copied() { - let mut statements = Vec::with_capacity(2); - - // we are at statement that performs a cast. The only sound way is - // to create another local that performs a similar copy without a cast and then - // use this copy in the Len operation - - match &statement.kind { - StatementKind::Assign(box ( - .., - Rvalue::Cast( - CastKind::Pointer(ty::adjustment::PointerCast::Unsize), - operand, - _, - ), - )) => { - match operand { - Operand::Copy(place) | Operand::Move(place) => { - // create new local - let ty = operand.ty(self.local_decls, self.tcx); - let local_decl = LocalDecl::with_source_info(ty, statement.source_info); - let local = self.local_decls.push(local_decl); - // make it live - let mut make_live_statement = statement.clone(); - make_live_statement.kind = StatementKind::StorageLive(local); - statements.push(make_live_statement); - // copy into it - - let operand = Operand::Copy(*place); - let mut make_copy_statement = statement.clone(); - let assign_to = Place::from(local); - let rvalue = Rvalue::Use(operand); - make_copy_statement.kind = - StatementKind::Assign(Box::new((assign_to, rvalue))); - statements.push(make_copy_statement); - - // to reorder we have to copy and make NOP - statements.push(statement.clone()); - statement.make_nop(); - - self.replacements_scratchpad.insert(len_statemnt_idx, local); - } - _ => { - unreachable!("it's a bug in the implementation") - } - } - } - _ => { - unreachable!("it's a bug in the implementation") +fn compute_slice_length<'tcx>( + tcx: TyCtxt<'tcx>, + ssa: &SsaLocals, + body: &Body<'tcx>, +) -> IndexVec>> { + let mut slice_lengths = IndexVec::from_elem(None, &body.local_decls); + + for (local, rvalue) in ssa.assignments(body) { + match rvalue { + Rvalue::Cast( + CastKind::Pointer(ty::adjustment::PointerCast::Unsize), + operand, + cast_ty, + ) => { + let operand_ty = operand.ty(body, tcx); + debug!(?operand_ty); + if let Some(operand_ty) = operand_ty.builtin_deref(true) + && let ty::Array(_, len) = operand_ty.ty.kind() + && let Some(cast_ty) = cast_ty.builtin_deref(true) + && let ty::Slice(..) = cast_ty.ty.kind() + { + slice_lengths[local] = Some(*len); } } - - self.statement_idx += 1; - - Some(statements.into_iter()) - } else if let Some(local) = self.replacements_scratchpad.get(&idx).copied() { - let mut statements = Vec::with_capacity(2); - - match &statement.kind { - StatementKind::Assign(box (into, Rvalue::Len(place))) => { - let add_deref = if let Some(..) = place.as_local() { - false - } else if let Some(..) = place.local_or_deref_local() { - true - } else { - unreachable!("it's a bug in the implementation") - }; - // replace len statement - let mut len_statement = statement.clone(); - let mut place = Place::from(local); - if add_deref { - place = self.tcx.mk_place_deref(place); - } - len_statement.kind = - StatementKind::Assign(Box::new((*into, Rvalue::Len(place)))); - statements.push(len_statement); - - // make temporary dead - let mut make_dead_statement = statement.clone(); - make_dead_statement.kind = StatementKind::StorageDead(local); - statements.push(make_dead_statement); - - // make original statement NOP - statement.make_nop(); + // The length information is stored in the fat pointer, so we treat `operand` as a value. + Rvalue::Use(operand) => { + if let Some(rhs) = operand.place() && let Some(rhs) = rhs.as_local() { + slice_lengths[local] = slice_lengths[rhs]; } - _ => { - unreachable!("it's a bug in the implementation") + } + // The length information is stored in the fat pointer. + // Reborrowing copies length information from one pointer to the other. + Rvalue::Ref(_, _, rhs) | Rvalue::AddressOf(_, rhs) => { + if let [PlaceElem::Deref] = rhs.projection[..] { + slice_lengths[local] = slice_lengths[rhs.local]; } } - - self.statement_idx += 1; - - Some(statements.into_iter()) - } else { - self.statement_idx += 1; - None + _ => {} } } + + slice_lengths } -fn normalize_array_len_call<'tcx>( +struct Replacer<'tcx> { tcx: TyCtxt<'tcx>, - block: &mut BasicBlockData<'tcx>, - local_decls: &mut IndexVec>, - interesting_locals: &BitSet, - state: &mut FxIndexMap, - patches_scratchpad: &mut FxIndexMap, - replacements_scratchpad: &mut FxIndexMap, -) { - for (statement_idx, statement) in block.statements.iter_mut().enumerate() { - match &mut statement.kind { - StatementKind::Assign(box (place, rvalue)) => { - match rvalue { - Rvalue::Cast( - CastKind::Pointer(ty::adjustment::PointerCast::Unsize), - operand, - cast_ty, - ) => { - let Some(local) = place.as_local() else { return }; - match operand { - Operand::Copy(place) | Operand::Move(place) => { - let Some(operand_local) = place.local_or_deref_local() else { return; }; - if !interesting_locals.contains(operand_local) { - return; - } - let operand_ty = local_decls[operand_local].ty; - match (operand_ty.kind(), cast_ty.kind()) { - (ty::Array(of_ty_src, ..), ty::Slice(of_ty_dst)) => { - if of_ty_src == of_ty_dst { - // this is a cast from [T; N] into [T], so we are good - state.insert(local, statement_idx); - } - } - // current way of patching doesn't allow to work with `mut` - ( - ty::Ref( - Region(Interned(ReErased, _)), - operand_ty, - Mutability::Not, - ), - ty::Ref( - Region(Interned(ReErased, _)), - cast_ty, - Mutability::Not, - ), - ) => { - match (operand_ty.kind(), cast_ty.kind()) { - // current way of patching doesn't allow to work with `mut` - (ty::Array(of_ty_src, ..), ty::Slice(of_ty_dst)) => { - if of_ty_src == of_ty_dst { - // this is a cast from [T; N] into [T], so we are good - state.insert(local, statement_idx); - } - } - _ => {} - } - } - _ => {} - } - } - _ => {} - } - } - Rvalue::Len(place) => { - let Some(local) = place.local_or_deref_local() else { - return; - }; - if let Some(cast_statement_idx) = state.get(&local).copied() { - patches_scratchpad.insert(cast_statement_idx, statement_idx); - } - } - _ => { - // invalidate - state.remove(&place.local); - } - } - } - _ => {} - } - } + slice_lengths: IndexVec>>, +} - let mut patcher = Patcher { - tcx, - patches_scratchpad: &*patches_scratchpad, - replacements_scratchpad, - local_decls, - statement_idx: 0, - }; +impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } - block.expand_statements(|st| patcher.patch_expand_statement(st)); + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, loc: Location) { + if let Rvalue::Len(place) = rvalue + && let [PlaceElem::Deref] = &place.projection[..] + && let Some(len) = self.slice_lengths[place.local] + { + *rvalue = Rvalue::Use(Operand::Constant(Box::new(Constant { + span: rustc_span::DUMMY_SP, + user_ty: None, + literal: ConstantKind::from_const(len, self.tcx), + }))); + } + self.super_rvalue(rvalue, loc); + } } diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 7b6fa2baf2f..ced97b2c788 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -404,6 +404,18 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } } +pub fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) { + // First, we're going to get a count of *actual* uses for every `Local`. + let mut used_locals = UsedLocals::new(body); + + // Next, we're going to remove any `Local` with zero actual uses. When we remove those + // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals` + // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from + // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a + // fixedpoint where there are no more unused locals. + remove_unused_definitions_helper(&mut used_locals, body); +} + pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) { // First, we're going to get a count of *actual* uses for every `Local`. let mut used_locals = UsedLocals::new(body); @@ -413,7 +425,7 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) { // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a // fixedpoint where there are no more unused locals. - remove_unused_definitions(&mut used_locals, body); + remove_unused_definitions_helper(&mut used_locals, body); // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s. let map = make_local_map(&mut body.local_decls, &used_locals); @@ -548,7 +560,7 @@ fn visit_local(&mut self, local: Local, _ctx: PlaceContext, _location: Location) } /// Removes unused definitions. Updates the used locals to reflect the changes made. -fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>) { +fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Body<'_>) { // The use counts are updated as we remove the statements. A local might become unused // during the retain operation, leading to a temporary inconsistency (storage statements or // definitions referencing the local might remain). For correctness it is crucial that this diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs new file mode 100644 index 00000000000..bc3fe65cf6c --- /dev/null +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -0,0 +1,222 @@ +use either::Either; +use rustc_data_structures::graph::dominators::Dominators; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_middle::middle::resolve_lifetime::Set1; +use rustc_middle::mir::visit::*; +use rustc_middle::mir::*; +use rustc_middle::ty::{ParamEnv, TyCtxt}; + +#[derive(Debug)] +pub struct SsaLocals { + /// Assignments to each local. This defines whether the local is SSA. + assignments: IndexVec>, + /// We visit the body in reverse postorder, to ensure each local is assigned before it is used. + /// We remember the order in which we saw the assignments to compute the SSA values in a single + /// pass. + assignment_order: Vec, + /// Copy equivalence classes between locals. See `copy_classes` for documentation. + copy_classes: IndexVec, +} + +impl SsaLocals { + pub fn new<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + body: &Body<'tcx>, + borrowed_locals: &BitSet, + ) -> SsaLocals { + let assignment_order = Vec::new(); + + let assignments = IndexVec::from_elem(Set1::Empty, &body.local_decls); + let dominators = body.basic_blocks.dominators(); + let mut visitor = SsaVisitor { assignments, assignment_order, dominators }; + + for (local, decl) in body.local_decls.iter_enumerated() { + if matches!(body.local_kind(local), LocalKind::Arg) { + visitor.assignments[local] = Set1::One(LocationExtended::Arg); + } + if borrowed_locals.contains(local) && !decl.ty.is_freeze(tcx, param_env) { + visitor.assignments[local] = Set1::Many; + } + } + + for (bb, data) in traversal::reverse_postorder(body) { + visitor.visit_basic_block_data(bb, data); + } + + for var_debug_info in &body.var_debug_info { + visitor.visit_var_debug_info(var_debug_info); + } + + debug!(?visitor.assignments); + + visitor + .assignment_order + .retain(|&local| matches!(visitor.assignments[local], Set1::One(_))); + debug!(?visitor.assignment_order); + + let copy_classes = compute_copy_classes(&visitor, body); + + SsaLocals { + assignments: visitor.assignments, + assignment_order: visitor.assignment_order, + copy_classes, + } + } + + pub fn is_ssa(&self, local: Local) -> bool { + matches!(self.assignments[local], Set1::One(_)) + } + + pub fn assignments<'a, 'tcx>( + &'a self, + body: &'a Body<'tcx>, + ) -> impl Iterator)> + 'a { + self.assignment_order.iter().filter_map(|&local| { + if let Set1::One(LocationExtended::Plain(loc)) = self.assignments[local] { + // `loc` must point to a direct assignment to `local`. + let Either::Left(stmt) = body.stmt_at(loc) else { bug!() }; + let Some((target, rvalue)) = stmt.kind.as_assign() else { bug!() }; + assert_eq!(target.as_local(), Some(local)); + Some((local, rvalue)) + } else { + None + } + }) + } + + /// Compute the equivalence classes for locals, based on copy statements. + /// + /// The returned vector maps each local to the one it copies. In the following case: + /// _a = &mut _0 + /// _b = move? _a + /// _c = move? _a + /// _d = move? _c + /// We return the mapping + /// _a => _a // not a copy so, represented by itself + /// _b => _a + /// _c => _a + /// _d => _a // transitively through _c + /// + /// Exception: we do not see through the return place, as it cannot be substituted. + pub fn copy_classes(&self) -> &IndexVec { + &self.copy_classes + } + + /// Make a property uniform on a copy equivalence class by removing elements. + pub fn meet_copy_equivalence(&self, property: &mut BitSet) { + // Consolidate to have a local iff all its copies are. + // + // `copy_classes` defines equivalence classes between locals. The `local`s that recursively + // move/copy the same local all have the same `head`. + for (local, &head) in self.copy_classes.iter_enumerated() { + // If any copy does not have `property`, then the head is not. + if !property.contains(local) { + property.remove(head); + } + } + for (local, &head) in self.copy_classes.iter_enumerated() { + // If any copy does not have `property`, then the head doesn't either, + // then no copy has `property`. + if !property.contains(head) { + property.remove(local); + } + } + + // Verify that we correctly computed equivalence classes. + #[cfg(debug_assertions)] + for (local, &head) in self.copy_classes.iter_enumerated() { + assert_eq!(property.contains(local), property.contains(head)); + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum LocationExtended { + Plain(Location), + Arg, +} + +struct SsaVisitor { + dominators: Dominators, + assignments: IndexVec>, + assignment_order: Vec, +} + +impl<'tcx> Visitor<'tcx> for SsaVisitor { + fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) { + match ctxt { + PlaceContext::MutatingUse(MutatingUseContext::Store) => { + self.assignments[local].insert(LocationExtended::Plain(loc)); + self.assignment_order.push(local); + } + // Anything can happen with raw pointers, so remove them. + PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) + | PlaceContext::MutatingUse(_) => self.assignments[local] = Set1::Many, + // Immutable borrows are taken into account in `SsaLocals::new` by + // removing non-freeze locals. + PlaceContext::NonMutatingUse(_) => { + let set = &mut self.assignments[local]; + let assign_dominates = match *set { + Set1::Empty | Set1::Many => false, + Set1::One(LocationExtended::Arg) => true, + Set1::One(LocationExtended::Plain(assign)) => { + assign.successor_within_block().dominates(loc, &self.dominators) + } + }; + // We are visiting a use that is not dominated by an assignment. + // Either there is a cycle involved, or we are reading for uninitialized local. + // Bail out. + if !assign_dominates { + *set = Set1::Many; + } + } + PlaceContext::NonUse(_) => {} + } + } +} + +#[instrument(level = "trace", skip(ssa, body))] +fn compute_copy_classes(ssa: &SsaVisitor, body: &Body<'_>) -> IndexVec { + let mut copies = IndexVec::from_fn_n(|l| l, body.local_decls.len()); + + for &local in &ssa.assignment_order { + debug!(?local); + + if local == RETURN_PLACE { + // `_0` is special, we cannot rename it. + continue; + } + + // This is not SSA: mark that we don't know the value. + debug!(assignments = ?ssa.assignments[local]); + let Set1::One(LocationExtended::Plain(loc)) = ssa.assignments[local] else { continue }; + + // `loc` must point to a direct assignment to `local`. + let Either::Left(stmt) = body.stmt_at(loc) else { bug!() }; + let Some((_target, rvalue)) = stmt.kind.as_assign() else { bug!() }; + assert_eq!(_target.as_local(), Some(local)); + + let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place)) + = rvalue + else { continue }; + + let Some(rhs) = place.as_local() else { continue }; + let Set1::One(_) = ssa.assignments[rhs] else { continue }; + + // We visit in `assignment_order`, ie. reverse post-order, so `rhs` has been + // visited before `local`, and we just have to copy the representing local. + copies[local] = copies[rhs]; + } + + debug!(?copies); + + // Invariant: `copies` must point to the head of an equivalence class. + #[cfg(debug_assertions)] + for &head in copies.iter() { + assert_eq!(copies[head], head); + } + + copies +} diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index fd6bcad1898..615126e8b58 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -180,7 +180,7 @@ pub fn partition<'tcx>( partitioner.place_root_mono_items(cx, mono_items) }; - initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); + initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx)); debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); @@ -200,7 +200,7 @@ pub fn partition<'tcx>( partitioner.place_inlined_mono_items(cx, initial_partitioning) }; - post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); + post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx)); debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter()); diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 40763da0bb5..054b41b478d 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -649,6 +649,48 @@ pub(crate) struct MatchArmBodyWithoutBraces { pub sub: MatchArmBodyWithoutBracesSugg, } +#[derive(Diagnostic)] +#[diag(parse_inclusive_range_extra_equals)] +#[note] +pub(crate) struct InclusiveRangeExtraEquals { + #[primary_span] + #[suggestion( + suggestion_remove_eq, + style = "short", + code = "..=", + applicability = "maybe-incorrect" + )] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_inclusive_range_match_arrow)] +pub(crate) struct InclusiveRangeMatchArrow { + #[primary_span] + pub span: Span, + #[suggestion( + suggestion_add_space, + style = "verbose", + code = " ", + applicability = "machine-applicable" + )] + pub after_pat: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_inclusive_range_no_end, code = "E0586")] +#[note] +pub(crate) struct InclusiveRangeNoEnd { + #[primary_span] + #[suggestion( + suggestion_open_range, + code = "..", + applicability = "machine-applicable", + style = "short" + )] + pub span: Span, +} + #[derive(Subdiagnostic)] pub(crate) enum MatchArmBodyWithoutBracesSugg { #[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 3225a309a31..dcc3059a7f4 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1882,7 +1882,16 @@ fn recover_after_dot(&mut self) -> Option { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = next_token.kind { - if self.token.span.hi() == next_token.span.lo() { + // If this integer looks like a float, then recover as such. + // + // We will never encounter the exponent part of a floating + // point literal here, since there's no use of the exponent + // syntax that also constitutes a valid integer, so we need + // not check for that. + if suffix.map_or(true, |s| s == sym::f32 || s == sym::f64) + && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_') + && self.token.span.hi() == next_token.span.lo() + { let s = String::from("0.") + symbol.as_str(); let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix); return Some(Token::new(kind, self.token.span.to(next_token.span))); @@ -3168,7 +3177,7 @@ fn mk_range( limits: RangeLimits, ) -> ExprKind { if end.is_none() && limits == RangeLimits::Closed { - self.inclusive_range_with_incorrect_end(self.prev_token.span); + self.inclusive_range_with_incorrect_end(); ExprKind::Err } else { ExprKind::Range(start, end, limits) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index e5411538eea..912f7cc14f6 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,5 +1,7 @@ use super::{ForceCollect, Parser, PathStyle, TrailingToken}; -use crate::errors::RemoveLet; +use crate::errors::{ + InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, RemoveLet, +}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; @@ -9,7 +11,7 @@ PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax, }; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; @@ -746,47 +748,52 @@ fn parse_pat_range_begin_with( // Parsing e.g. `X..`. if let RangeEnd::Included(_) = re.node { // FIXME(Centril): Consider semantic errors instead in `ast_validation`. - self.inclusive_range_with_incorrect_end(re.span); + self.inclusive_range_with_incorrect_end(); } None }; Ok(PatKind::Range(Some(begin), end, re)) } - pub(super) fn inclusive_range_with_incorrect_end(&mut self, span: Span) { + pub(super) fn inclusive_range_with_incorrect_end(&mut self) { let tok = &self.token; - + let span = self.prev_token.span; // If the user typed "..==" instead of "..=", we want to give them // a specific error message telling them to use "..=". + // If they typed "..=>", suggest they use ".. =>". // Otherwise, we assume that they meant to type a half open exclusive // range and give them an error telling them to do that instead. - if matches!(tok.kind, token::Eq) && tok.span.lo() == span.hi() { - let span_with_eq = span.to(tok.span); + let no_space = tok.span.lo() == span.hi(); + match tok.kind { + token::Eq if no_space => { + let span_with_eq = span.to(tok.span); - // Ensure the user doesn't receive unhelpful unexpected token errors - self.bump(); - if self.is_pat_range_end_start(0) { - let _ = self.parse_pat_range_end().map_err(|e| e.cancel()); - } + // Ensure the user doesn't receive unhelpful unexpected token errors + self.bump(); + if self.is_pat_range_end_start(0) { + let _ = self.parse_pat_range_end().map_err(|e| e.cancel()); + } - self.error_inclusive_range_with_extra_equals(span_with_eq); - } else { - self.error_inclusive_range_with_no_end(span); + self.error_inclusive_range_with_extra_equals(span_with_eq); + } + token::Gt if no_space => { + self.error_inclusive_range_match_arrow(span); + } + _ => self.error_inclusive_range_with_no_end(span), } } fn error_inclusive_range_with_extra_equals(&self, span: Span) { - self.struct_span_err(span, "unexpected `=` after inclusive range") - .span_suggestion_short(span, "use `..=` instead", "..=", Applicability::MaybeIncorrect) - .note("inclusive ranges end with a single equals sign (`..=`)") - .emit(); + self.sess.emit_err(InclusiveRangeExtraEquals { span }); + } + + fn error_inclusive_range_match_arrow(&self, span: Span) { + let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi(); + self.sess.emit_err(InclusiveRangeMatchArrow { span, after_pat }); } fn error_inclusive_range_with_no_end(&self, span: Span) { - struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end") - .span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable) - .note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)") - .emit(); + self.sess.emit_err(InclusiveRangeNoEnd { span }); } /// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 25de0a9e750..82d9138c7a3 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1048,7 +1048,7 @@ fn parse_generic_ty_bound( self.parse_remaining_bounds(bounds, true)?; self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; let sp = vec![lo, self.prev_token.span]; - let sugg: Vec<_> = sp.iter().map(|sp| (*sp, String::new())).collect(); + let sugg = vec![(lo, String::from(" ")), (self.prev_token.span, String::new())]; self.struct_span_err(sp, "incorrect braces around trait bounds") .multipart_suggestion( "remove the parentheses", diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 127acb46e92..83adfeb6b10 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -459,30 +459,32 @@ fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { } fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - if tcx.has_attr(def_id.to_def_id(), sym::lang) { - return true; + fn has_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + tcx.has_attr(def_id.to_def_id(), sym::lang) + // Stable attribute for #[lang = "panic_impl"] + || tcx.has_attr(def_id.to_def_id(), sym::panic_handler) } - // Stable attribute for #[lang = "panic_impl"] - if tcx.has_attr(def_id.to_def_id(), sym::panic_handler) { - return true; + fn has_allow_dead_code(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0 == lint::Allow } - if tcx.def_kind(def_id).has_codegen_attrs() { - let cg_attrs = tcx.codegen_fn_attrs(def_id); + fn has_used_like_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + tcx.def_kind(def_id).has_codegen_attrs() && { + let cg_attrs = tcx.codegen_fn_attrs(def_id); - // #[used], #[no_mangle], #[export_name], etc also keeps the item alive - // forcefully, e.g., for placing it in a specific section. - if cg_attrs.contains_extern_indicator() - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) - { - return true; + // #[used], #[no_mangle], #[export_name], etc also keeps the item alive + // forcefully, e.g., for placing it in a specific section. + cg_attrs.contains_extern_indicator() + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) } } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0 == lint::Allow + has_allow_dead_code(tcx, def_id) + || has_used_like_attr(tcx, def_id) + || has_lang_attr(tcx, def_id) } // These check_* functions seeds items that diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index db95b8bca2f..c49c5fa9904 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2573,6 +2573,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio "hir,typed" => Hir(PpHirMode::Typed), "hir-tree" => HirTree, "thir-tree" => ThirTree, + "thir-flat" => ThirFlat, "mir" => Mir, "mir-cfg" => MirCFG, name => early_error( @@ -2581,7 +2582,8 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio "argument to `unpretty` must be one of `normal`, `identified`, \ `expanded`, `expanded,identified`, `expanded,hygiene`, \ `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \ - `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}" + `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir` or \ + `mir-cfg`; got {name}" ), ), }; @@ -2736,6 +2738,8 @@ pub enum PpMode { HirTree, /// `-Zunpretty=thir-tree` ThirTree, + /// `-Zunpretty=`thir-flat` + ThirFlat, /// `-Zunpretty=mir` Mir, /// `-Zunpretty=mir-cfg` @@ -2754,6 +2758,7 @@ pub fn needs_ast_map(&self) -> bool { | Hir(_) | HirTree | ThirTree + | ThirFlat | Mir | MirCFG => true, } @@ -2763,13 +2768,13 @@ pub fn needs_hir(&self) -> bool { match *self { Source(_) | AstTree(_) => false, - Hir(_) | HirTree | ThirTree | Mir | MirCFG => true, + Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true, } } pub fn needs_analysis(&self) -> bool { use PpMode::*; - matches!(*self, Mir | MirCFG | ThirTree) + matches!(*self, Mir | MirCFG | ThirTree | ThirFlat) } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 30ca0b8060d..f1119214be4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -955,6 +955,7 @@ mul, mul_assign, mul_with_overflow, + multiple_supertrait_upcastable, must_not_suspend, must_use, naked, diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index f7cf81da497..e44fd82ba22 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -78,7 +78,7 @@ pub(super) enum CandidateSource { /// let _y = x.clone(); /// } /// ``` - AliasBound(usize), + AliasBound, } pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { @@ -242,8 +242,6 @@ fn assemble_candidates_after_normalizing_self_ty>( // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. // This doesn't work as long as we use `CandidateSource` in winnowing. let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - // FIXME: This is broken if we care about the `usize` of `AliasBound` because the self type - // could be normalized to yet another projection with different item bounds. let normalized_candidates = self.assemble_and_evaluate_candidates(goal); for mut normalized_candidate in normalized_candidates { normalized_candidate.result = @@ -368,15 +366,14 @@ fn assemble_alias_bound_candidates>( ty::Alias(_, alias_ty) => alias_ty, }; - for (i, (assumption, _)) in self + for (assumption, _) in self .tcx() .bound_explicit_item_bounds(alias_ty.def_id) .subst_iter_copied(self.tcx(), alias_ty.substs) - .enumerate() { match G::consider_assumption(self, goal, assumption) { Ok(result) => { - candidates.push(Candidate { source: CandidateSource::AliasBound(i), result }) + candidates.push(Candidate { source: CandidateSource::AliasBound, result }) } Err(NoSolution) => (), } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index cbe64ae4f4e..dd16672cc7a 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -361,7 +361,7 @@ fn compute_closure_kind_goal( } fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> { - if self.tcx().is_object_safe(trait_def_id) { + if self.tcx().check_is_object_safe(trait_def_id) { self.make_canonical_response(Certainty::Yes) } else { Err(NoSolution) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 1961344e838..b175a6dde17 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -171,7 +171,7 @@ fn project_candidate_should_be_dropped_in_favor_of( (CandidateSource::Impl(_), _) | (CandidateSource::ParamEnv(_), _) | (CandidateSource::BuiltinImpl, _) - | (CandidateSource::AliasBound(_), _) => unimplemented!(), + | (CandidateSource::AliasBound, _) => unimplemented!(), } } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 45b6a5f4ec5..1ea8fb8fd3d 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -322,7 +322,7 @@ fn trait_candidate_should_be_dropped_in_favor_of( match (candidate.source, other.source) { (CandidateSource::Impl(_), _) | (CandidateSource::ParamEnv(_), _) - | (CandidateSource::AliasBound(_), _) + | (CandidateSource::AliasBound, _) | (CandidateSource::BuiltinImpl, _) => unimplemented!(), } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index ee0c07e15a3..b35b9d62759 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1748,7 +1748,7 @@ fn suggest_impl_trait( // If the `dyn Trait` is not object safe, do not suggest `Box`. predicates .principal_def_id() - .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty()) + .map_or(true, |def_id| self.tcx.check_is_object_safe(def_id)) } // We only want to suggest `impl Trait` to `dyn Trait`s. // For example, `fn foo() -> str` needs to be filtered out. diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 6c18bf8d22d..18d30771035 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -369,7 +369,7 @@ fn process_obligation( } ty::PredicateKind::ObjectSafe(trait_def_id) => { - if !self.selcx.tcx().is_object_safe(trait_def_id) { + if !self.selcx.tcx().check_is_object_safe(trait_def_id) { ProcessResult::Error(CodeSelectionError(Unimplemented)) } else { ProcessResult::Changed(vec![]) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 55c2f7e2e35..565cfca9090 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -62,6 +62,37 @@ fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [Object ) } +fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { + let violations = tcx.object_safety_violations(trait_def_id); + + if violations.is_empty() { + return true; + } + + // If the trait contains any other violations, then let the error reporting path + // report it instead of emitting a warning here. + if violations.iter().all(|violation| { + matches!( + violation, + ObjectSafetyViolation::Method(_, MethodViolationCode::WhereClauseReferencesSelf, _) + ) + }) { + for violation in violations { + if let ObjectSafetyViolation::Method( + _, + MethodViolationCode::WhereClauseReferencesSelf, + span, + ) = violation + { + lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation); + } + } + return true; + } + + false +} + /// We say a method is *vtable safe* if it can be invoked on a trait /// object. Note that object-safe traits can have some /// non-vtable-safe methods, so long as they require `Self: Sized` or @@ -93,19 +124,6 @@ fn object_safety_violations_for_trait( object_safety_violation_for_method(tcx, trait_def_id, &item) .map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span)) }) - .filter(|violation| { - if let ObjectSafetyViolation::Method( - _, - MethodViolationCode::WhereClauseReferencesSelf, - span, - ) = violation - { - lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation); - false - } else { - true - } - }) .collect(); // Check the trait itself. @@ -866,5 +884,6 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>( } pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { object_safety_violations, ..*providers }; + *providers = + ty::query::Providers { object_safety_violations, check_is_object_safe, ..*providers }; } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 52f4d29181d..7b7abcf552a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -466,7 +466,7 @@ fn assemble_candidates_from_object_ty( if let Some(principal) = data.principal() { if !self.infcx.tcx.features().object_safe_for_dispatch { principal.with_self_ty(self.tcx(), self_ty) - } else if self.tcx().is_object_safe(principal.def_id()) { + } else if self.tcx().check_is_object_safe(principal.def_id()) { principal.with_self_ty(self.tcx(), self_ty) } else { return; diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 61d3531cfc4..89a8fdbac1c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -8,12 +8,11 @@ //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; -use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_middle::ty::{ - self, Binder, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef, - ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeVisitable, + self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate, + TraitRef, Ty, TyCtxt, TypeVisitable, }; use rustc_session::config::TraitSolver; use rustc_span::def_id::DefId; @@ -1009,7 +1008,7 @@ fn confirm_builtin_unsize_candidate( // `T` -> `Trait` (_, &ty::Dynamic(ref data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); - if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { + if let Some(did) = object_dids.find(|did| !tcx.check_is_object_safe(*did)) { return Err(TraitNotObjectSafe(did)); } @@ -1064,51 +1063,18 @@ fn confirm_builtin_unsize_candidate( // `Struct` -> `Struct` (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { - let maybe_unsizing_param_idx = |arg: GenericArg<'tcx>| match arg.unpack() { - GenericArgKind::Type(ty) => match ty.kind() { - ty::Param(p) => Some(p.index), - _ => None, - }, - - // Lifetimes aren't allowed to change during unsizing. - GenericArgKind::Lifetime(_) => None, - - GenericArgKind::Const(ct) => match ct.kind() { - ty::ConstKind::Param(p) => Some(p.index), - _ => None, - }, - }; - - // FIXME(eddyb) cache this (including computing `unsizing_params`) - // by putting it in a query; it would only need the `DefId` as it - // looks at declared field types, not anything substituted. - - // The last field of the structure has to exist and contain type/const parameters. - let (tail_field, prefix_fields) = - def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?; - let tail_field_ty = tcx.bound_type_of(tail_field.did); - - let mut unsizing_params = GrowableBitSet::new_empty(); - for arg in tail_field_ty.0.walk() { - if let Some(i) = maybe_unsizing_param_idx(arg) { - unsizing_params.insert(i); - } - } - - // Ensure none of the other fields mention the parameters used - // in unsizing. - for field in prefix_fields { - for arg in tcx.type_of(field.did).walk() { - if let Some(i) = maybe_unsizing_param_idx(arg) { - unsizing_params.remove(i); - } - } - } - + let unsizing_params = tcx.unsizing_params_for_adt(def.did()); if unsizing_params.is_empty() { return Err(Unimplemented); } + let tail_field = def + .non_enum_variant() + .fields + .last() + .expect("expected unsized ADT to have a tail field"); + let tail_field_ty = tcx.bound_type_of(tail_field.did); + // Extract `TailField` and `TailField` from `Struct` and `Struct`, // normalizing in the process, since `type_of` returns something directly from // astconv (which means it's un-normalized). diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index efd21b979ce..b8f5aeee2d5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -797,7 +797,7 @@ fn evaluate_predicate_recursively<'o>( } ty::PredicateKind::ObjectSafe(trait_def_id) => { - if self.tcx().is_object_safe(trait_def_id) { + if self.tcx().check_is_object_safe(trait_def_id) { Ok(EvaluatedToOk) } else { Ok(EvaluatedToErr) diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 2e9107e153c..84f7e836208 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -580,7 +580,7 @@ fn well_known_trait_id( } fn is_object_safe(&self, trait_id: chalk_ir::TraitId>) -> bool { - self.interner.tcx.is_object_safe(trait_id.0) + self.interner.tcx.check_is_object_safe(trait_id.0) } fn hidden_opaque_type( diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 89abffebdc6..b5005c1d8d8 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; +use rustc_index::bit_set::BitSet; use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt}; use rustc_session::config::TraitSolver; use rustc_span::def_id::{DefId, CRATE_DEF_ID}; @@ -406,6 +407,56 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { node.fn_sig().map_or(hir::IsAsync::NotAsync, |sig| sig.header.asyncness) } +fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BitSet { + let def = tcx.adt_def(def_id); + let num_params = tcx.generics_of(def_id).count(); + + let maybe_unsizing_param_idx = |arg: ty::GenericArg<'tcx>| match arg.unpack() { + ty::GenericArgKind::Type(ty) => match ty.kind() { + ty::Param(p) => Some(p.index), + _ => None, + }, + + // We can't unsize a lifetime + ty::GenericArgKind::Lifetime(_) => None, + + ty::GenericArgKind::Const(ct) => match ct.kind() { + ty::ConstKind::Param(p) => Some(p.index), + _ => None, + }, + }; + + // FIXME(eddyb) cache this (including computing `unsizing_params`) + // by putting it in a query; it would only need the `DefId` as it + // looks at declared field types, not anything substituted. + + // The last field of the structure has to exist and contain type/const parameters. + let Some((tail_field, prefix_fields)) = + def.non_enum_variant().fields.split_last() else + { + return BitSet::new_empty(num_params); + }; + + let mut unsizing_params = BitSet::new_empty(num_params); + for arg in tcx.bound_type_of(tail_field.did).subst_identity().walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.insert(i); + } + } + + // Ensure none of the other fields mention the parameters used + // in unsizing. + for field in prefix_fields { + for arg in tcx.bound_type_of(field.did).subst_identity().walk() { + if let Some(i) = maybe_unsizing_param_idx(arg) { + unsizing_params.remove(i); + } + } + } + + unsizing_params +} + pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { asyncness, @@ -415,6 +466,7 @@ pub fn provide(providers: &mut ty::query::Providers) { instance_def_size_estimate, issue33140_self_ty, impl_defaultness, + unsizing_params_for_adt, ..*providers }; } diff --git a/config.toml.example b/config.toml.example index 299bfd779e5..85f058f3664 100644 --- a/config.toml.example +++ b/config.toml.example @@ -233,6 +233,9 @@ changelog-seen = 2 # and generated in already-minified form from the beginning. #docs-minification = true +# Flag to specify whether private items should be included in the library docs. +#library-docs-private-items = false + # Indicate whether the compiler should be documented in addition to the standard # library and facade crates. #compiler-docs = false diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index eadb35cb96d..1da86e1a46a 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -558,7 +558,7 @@ #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::Error; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::fmt::{write, ArgumentV1, Arguments}; +pub use core::fmt::{write, Arguments}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{Binary, Octal}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ca75c3895f4..76dabfb429d 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -87,6 +87,7 @@ #![warn(missing_debug_implementations)] #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] +#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))] // // Library features: #![feature(alloc_layout_extra)] @@ -195,6 +196,7 @@ #![feature(c_unwind)] #![feature(with_negative_coherence)] #![cfg_attr(test, feature(panic_update_hook))] +#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))] // // Rustdoc features: #![feature(doc_cfg)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index c9aa23fc4af..fd1e3e0f75b 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1092,7 +1092,7 @@ pub fn get_mut(this: &mut Self) -> Option<&mut T> { /// # Safety /// /// If any other `Rc` or [`Weak`] pointers to the same allocation exist, then - /// they must be must not be dereferenced or have active borrows for the duration + /// they must not be dereferenced or have active borrows for the duration /// of the returned borrow, and their inner type must be exactly the same as the /// inner type of this Rc (including lifetimes). This is trivially the case if no /// such pointers exist, for example immediately after `Rc::new`. diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index fecacc2bb63..093dcbbe8bf 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -782,6 +782,38 @@ fn borrow_mut(&mut self) -> &mut [T] { } } +// Specializable trait for implementing ToOwned::clone_into. This is +// public in the crate and has the Allocator parameter so that +// vec::clone_from use it too. +#[cfg(not(no_global_oom_handling))] +pub(crate) trait SpecCloneIntoVec { + fn clone_into(&self, target: &mut Vec); +} + +#[cfg(not(no_global_oom_handling))] +impl SpecCloneIntoVec for [T] { + default fn clone_into(&self, target: &mut Vec) { + // drop anything in target that will not be overwritten + target.truncate(self.len()); + + // target.len <= self.len due to the truncate above, so the + // slices here are always in-bounds. + let (init, tail) = self.split_at(target.len()); + + // reuse the contained values' allocations/resources. + target.clone_from_slice(init); + target.extend_from_slice(tail); + } +} + +#[cfg(not(no_global_oom_handling))] +impl SpecCloneIntoVec for [T] { + fn clone_into(&self, target: &mut Vec) { + target.clear(); + target.extend_from_slice(self); + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for [T] { @@ -797,16 +829,7 @@ fn to_owned(&self) -> Vec { } fn clone_into(&self, target: &mut Vec) { - // drop anything in target that will not be overwritten - target.truncate(self.len()); - - // target.len <= self.len due to the truncate above, so the - // slices here are always in-bounds. - let (init, tail) = self.split_at(target.len()); - - // reuse the contained values' allocations/resources. - target.clone_from_slice(init); - target.extend_from_slice(tail); + SpecCloneIntoVec::clone_into(self, target); } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 9bc9182f7b5..f20486ca9e4 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1733,7 +1733,7 @@ pub fn get_mut(this: &mut Self) -> Option<&mut T> { /// # Safety /// /// If any other `Arc` or [`Weak`] pointers to the same allocation exist, then - /// they must be must not be dereferenced or have active borrows for the duration + /// they must not be dereferenced or have active borrows for the duration /// of the returned borrow, and their inner type must be exactly the same as the /// inner type of this Rc (including lifetimes). This is trivially the case if no /// such pointers exist, for example immediately after `Arc::new`. diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 36b0b3c9e7c..a07f3da78d3 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2646,35 +2646,6 @@ fn deref_mut(&mut self) -> &mut [T] { } } -#[cfg(not(no_global_oom_handling))] -trait SpecCloneFrom { - fn clone_from(this: &mut Self, other: &Self); -} - -#[cfg(not(no_global_oom_handling))] -impl SpecCloneFrom for Vec { - default fn clone_from(this: &mut Self, other: &Self) { - // drop anything that will not be overwritten - this.truncate(other.len()); - - // self.len <= other.len due to the truncate above, so the - // slices here are always in-bounds. - let (init, tail) = other.split_at(this.len()); - - // reuse the contained values' allocations/resources. - this.clone_from_slice(init); - this.extend_from_slice(tail); - } -} - -#[cfg(not(no_global_oom_handling))] -impl SpecCloneFrom for Vec { - fn clone_from(this: &mut Self, other: &Self) { - this.clear(); - this.extend_from_slice(other); - } -} - #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Vec { @@ -2695,7 +2666,7 @@ fn clone(&self) -> Self { } fn clone_from(&mut self, other: &Self) { - SpecCloneFrom::clone_from(self, other) + crate::slice::SpecCloneIntoVec::clone_into(other.as_slice(), self); } } diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 7152300abcb..d2fac23ff18 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -28,6 +28,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Error")] #[rustc_has_incoherent_inherent_impls] +#[cfg_attr(not(bootstrap), allow(multiple_supertrait_upcastable))] pub trait Error: Debug + Display { /// The lower-level source of this error, if any. /// diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 8790649abe6..6dfe36e6926 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -95,6 +95,7 @@ #![warn(missing_docs)] #![allow(explicit_outlives_requirements)] #![allow(incomplete_features)] +#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))] // // Library features: #![feature(const_align_offset)] @@ -235,6 +236,7 @@ #![feature(unsized_fn_params)] #![feature(asm_const)] #![feature(const_transmute_copy)] +#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))] // // Target features: #![feature(arm_target_feature)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 2cae98b8e49..b59f28193e2 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -5,7 +5,7 @@ macro_rules! int_impl { $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr, $bound_condition:expr) => { /// The smallest value that can be represented by this integer type - #[doc = concat!("(−2", $BITS_MINUS_ONE, "", $bound_condition, ")")] + #[doc = concat!("(−2", $BITS_MINUS_ONE, "", $bound_condition, ").")] /// /// # Examples /// @@ -18,7 +18,7 @@ macro_rules! int_impl { pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self; /// The largest value that can be represented by this integer type - #[doc = concat!("(2", $BITS_MINUS_ONE, " − 1", $bound_condition, ")")] + #[doc = concat!("(2", $BITS_MINUS_ONE, " − 1", $bound_condition, ").")] /// /// # Examples /// @@ -2574,12 +2574,13 @@ pub const fn abs_diff(self, other: Self) -> $UnsignedT { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] + #[rustc_allow_const_fn_unstable(const_cmp)] pub const fn signum(self) -> Self { - match self { - n if n > 0 => 1, - 0 => 0, - _ => -1, - } + // Picking the right way to phrase this is complicated + // () + // so delegate it to `Ord` which is already producing -1/0/+1 + // exactly like we need and can be the place to deal with the complexity. + self.cmp(&0) as _ } /// Returns `true` if `self` is positive and `false` if the number is zero or diff --git a/library/std/src/os/fuchsia/raw.rs b/library/std/src/os/fuchsia/raw.rs index 060d6e86b6c..ea6b94f2f13 100644 --- a/library/std/src/os/fuchsia/raw.rs +++ b/library/std/src/os/fuchsia/raw.rs @@ -24,12 +24,7 @@ #[stable(feature = "raw_ext", since = "1.1.0")] pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; -#[cfg(any( - target_arch = "x86", - target_arch = "le32", - target_arch = "powerpc", - target_arch = "arm" -))] +#[cfg(any(target_arch = "x86", target_arch = "powerpc", target_arch = "arm"))] mod arch { use crate::os::raw::{c_long, c_short, c_uint}; diff --git a/library/std/src/os/l4re/raw.rs b/library/std/src/os/l4re/raw.rs index 699e8be33c8..b3f7439f8cd 100644 --- a/library/std/src/os/l4re/raw.rs +++ b/library/std/src/os/l4re/raw.rs @@ -26,7 +26,6 @@ #[cfg(any( target_arch = "x86", - target_arch = "le32", target_arch = "m68k", target_arch = "powerpc", target_arch = "sparc", diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index c73791d1452..f46028c3a96 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -26,7 +26,6 @@ #[cfg(any( target_arch = "x86", - target_arch = "le32", target_arch = "m68k", target_arch = "powerpc", target_arch = "sparc", diff --git a/library/std/src/os/net/mod.rs b/library/std/src/os/net/mod.rs index 5ec267c41e9..b7046dd7c59 100644 --- a/library/std/src/os/net/mod.rs +++ b/library/std/src/os/net/mod.rs @@ -1,4 +1,13 @@ //! OS-specific networking functionality. +// See cfg macros in `library/std/src/os/mod.rs` for why these platforms must +// be special-cased during rustdoc generation. +#[cfg(not(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +)))] #[cfg(any(target_os = "linux", target_os = "android", doc))] pub(super) mod linux_ext; diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs index 3edbe728077..403a5e627f1 100644 --- a/library/std/src/sys/common/alloc.rs +++ b/library/std/src/sys/common/alloc.rs @@ -7,6 +7,7 @@ #[cfg(any( target_arch = "x86", target_arch = "arm", + target_arch = "m68k", target_arch = "mips", target_arch = "powerpc", target_arch = "powerpc64", diff --git a/library/std/src/time.rs b/library/std/src/time.rs index ecd06ebf743..acf9c29083f 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -1,6 +1,6 @@ //! Temporal quantification. //! -//! # Examples: +//! # Examples //! //! There are multiple ways to create a new [`Duration`]: //! diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 24cbe035f2f..1ee68c8540b 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -53,6 +53,7 @@ pub struct ConsoleTestState { pub metrics: MetricMap, pub failures: Vec<(TestDesc, Vec)>, pub not_failures: Vec<(TestDesc, Vec)>, + pub ignores: Vec<(TestDesc, Vec)>, pub time_failures: Vec<(TestDesc, Vec)>, pub options: Options, } @@ -76,6 +77,7 @@ pub fn new(opts: &TestOpts) -> io::Result { metrics: MetricMap::new(), failures: Vec::new(), not_failures: Vec::new(), + ignores: Vec::new(), time_failures: Vec::new(), options: opts.options, }) @@ -194,7 +196,10 @@ fn handle_test_result(st: &mut ConsoleTestState, completed_test: CompletedTest) st.passed += 1; st.not_failures.push((test, stdout)); } - TestResult::TrIgnored => st.ignored += 1, + TestResult::TrIgnored => { + st.ignored += 1; + st.ignores.push((test, stdout)); + } TestResult::TrBench(bs) => { st.metrics.insert_metric( test.name.as_slice(), diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs index 0837ab16905..a431acfbc27 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -254,6 +254,15 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result { self.write_plain("\n\n")?; + // Custom handling of cases where there is only 1 test to execute and that test was ignored. + // We want to show more detailed information(why was the test ignored) for investigation purposes. + if self.total_test_count == 1 && state.ignores.len() == 1 { + let test_desc = &state.ignores[0].0; + if let Some(im) = test_desc.ignore_message { + self.write_plain(format!("test: {}, ignore_message: {}\n\n", test_desc.name, im))?; + } + } + Ok(success) } } diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 3a0260f86cf..44776fb0a31 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -790,6 +790,7 @@ fn should_sort_failures_before_printing_them() { failures: vec![(test_b, Vec::new()), (test_a, Vec::new())], options: Options::new(), not_failures: Vec::new(), + ignores: Vec::new(), time_failures: Vec::new(), }; diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index fdd659c60ca..165502b0a41 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -65,6 +65,7 @@ pub struct Config { pub verbose: usize, pub submodules: Option, pub compiler_docs: bool, + pub library_docs_private_items: bool, pub docs_minification: bool, pub docs: bool, pub locked_deps: bool, @@ -606,6 +607,7 @@ struct Build { rustfmt: Option = "rustfmt", docs: Option = "docs", compiler_docs: Option = "compiler-docs", + library_docs_private_items: Option = "library-docs-private-items", docs_minification: Option = "docs-minification", submodules: Option = "submodules", gdb: Option = "gdb", @@ -1018,6 +1020,7 @@ fn parse_inner<'a>(args: &[String], get_toml: impl 'a + Fn(&Path) -> TomlConfig) config.submodules = build.submodules; set(&mut config.low_priority, build.low_priority); set(&mut config.compiler_docs, build.compiler_docs); + set(&mut config.library_docs_private_items, build.library_docs_private_items); set(&mut config.docs_minification, build.docs_minification); set(&mut config.docs, build.docs); set(&mut config.locked_deps, build.locked_deps); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 9bad9046ecc..7f8aa2573dd 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -597,6 +597,9 @@ fn doc_std( .arg("--resource-suffix") .arg(&builder.version) .args(extra_args); + if builder.config.library_docs_private_items { + cargo.arg("--document-private-items").arg("--document-hidden-items"); + } builder.run(&mut cargo.into()); }; diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index d44b96cfb99..267aa3278d8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -110,7 +110,7 @@ use std::io; use std::io::ErrorKind; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, Stdio}; use std::str; use build_helper::ci::CiEnv; @@ -203,7 +203,6 @@ pub unsafe fn setup(_build: &mut crate::Build) {} (None, "bootstrap", None), (Some(Mode::Rustc), "parallel_compiler", None), (Some(Mode::ToolRustc), "parallel_compiler", None), - (Some(Mode::ToolRustc), "emulate_second_only_system", None), (Some(Mode::Codegen), "parallel_compiler", None), (Some(Mode::Std), "stdarch_intel_sde", None), (Some(Mode::Std), "no_fp_fmt_parse", None), @@ -214,18 +213,9 @@ pub unsafe fn setup(_build: &mut crate::Build) {} (Some(Mode::Std), "backtrace_in_libstd", None), /* Extra values not defined in the built-in targets yet, but used in std */ (Some(Mode::Std), "target_env", Some(&["libnx"])), - (Some(Mode::Std), "target_os", Some(&["watchos"])), - ( - Some(Mode::Std), - "target_arch", - Some(&["asmjs", "spirv", "nvptx", "nvptx64", "le32", "xtensa"]), - ), + // (Some(Mode::Std), "target_os", Some(&[])), + (Some(Mode::Std), "target_arch", Some(&["asmjs", "spirv", "nvptx", "xtensa"])), /* Extra names used by dependencies */ - // FIXME: Used by rustfmt is their test but is invalid (neither cargo nor bootstrap ever set - // this config) should probably by removed or use a allow attribute. - (Some(Mode::ToolRustc), "release", None), - // FIXME: Used by stdarch in their test, should use a allow attribute instead. - (Some(Mode::Std), "dont_compile_me", None), // FIXME: Used by serde_json, but we should not be triggering on external dependencies. (Some(Mode::Rustc), "no_btreemap_remove_entry", None), (Some(Mode::ToolRustc), "no_btreemap_remove_entry", None), @@ -235,8 +225,12 @@ pub unsafe fn setup(_build: &mut crate::Build) {} // FIXME: Used by proc-macro2, but we should not be triggering on external dependencies. (Some(Mode::Rustc), "span_locations", None), (Some(Mode::ToolRustc), "span_locations", None), - // Can be passed in RUSTFLAGS to prevent direct syscalls in rustix. - (None, "rustix_use_libc", None), + // FIXME: Used by rustix, but we should not be triggering on external dependencies. + (Some(Mode::Rustc), "rustix_use_libc", None), + (Some(Mode::ToolRustc), "rustix_use_libc", None), + // FIXME: Used by filetime, but we should not be triggering on external dependencies. + (Some(Mode::Rustc), "emulate_second_only_system", None), + (Some(Mode::ToolRustc), "emulate_second_only_system", None), ]; /// A structure representing a Rust compiler. @@ -662,12 +656,32 @@ fn dir_is_empty(dir: &Path) -> bool { // Try passing `--progress` to start, then run git again without if that fails. let update = |progress: bool| { - let mut git = Command::new("git"); + // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository, + // even though that has no relation to the upstream for the submodule. + let current_branch = { + let output = self + .config + .git() + .args(["symbolic-ref", "--short", "HEAD"]) + .stderr(Stdio::inherit()) + .output(); + let output = t!(output); + if output.status.success() { + Some(String::from_utf8(output.stdout).unwrap().trim().to_owned()) + } else { + None + } + }; + + let mut git = self.config.git(); + if let Some(branch) = current_branch { + git.arg("-c").arg(format!("branch.{branch}.remote=origin")); + } git.args(&["submodule", "update", "--init", "--recursive", "--depth=1"]); if progress { git.arg("--progress"); } - git.arg(relative_path).current_dir(&self.config.src); + git.arg(relative_path); git }; // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails. @@ -1431,6 +1445,14 @@ fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> { return Vec::new(); } + if !stamp.exists() { + eprintln!( + "Error: Unable to find the stamp file {}, did you try to keep a nonexistent build stage?", + stamp.display() + ); + crate::detail_exit(1); + } + let mut paths = Vec::new(); let contents = t!(fs::read(stamp), &stamp); // This is the method we use for extracting paths from the stamp file passed to us. See diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 6bdc88e18f5..5feba4e0605 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -81,7 +81,7 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.jemalloc \ --set rust.use-lld=true \ --set rust.lto=thin -ENV SCRIPT ../src/ci/pgo.sh python3 ../x.py dist \ +ENV SCRIPT python3 ../src/ci/stage-build.py python3 ../x.py dist \ --host $HOSTS --target $HOSTS \ --include-default-paths \ build-manifest bootstrap diff --git a/src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh b/src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh index c6d728eb80d..0b06f5e3623 100755 --- a/src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh +++ b/src/ci/docker/host-x86_64/mingw-check/validate-toolstate.sh @@ -9,11 +9,5 @@ git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git cd rust-toolstate python3 "../../src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" \ "$(git log --format=%s -n1 HEAD)" "" "" -# Only check maintainers if this build is supposed to publish toolstate. -# Builds that are not supposed to publish don't have the access token. -if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then - TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python3 \ - "../../src/tools/publish_toolstate.py" -fi cd .. rm -rf rust-toolstate diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index a466777dd46..5e676a470a0 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -629,9 +629,7 @@ jobs: - name: i686-mingw-1 env: - RUST_CONFIGURE_ARGS: >- - --build=i686-pc-windows-gnu - --set llvm.allow-old-toolchain + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw-subset-1 # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). @@ -641,9 +639,7 @@ jobs: - name: i686-mingw-2 env: - RUST_CONFIGURE_ARGS: >- - --build=i686-pc-windows-gnu - --set llvm.allow-old-toolchain + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw-subset-2 # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). @@ -657,7 +653,6 @@ jobs: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-gnu --enable-profiler - --set llvm.allow-old-toolchain # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 @@ -670,7 +665,6 @@ jobs: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-gnu --enable-profiler - --set llvm.allow-old-toolchain # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 @@ -686,7 +680,7 @@ jobs: --enable-full-tools --enable-profiler --set rust.lto=thin - SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths + SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-xl @@ -722,7 +716,6 @@ jobs: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler - --set llvm.allow-old-toolchain # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 @@ -738,7 +731,6 @@ jobs: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler - --set llvm.allow-old-toolchain # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 1685fbbbbba..7eccb9b8650 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -2,24 +2,6 @@ # If we need to download a custom MinGW, do so here and set the path # appropriately. # -# Here we also do a pretty heinous thing which is to mangle the MinGW -# installation we just downloaded. Currently, as of this writing, we're using -# MinGW-w64 builds of gcc, and that's currently at 6.3.0. We use 6.3.0 as it -# appears to be the first version which contains a fix for #40546, builds -# randomly failing during LLVM due to ar.exe/ranlib.exe failures. -# -# Unfortunately, though, 6.3.0 *also* is the first version of MinGW-w64 builds -# to contain a regression in gdb (#40184). As a result if we were to use the -# gdb provided (7.11.1) then we would fail all debuginfo tests. -# -# In order to fix spurious failures (pretty high priority) we use 6.3.0. To -# avoid disabling gdb tests we download an *old* version of gdb, specifically -# that found inside the 6.2.0 distribution. We then overwrite the 6.3.0 gdb -# with the 6.2.0 gdb to get tests passing. -# -# Note that we don't literally overwrite the gdb.exe binary because it appears -# to just use gdborig.exe, so that's the binary we deal with instead. -# # Otherwise install MinGW through `pacman` set -euo pipefail @@ -27,8 +9,8 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" -MINGW_ARCHIVE_32="i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z" -MINGW_ARCHIVE_64="x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z" +MINGW_ARCHIVE_32="i686-12.2.0-release-posix-dwarf-rt_v10-rev0.7z" +MINGW_ARCHIVE_64="x86_64-12.2.0-release-posix-seh-rt_v10-rev0.7z" if isWindows; then case "${CI_JOB_NAME}" in @@ -66,7 +48,6 @@ if isWindows; then curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" 7z x -y mingw.7z > /dev/null - curl -o "${mingw_dir}/bin/gdborig.exe" "${MIRRORS_BASE}/2017-04-20-${bits}bit-gdborig.exe" ciCommandAddPath "$(pwd)/${mingw_dir}/bin" fi fi diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py new file mode 100644 index 00000000000..c373edfcf46 --- /dev/null +++ b/src/ci/stage-build.py @@ -0,0 +1,663 @@ +#!/usr/bin/env python3 +# ignore-tidy-linelength + +# Compatible with Python 3.6+ + +import contextlib +import getpass +import glob +import logging +import os +import pprint +import shutil +import subprocess +import sys +import time +import traceback +import urllib.request +from collections import OrderedDict +from io import StringIO +from pathlib import Path +from typing import Callable, Dict, Iterable, List, Optional, Union + +PGO_HOST = os.environ["PGO_HOST"] + +LOGGER = logging.getLogger("stage-build") + +LLVM_PGO_CRATES = [ + "syn-1.0.89", + "cargo-0.60.0", + "serde-1.0.136", + "ripgrep-13.0.0", + "regex-1.5.5", + "clap-3.1.6", + "hyper-0.14.18" +] + +RUSTC_PGO_CRATES = [ + "externs", + "ctfe-stress-5", + "cargo-0.60.0", + "token-stream-stress", + "match-stress", + "tuple-stress", + "diesel-1.4.8", + "bitmaps-3.1.0" +] + +LLVM_BOLT_CRATES = LLVM_PGO_CRATES + + +class Pipeline: + # Paths + def checkout_path(self) -> Path: + """ + The root checkout, where the source is located. + """ + raise NotImplementedError + + def downloaded_llvm_dir(self) -> Path: + """ + Directory where the host LLVM is located. + """ + raise NotImplementedError + + def build_root(self) -> Path: + """ + The main directory where the build occurs. + """ + raise NotImplementedError + + def build_artifacts(self) -> Path: + return self.build_root() / "build" / PGO_HOST + + def rustc_stage_0(self) -> Path: + return self.build_artifacts() / "stage0" / "bin" / "rustc" + + def cargo_stage_0(self) -> Path: + return self.build_artifacts() / "stage0" / "bin" / "cargo" + + def rustc_stage_2(self) -> Path: + return self.build_artifacts() / "stage2" / "bin" / "rustc" + + def opt_artifacts(self) -> Path: + raise NotImplementedError + + def llvm_profile_dir_root(self) -> Path: + return self.opt_artifacts() / "llvm-pgo" + + def llvm_profile_merged_file(self) -> Path: + return self.opt_artifacts() / "llvm-pgo.profdata" + + def rustc_perf_dir(self) -> Path: + return self.opt_artifacts() / "rustc-perf" + + def build_rustc_perf(self): + raise NotImplementedError() + + def rustc_profile_dir_root(self) -> Path: + return self.opt_artifacts() / "rustc-pgo" + + def rustc_profile_merged_file(self) -> Path: + return self.opt_artifacts() / "rustc-pgo.profdata" + + def rustc_profile_template_path(self) -> Path: + """ + The profile data is written into a single filepath that is being repeatedly merged when each + rustc invocation ends. Empirically, this can result in some profiling data being lost. That's + why we override the profile path to include the PID. This will produce many more profiling + files, but the resulting profile will produce a slightly faster rustc binary. + """ + return self.rustc_profile_dir_root() / "default_%m_%p.profraw" + + def supports_bolt(self) -> bool: + raise NotImplementedError + + def llvm_bolt_profile_merged_file(self) -> Path: + return self.opt_artifacts() / "bolt.profdata" + + +class LinuxPipeline(Pipeline): + def checkout_path(self) -> Path: + return Path("/checkout") + + def downloaded_llvm_dir(self) -> Path: + return Path("/rustroot") + + def build_root(self) -> Path: + return self.checkout_path() / "obj" + + def opt_artifacts(self) -> Path: + return Path("/tmp/tmp-multistage/opt-artifacts") + + def build_rustc_perf(self): + # /tmp/rustc-perf comes from the Dockerfile + shutil.copytree("/tmp/rustc-perf", self.rustc_perf_dir()) + cmd(["chown", "-R", f"{getpass.getuser()}:", self.rustc_perf_dir()]) + + with change_cwd(self.rustc_perf_dir()): + cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict( + RUSTC=str(self.rustc_stage_0()), + RUSTC_BOOTSTRAP="1" + )) + + def supports_bolt(self) -> bool: + return True + + +class WindowsPipeline(Pipeline): + def __init__(self): + self.checkout_dir = Path(os.getcwd()) + + def checkout_path(self) -> Path: + return self.checkout_dir + + def downloaded_llvm_dir(self) -> Path: + return self.checkout_path() / "citools" / "clang-rust" + + def build_root(self) -> Path: + return self.checkout_path() + + def opt_artifacts(self) -> Path: + return self.checkout_path() / "opt-artifacts" + + def rustc_stage_0(self) -> Path: + return super().rustc_stage_0().with_suffix(".exe") + + def cargo_stage_0(self) -> Path: + return super().cargo_stage_0().with_suffix(".exe") + + def rustc_stage_2(self) -> Path: + return super().rustc_stage_2().with_suffix(".exe") + + def build_rustc_perf(self): + # rustc-perf version from 2022-07-22 + perf_commit = "3c253134664fdcba862c539d37f0de18557a9a4c" + rustc_perf_zip_path = self.opt_artifacts() / "perf.zip" + + def download_rustc_perf(): + download_file( + f"https://github.com/rust-lang/rustc-perf/archive/{perf_commit}.zip", + rustc_perf_zip_path + ) + with change_cwd(self.opt_artifacts()): + unpack_archive(rustc_perf_zip_path) + move_path(Path(f"rustc-perf-{perf_commit}"), self.rustc_perf_dir()) + delete_file(rustc_perf_zip_path) + + retry_action(download_rustc_perf, "Download rustc-perf") + + with change_cwd(self.rustc_perf_dir()): + cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict( + RUSTC=str(self.rustc_stage_0()), + RUSTC_BOOTSTRAP="1" + )) + + def rustc_profile_template_path(self) -> Path: + """ + On Windows, we don't have enough space to use separate files for each rustc invocation. + Therefore, we use a single file for the generated profiles. + """ + return self.rustc_profile_dir_root() / "default_%m.profraw" + + def supports_bolt(self) -> bool: + return False + + +class Timer: + def __init__(self): + # We want this dictionary to be ordered by insertion. + # We use `OrderedDict` for compatibility with older Python versions. + self.stages = OrderedDict() + + @contextlib.contextmanager + def stage(self, name: str): + assert name not in self.stages + + start = time.time() + exc = None + try: + LOGGER.info(f"Stage `{name}` starts") + yield + except BaseException as exception: + exc = exception + raise + finally: + end = time.time() + duration = end - start + self.stages[name] = duration + if exc is None: + LOGGER.info(f"Stage `{name}` ended: OK ({duration:.2f}s)") + else: + LOGGER.info(f"Stage `{name}` ended: FAIL ({duration:.2f}s)") + + def print_stats(self): + total_duration = sum(self.stages.values()) + + # 57 is the width of the whole table + divider = "-" * 57 + + with StringIO() as output: + print(divider, file=output) + for (name, duration) in self.stages.items(): + pct = (duration / total_duration) * 100 + name_str = f"{name}:" + print(f"{name_str:<34} {duration:>12.2f}s ({pct:>5.2f}%)", file=output) + + total_duration_label = "Total duration:" + print(f"{total_duration_label:<34} {total_duration:>12.2f}s", file=output) + print(divider, file=output, end="") + LOGGER.info(f"Timer results\n{output.getvalue()}") + + +@contextlib.contextmanager +def change_cwd(dir: Path): + """ + Temporarily change working directory to `dir`. + """ + cwd = os.getcwd() + LOGGER.debug(f"Changing working dir from `{cwd}` to `{dir}`") + os.chdir(dir) + try: + yield + finally: + LOGGER.debug(f"Reverting working dir to `{cwd}`") + os.chdir(cwd) + + +def move_path(src: Path, dst: Path): + LOGGER.info(f"Moving `{src}` to `{dst}`") + shutil.move(src, dst) + + +def delete_file(path: Path): + LOGGER.info(f"Deleting file `{path}`") + os.unlink(path) + + +def delete_directory(path: Path): + LOGGER.info(f"Deleting directory `{path}`") + shutil.rmtree(path) + + +def unpack_archive(archive: Path): + LOGGER.info(f"Unpacking archive `{archive}`") + shutil.unpack_archive(archive) + + +def download_file(src: str, target: Path): + LOGGER.info(f"Downloading `{src}` into `{target}`") + urllib.request.urlretrieve(src, str(target)) + + +def retry_action(action, name: str, max_fails: int = 5): + LOGGER.info(f"Attempting to perform action `{name}` with retry") + for iteration in range(max_fails): + LOGGER.info(f"Attempt {iteration + 1}/{max_fails}") + try: + action() + return + except: + LOGGER.error(f"Action `{name}` has failed\n{traceback.format_exc()}") + + raise Exception(f"Action `{name}` has failed after {max_fails} attempts") + + +def cmd( + args: List[Union[str, Path]], + env: Optional[Dict[str, str]] = None, + output_path: Optional[Path] = None +): + args = [str(arg) for arg in args] + + environment = os.environ.copy() + + cmd_str = "" + if env is not None: + environment.update(env) + cmd_str += " ".join(f"{k}={v}" for (k, v) in (env or {}).items()) + cmd_str += " " + cmd_str += " ".join(args) + if output_path is not None: + cmd_str += f" > {output_path}" + LOGGER.info(f"Executing `{cmd_str}`") + + if output_path is not None: + with open(output_path, "w") as f: + return subprocess.run( + args, + env=environment, + check=True, + stdout=f + ) + return subprocess.run(args, env=environment, check=True) + + +def run_compiler_benchmarks( + pipeline: Pipeline, + profiles: List[str], + scenarios: List[str], + crates: List[str], + env: Optional[Dict[str, str]] = None +): + env = env if env is not None else {} + + # Compile libcore, both in opt-level=0 and opt-level=3 + with change_cwd(pipeline.build_root()): + cmd([ + pipeline.rustc_stage_2(), + "--edition", "2021", + "--crate-type", "lib", + str(pipeline.checkout_path() / "library/core/src/lib.rs"), + "--out-dir", pipeline.opt_artifacts() + ], env=dict(RUSTC_BOOTSTRAP="1", **env)) + + cmd([ + pipeline.rustc_stage_2(), + "--edition", "2021", + "--crate-type", "lib", + "-Copt-level=3", + str(pipeline.checkout_path() / "library/core/src/lib.rs"), + "--out-dir", pipeline.opt_artifacts() + ], env=dict(RUSTC_BOOTSTRAP="1", **env)) + + # Run rustc-perf benchmarks + # Benchmark using profile_local with eprintln, which essentially just means + # don't actually benchmark -- just make sure we run rustc a bunch of times. + with change_cwd(pipeline.rustc_perf_dir()): + cmd([ + pipeline.cargo_stage_0(), + "run", + "-p", "collector", "--bin", "collector", "--", + "profile_local", "eprintln", + pipeline.rustc_stage_2(), + "--id", "Test", + "--cargo", pipeline.cargo_stage_0(), + "--profiles", ",".join(profiles), + "--scenarios", ",".join(scenarios), + "--include", ",".join(crates) + ], env=dict( + RUST_LOG="collector=debug", + RUSTC=str(pipeline.rustc_stage_0()), + RUSTC_BOOTSTRAP="1", + **env + )) + + +# https://stackoverflow.com/a/31631711/1107768 +def format_bytes(size: int) -> str: + """Return the given bytes as a human friendly KiB, MiB or GiB string.""" + KB = 1024 + MB = KB ** 2 # 1,048,576 + GB = KB ** 3 # 1,073,741,824 + TB = KB ** 4 # 1,099,511,627,776 + + if size < KB: + return f"{size} B" + elif KB <= size < MB: + return f"{size / KB:.2f} KiB" + elif MB <= size < GB: + return f"{size / MB:.2f} MiB" + elif GB <= size < TB: + return f"{size / GB:.2f} GiB" + else: + return str(size) + + +# https://stackoverflow.com/a/63307131/1107768 +def count_files(path: Path) -> int: + return sum(1 for p in path.rglob("*") if p.is_file()) + + +def count_files_with_prefix(path: Path) -> int: + return sum(1 for p in glob.glob(f"{path}*") if Path(p).is_file()) + + +# https://stackoverflow.com/a/55659577/1107768 +def get_path_size(path: Path) -> int: + if path.is_dir(): + return sum(p.stat().st_size for p in path.rglob("*")) + return path.stat().st_size + + +def get_path_prefix_size(path: Path) -> int: + """ + Get size of all files beginning with the prefix `path`. + Alternative to shell `du -sh *`. + """ + return sum(Path(p).stat().st_size for p in glob.glob(f"{path}*")) + + +def get_files(directory: Path, filter: Optional[Callable[[Path], bool]] = None) -> Iterable[Path]: + for file in os.listdir(directory): + path = directory / file + if filter is None or filter(path): + yield path + + +def build_rustc( + pipeline: Pipeline, + args: List[str], + env: Optional[Dict[str, str]] = None +): + arguments = [ + sys.executable, + pipeline.checkout_path() / "x.py", + "build", + "--target", PGO_HOST, + "--host", PGO_HOST, + "--stage", "2", + "library/std" + ] + args + cmd(arguments, env=env) + + +def create_pipeline() -> Pipeline: + if sys.platform == "linux": + return LinuxPipeline() + elif sys.platform in ("cygwin", "win32"): + return WindowsPipeline() + else: + raise Exception(f"Optimized build is not supported for platform {sys.platform}") + + +def gather_llvm_profiles(pipeline: Pipeline): + LOGGER.info("Running benchmarks with PGO instrumented LLVM") + run_compiler_benchmarks( + pipeline, + profiles=["Debug", "Opt"], + scenarios=["Full"], + crates=LLVM_PGO_CRATES + ) + + profile_path = pipeline.llvm_profile_merged_file() + LOGGER.info(f"Merging LLVM PGO profiles to {profile_path}") + cmd([ + pipeline.downloaded_llvm_dir() / "bin" / "llvm-profdata", + "merge", + "-o", profile_path, + pipeline.llvm_profile_dir_root() + ]) + + LOGGER.info("LLVM PGO statistics") + LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}") + LOGGER.info( + f"{pipeline.llvm_profile_dir_root()}: {format_bytes(get_path_size(pipeline.llvm_profile_dir_root()))}") + LOGGER.info(f"Profile file count: {count_files(pipeline.llvm_profile_dir_root())}") + + # We don't need the individual .profraw files now that they have been merged + # into a final .profdata + delete_directory(pipeline.llvm_profile_dir_root()) + + +def gather_rustc_profiles(pipeline: Pipeline): + LOGGER.info("Running benchmarks with PGO instrumented rustc") + + # Here we're profiling the `rustc` frontend, so we also include `Check`. + # The benchmark set includes various stress tests that put the frontend under pressure. + run_compiler_benchmarks( + pipeline, + profiles=["Check", "Debug", "Opt"], + scenarios=["All"], + crates=RUSTC_PGO_CRATES, + env=dict( + LLVM_PROFILE_FILE=str(pipeline.rustc_profile_template_path()) + ) + ) + + profile_path = pipeline.rustc_profile_merged_file() + LOGGER.info(f"Merging Rustc PGO profiles to {profile_path}") + cmd([ + pipeline.build_artifacts() / "llvm" / "bin" / "llvm-profdata", + "merge", + "-o", profile_path, + pipeline.rustc_profile_dir_root() + ]) + + LOGGER.info("Rustc PGO statistics") + LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}") + LOGGER.info( + f"{pipeline.rustc_profile_dir_root()}: {format_bytes(get_path_size(pipeline.rustc_profile_dir_root()))}") + LOGGER.info(f"Profile file count: {count_files(pipeline.rustc_profile_dir_root())}") + + # We don't need the individual .profraw files now that they have been merged + # into a final .profdata + delete_directory(pipeline.rustc_profile_dir_root()) + + +def gather_llvm_bolt_profiles(pipeline: Pipeline): + LOGGER.info("Running benchmarks with BOLT instrumented LLVM") + run_compiler_benchmarks( + pipeline, + profiles=["Check", "Debug", "Opt"], + scenarios=["Full"], + crates=LLVM_BOLT_CRATES + ) + + merged_profile_path = pipeline.llvm_bolt_profile_merged_file() + profile_files_path = Path("/tmp/prof.fdata") + LOGGER.info(f"Merging LLVM BOLT profiles to {merged_profile_path}") + + profile_files = sorted(glob.glob(f"{profile_files_path}*")) + cmd([ + "merge-fdata", + *profile_files, + ], output_path=merged_profile_path) + + LOGGER.info("LLVM BOLT statistics") + LOGGER.info(f"{merged_profile_path}: {format_bytes(get_path_size(merged_profile_path))}") + LOGGER.info( + f"{profile_files_path}: {format_bytes(get_path_prefix_size(profile_files_path))}") + LOGGER.info(f"Profile file count: {count_files_with_prefix(profile_files_path)}") + + +def clear_llvm_files(pipeline: Pipeline): + """ + Rustbuild currently doesn't support rebuilding LLVM when PGO options + change (or any other llvm-related options); so just clear out the relevant + directories ourselves. + """ + LOGGER.info("Clearing LLVM build files") + delete_directory(pipeline.build_artifacts() / "llvm") + delete_directory(pipeline.build_artifacts() / "lld") + + +def print_binary_sizes(pipeline: Pipeline): + bin_dir = pipeline.build_artifacts() / "stage2" / "bin" + binaries = get_files(bin_dir) + + lib_dir = pipeline.build_artifacts() / "stage2" / "lib" + libraries = get_files(lib_dir, lambda p: p.suffix == ".so") + + paths = sorted(binaries) + sorted(libraries) + with StringIO() as output: + for path in paths: + path_str = f"{path.name}:" + print(f"{path_str:<30}{format_bytes(path.stat().st_size):>14}", file=output) + LOGGER.info(f"Rustc binary size\n{output.getvalue()}") + + +def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: List[str]): + # Clear and prepare tmp directory + shutil.rmtree(pipeline.opt_artifacts(), ignore_errors=True) + os.makedirs(pipeline.opt_artifacts(), exist_ok=True) + + pipeline.build_rustc_perf() + + # Stage 1: Build rustc + PGO instrumented LLVM + with timer.stage("Build rustc (LLVM PGO)"): + build_rustc(pipeline, args=[ + "--llvm-profile-generate" + ], env=dict( + LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p") + )) + + with timer.stage("Gather profiles (LLVM PGO)"): + gather_llvm_profiles(pipeline) + + clear_llvm_files(pipeline) + final_build_args += [ + "--llvm-profile-use", + pipeline.llvm_profile_merged_file() + ] + + # Stage 2: Build PGO instrumented rustc + LLVM + with timer.stage("Build rustc (rustc PGO)"): + build_rustc(pipeline, args=[ + "--rust-profile-generate", + pipeline.rustc_profile_dir_root() + ]) + + with timer.stage("Gather profiles (rustc PGO)"): + gather_rustc_profiles(pipeline) + + clear_llvm_files(pipeline) + final_build_args += [ + "--rust-profile-use", + pipeline.rustc_profile_merged_file() + ] + + # Stage 3: Build rustc + BOLT instrumented LLVM + if pipeline.supports_bolt(): + with timer.stage("Build rustc (LLVM BOLT)"): + build_rustc(pipeline, args=[ + "--llvm-profile-use", + pipeline.llvm_profile_merged_file(), + "--llvm-bolt-profile-generate", + ]) + with timer.stage("Gather profiles (LLVM BOLT)"): + gather_llvm_bolt_profiles(pipeline) + + clear_llvm_files(pipeline) + final_build_args += [ + "--llvm-bolt-profile-use", + pipeline.llvm_bolt_profile_merged_file() + ] + + # Stage 4: Build PGO optimized rustc + PGO/BOLT optimized LLVM + with timer.stage("Final build"): + cmd(final_build_args) + + +if __name__ == "__main__": + logging.basicConfig( + level=logging.DEBUG, + format="%(name)s %(levelname)-4s: %(message)s", + ) + + LOGGER.info(f"Running multi-stage build using Python {sys.version}") + LOGGER.info(f"Environment values\n{pprint.pformat(dict(os.environ), indent=2)}") + + build_args = sys.argv[1:] + + timer = Timer() + pipeline = create_pipeline() + try: + execute_build_pipeline(timer, pipeline, build_args) + except BaseException as e: + LOGGER.error("The multi-stage build has failed") + raise e + finally: + timer.print_stats() + + print_binary_sizes(pipeline) diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh index 7a846d44ad6..ff17931115c 100755 --- a/src/etc/pre-push.sh +++ b/src/etc/pre-push.sh @@ -14,4 +14,4 @@ ROOT_DIR="$(git rev-parse --show-toplevel)" echo "Running pre-push script $ROOT_DIR/x test tidy" cd "$ROOT_DIR" -./x test tidy +CARGOFLAGS="--locked" ./x test tidy diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 56b40d8c66b..2c514a0c826 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -509,7 +509,7 @@ fn println_condition(condition: Condition) { // these values up both in `dataset` and in the storage API, so it needs to be able // to convert the names back and forth. Despite doing this kebab-case to // StudlyCaps transformation automatically, the JS DOM API does not provide a - // mechanism for doing the just transformation on a string. So we want to avoid + // mechanism for doing just the transformation on a string. So we want to avoid // the StudlyCaps representation in the `dataset` property. // // We solve this by replacing all the `-`s with `_`s. We do that here, when we diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index d644293d3ef..be6de231854 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1528,11 +1528,7 @@ fn doc_impl_item( }) }) .map(|item| format!("{}.{}", item.type_(), name)); - write!( - w, - "
", - id, item_type, in_trait_class, - ); + write!(w, "
", id, item_type, in_trait_class,); render_rightside(w, cx, item, containing_item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. @@ -1554,11 +1550,7 @@ fn doc_impl_item( kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => { let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); - write!( - w, - "
", - id, item_type, in_trait_class - ); + write!(w, "
", id, item_type, in_trait_class); render_rightside(w, cx, item, containing_item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. @@ -1606,11 +1598,7 @@ fn doc_impl_item( clean::AssocTypeItem(tydef, _bounds) => { let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); - write!( - w, - "
", - id, item_type, in_trait_class - ); + write!(w, "
", id, item_type, in_trait_class); if trait_.is_some() { // Anchors are only used on trait impls. write!(w, "§", id); @@ -1844,7 +1832,7 @@ pub(crate) fn render_impl_summary( } else { format!(" data-aliases=\"{}\"", aliases.join(",")) }; - write!(w, "
", id, aliases); + write!(w, "
", id, aliases); render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal); write!(w, "§", id); write!(w, "

"); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 508b2bab0eb..b0288d55c25 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -735,7 +735,7 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean:: let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; write!(w, "
"); } - write!(w, "
", id); + write!(w, "
", id); render_rightside(w, cx, m, t, RenderMode::Normal); write!(w, "

"); render_assoc_item( diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index a841b4b63ba..1cd552e7f25 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -1,5 +1,5 @@ // Local js definitions: -/* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */ +/* global getSettingValue, getVirtualKey, updateLocalStorage, updateTheme */ /* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */ /* global MAIN_ID, getVar, getSettingsButton */ @@ -19,7 +19,7 @@ case "theme": case "preferred-dark-theme": case "preferred-light-theme": - updateSystemTheme(); + updateTheme(); updateLightAndDark(); break; case "line-numbers": diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index db2db83ca63..8836d1b2e46 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -153,79 +153,74 @@ function switchTheme(styleElem, mainStyleElem, newThemeName, saveTheme) { } } -// This function is called from "main.js". -// eslint-disable-next-line no-unused-vars -function useSystemTheme(value) { - if (value === undefined) { - value = true; - } - - updateLocalStorage("use-system-theme", value); - - // update the toggle if we're on the settings page - const toggle = document.getElementById("use-system-theme"); - if (toggle && toggle instanceof HTMLInputElement) { - toggle.checked = value; - } -} - -const updateSystemTheme = (function() { - if (!window.matchMedia) { - // fallback to the CSS computed value - return () => { - const cssTheme = getComputedStyle(document.documentElement) - .getPropertyValue("content"); - - switchTheme( - window.currentTheme, - window.mainTheme, - JSON.parse(cssTheme) || "light", - true - ); +const updateTheme = (function() { + /** + * Update the current theme to match whatever the current combination of + * * the preference for using the system theme + * (if this is the case, the value of preferred-light-theme, if the + * system theme is light, otherwise if dark, the value of + * preferred-dark-theme.) + * * the preferred theme + * … dictates that it should be. + */ + function updateTheme() { + const use = (theme, saveTheme) => { + switchTheme(window.currentTheme, window.mainTheme, theme, saveTheme); }; - } - - // only listen to (prefers-color-scheme: dark) because light is the default - const mql = window.matchMedia("(prefers-color-scheme: dark)"); - function handlePreferenceChange(mql) { - const use = theme => { - switchTheme(window.currentTheme, window.mainTheme, theme, true); - }; // maybe the user has disabled the setting in the meantime! if (getSettingValue("use-system-theme") !== "false") { const lightTheme = getSettingValue("preferred-light-theme") || "light"; const darkTheme = getSettingValue("preferred-dark-theme") || "dark"; - if (mql.matches) { - use(darkTheme); + if (isDarkMode()) { + use(darkTheme, true); } else { // prefers a light theme, or has no preference - use(lightTheme); + use(lightTheme, true); } // note: we save the theme so that it doesn't suddenly change when // the user disables "use-system-theme" and reloads the page or // navigates to another page } else { - use(getSettingValue("theme")); + use(getSettingValue("theme"), false); } } - mql.addListener(handlePreferenceChange); + // This is always updated below to a function () => bool. + let isDarkMode; - return () => { - handlePreferenceChange(mql); - }; -})(); + // Determine the function for isDarkMode, and if we have + // `window.matchMedia`, set up an event listener on the preferred color + // scheme. + // + // Otherwise, fall back to the prefers-color-scheme value CSS captured in + // the "content" property. + if (window.matchMedia) { + // only listen to (prefers-color-scheme: dark) because light is the default + const mql = window.matchMedia("(prefers-color-scheme: dark)"); -function switchToSavedTheme() { - switchTheme( - window.currentTheme, - window.mainTheme, - getSettingValue("theme") || "light", - false - ); -} + isDarkMode = () => mql.matches; + + if (mql.addEventListener) { + mql.addEventListener("change", updateTheme); + } else { + // This is deprecated, see: + // https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/addListener + mql.addListener(updateTheme); + } + } else { + // fallback to the CSS computed value + const cssContent = getComputedStyle(document.documentElement) + .getPropertyValue("content"); + // (Note: the double-quotes come from that this is a CSS value, which + // might be a length, string, etc.) + const cssColorScheme = cssContent || "\"light\""; + isDarkMode = () => (cssColorScheme === "\"dark\""); + } + + return updateTheme; +})(); if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) { // update the preferred dark theme if the user is already using a dark theme @@ -235,13 +230,10 @@ if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) { && darkThemes.indexOf(localStoredTheme) >= 0) { updateLocalStorage("preferred-dark-theme", localStoredTheme); } - - // call the function to initialize the theme at least once! - updateSystemTheme(); -} else { - switchToSavedTheme(); } +updateTheme(); + if (getSettingValue("source-sidebar-show") === "true") { // At this point in page load, `document.body` is not available yet. // Set a class on the `` element instead. @@ -259,6 +251,6 @@ if (getSettingValue("source-sidebar-show") === "true") { // specifically when talking to a remote website with no caching. window.addEventListener("pageshow", ev => { if (ev.persisted) { - setTimeout(switchToSavedTheme, 0); + setTimeout(updateTheme, 0); } }); diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index dc30e4bb1be..45fd87bea9b 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -926,7 +926,7 @@ pub fn make_test_description( cfg: Option<&str>, ) -> test::TestDesc { let mut ignore = false; - let ignore_message = None; + let mut ignore_message = None; let mut should_fail = false; let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some(); @@ -966,41 +966,67 @@ pub fn make_test_description( if revision.is_some() && revision != cfg { return; } + macro_rules! reason { + ($e:expr) => { + ignore |= match $e { + true => { + ignore_message = Some(stringify!($e)); + true + } + false => ignore, + } + }; + } ignore = match config.parse_cfg_name_directive(ln, "ignore") { - ParsedNameDirective::Match => true, + ParsedNameDirective::Match => { + ignore_message = Some("cfg -> ignore => Match"); + true + } ParsedNameDirective::NoMatch => ignore, }; + if config.has_cfg_prefix(ln, "only") { ignore = match config.parse_cfg_name_directive(ln, "only") { ParsedNameDirective::Match => ignore, - ParsedNameDirective::NoMatch => true, + ParsedNameDirective::NoMatch => { + ignore_message = Some("cfg -> only => NoMatch"); + true + } }; } - ignore |= ignore_llvm(config, ln); - ignore |= - config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln); - ignore |= !has_asm_support && config.parse_name_directive(ln, "needs-asm-support"); - ignore |= !rustc_has_profiler_support && config.parse_needs_profiler_support(ln); - ignore |= !config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled"); - ignore |= !rustc_has_sanitizer_support - && config.parse_name_directive(ln, "needs-sanitizer-support"); - ignore |= !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address"); - ignore |= !has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi"); - ignore |= !has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi"); - ignore |= !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak"); - ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory"); - ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread"); - ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress"); - ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag"); - ignore |= !has_shadow_call_stack - && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack"); - ignore |= !config.can_unwind() && config.parse_name_directive(ln, "needs-unwind"); - ignore |= config.target == "wasm32-unknown-unknown" - && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS); - ignore |= config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln); - ignore |= config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln); - ignore |= config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln); - ignore |= !has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld"); + + reason!(ignore_llvm(config, ln)); + reason!( + config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln) + ); + reason!(!has_asm_support && config.parse_name_directive(ln, "needs-asm-support")); + reason!(!rustc_has_profiler_support && config.parse_needs_profiler_support(ln)); + reason!(!config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled")); + reason!( + !rustc_has_sanitizer_support + && config.parse_name_directive(ln, "needs-sanitizer-support") + ); + reason!(!has_asan && config.parse_name_directive(ln, "needs-sanitizer-address")); + reason!(!has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi")); + reason!(!has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi")); + reason!(!has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak")); + reason!(!has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory")); + reason!(!has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread")); + reason!(!has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress")); + reason!(!has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag")); + reason!( + !has_shadow_call_stack + && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack") + ); + reason!(!config.can_unwind() && config.parse_name_directive(ln, "needs-unwind")); + reason!( + config.target == "wasm32-unknown-unknown" + && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) + ); + reason!(config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln)); + reason!(config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln)); + reason!(config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln)); + reason!(!has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld")); should_fail |= config.parse_name_directive(ln, "should-fail"); }); diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 9c16ef2cbec..395bcc745f8 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -68,52 +68,6 @@ def load_json_from_response(resp): print("Refusing to decode " + str(type(content)) + " to str") return json.loads(content_str) -def validate_maintainers(repo, github_token): - # type: (str, str) -> None - '''Ensure all maintainers are assignable on a GitHub repo''' - next_link_re = re.compile(r'<([^>]+)>; rel="next"') - - # Load the list of assignable people in the GitHub repo - assignable = [] # type: typing.List[str] - url = 'https://api.github.com/repos/' \ - + '%s/collaborators?per_page=100' % repo # type: typing.Optional[str] - while url is not None: - response = urllib2.urlopen(urllib2.Request(url, headers={ - 'Authorization': 'token ' + github_token, - # Properly load nested teams. - 'Accept': 'application/vnd.github.hellcat-preview+json', - })) - assignable.extend(user['login'] for user in load_json_from_response(response)) - # Load the next page if available - url = None - link_header = response.headers.get('Link') - if link_header: - matches = next_link_re.match(link_header) - if matches is not None: - url = matches.group(1) - - errors = False - for tool, maintainers in MAINTAINERS.items(): - for maintainer in maintainers: - if maintainer not in assignable: - errors = True - print( - "error: %s maintainer @%s is not assignable in the %s repo" - % (tool, maintainer, repo), - ) - - if errors: - print() - print(" To be assignable, a person needs to be explicitly listed as a") - print(" collaborator in the repository settings. The simple way to") - print(" fix this is to ask someone with 'admin' privileges on the repo") - print(" to add the person or whole team as a collaborator with 'read'") - print(" privileges. Those privileges don't grant any extra permissions") - print(" so it's safe to apply them.") - print() - print("The build will fail due to this.") - exit(1) - def read_current_status(current_commit, path): # type: (str, str) -> typing.Mapping[str, typing.Any] @@ -280,21 +234,6 @@ def update_latest( try: if __name__ != '__main__': exit(0) - repo = os.environ.get('TOOLSTATE_VALIDATE_MAINTAINERS_REPO') - if repo: - github_token = os.environ.get('TOOLSTATE_REPO_ACCESS_TOKEN') - if github_token: - # FIXME: This is currently broken. Starting on 2021-09-15, GitHub - # seems to have changed it so that to list the collaborators - # requires admin permissions. I think this will probably just need - # to be removed since we are probably not going to use an admin - # token, and I don't see another way to do this. - print('maintainer validation disabled') - # validate_maintainers(repo, github_token) - else: - print('skipping toolstate maintainers validation since no GitHub token is present') - # When validating maintainers don't run the full script. - exit(0) cur_commit = sys.argv[1] cur_datetime = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') diff --git a/tests/debuginfo/embedded-visualizer.rs b/tests/debuginfo/embedded-visualizer.rs index 0269015b466..2898e75e0ee 100644 --- a/tests/debuginfo/embedded-visualizer.rs +++ b/tests/debuginfo/embedded-visualizer.rs @@ -1,6 +1,7 @@ // compile-flags:-g // min-gdb-version: 8.1 // ignore-lldb +// ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows // === CDB TESTS ================================================================================== diff --git a/tests/debuginfo/numeric-types.rs b/tests/debuginfo/numeric-types.rs index c41c9ee21df..c122112e6c7 100644 --- a/tests/debuginfo/numeric-types.rs +++ b/tests/debuginfo/numeric-types.rs @@ -1,6 +1,7 @@ // compile-flags:-g // min-gdb-version: 8.1 +// ignore-windows-gnu // emit_debug_gdb_scripts is disabled on Windows // Tests the visualizations for `NonZero{I,U}{8,16,32,64,128,size}`, `Wrapping` and // `Atomic{Bool,I8,I16,I32,I64,Isize,U8,U16,U32,U64,Usize}` located in `libcore.natvis`. diff --git a/tests/debuginfo/vec-slices.rs b/tests/debuginfo/vec-slices.rs index 7d88e45caf2..de4099a7f50 100644 --- a/tests/debuginfo/vec-slices.rs +++ b/tests/debuginfo/vec-slices.rs @@ -1,4 +1,3 @@ -// ignore-windows // min-lldb-version: 310 // compile-flags:-g diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff index dd548adde7e..5e587be1f16 100644 --- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff +++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff @@ -64,17 +64,8 @@ _3 = const 3_u8; // scope 2 at $DIR/const_debuginfo.rs:+3:13: +3:16 StorageLive(_4); // scope 3 at $DIR/const_debuginfo.rs:+4:9: +4:12 StorageLive(_5); // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20 - StorageLive(_6); // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:16 - _6 = const 1_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:16 - StorageLive(_7); // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20 - _7 = const 2_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20 _5 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:20 - StorageDead(_7); // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20 - StorageDead(_6); // scope 3 at $DIR/const_debuginfo.rs:+4:19: +4:20 - StorageLive(_8); // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24 - _8 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24 _4 = const 6_u8; // scope 3 at $DIR/const_debuginfo.rs:+4:15: +4:24 - StorageDead(_8); // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24 StorageDead(_5); // scope 3 at $DIR/const_debuginfo.rs:+4:23: +4:24 StorageLive(_9); // scope 4 at $DIR/const_debuginfo.rs:+6:9: +6:10 _9 = const "hello, world!"; // scope 4 at $DIR/const_debuginfo.rs:+6:13: +6:28 @@ -117,9 +108,6 @@ StorageDead(_16); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_9); // scope 4 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_4); // scope 3 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_3); // scope 2 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_2); // scope 1 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_1); // scope 0 at $DIR/const_debuginfo.rs:+14:1: +14:2 return; // scope 0 at $DIR/const_debuginfo.rs:+14:2: +14:2 } } diff --git a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff index 8485703e39f..e085a88b2da 100644 --- a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff @@ -21,32 +21,25 @@ StorageLive(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:9: +1:10 _1 = const 0_i32; // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:13: +1:14 StorageLive(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:9: +2:11 - StorageLive(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 -- _3 = _1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 -- _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 +- _4 = Eq(_1, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 - assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ _3 = const 0_i32; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 + _4 = const true; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 + assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 } bb1: { -- _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 + _5 = Eq(_1, const -1_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 - _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 - _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -- assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ _5 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 +- assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _1) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 + _6 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 + _7 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 ++ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _1) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 } bb2: { -- _2 = Rem(const 1_i32, move _3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 -+ _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 - StorageDead(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19 + _2 = Rem(const 1_i32, _1); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19 StorageDead(_2); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2 - StorageDead(_1); // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2 return; // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:2: +3:2 } } diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff index 27e41d4869d..38d402b8f21 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff @@ -23,24 +23,21 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10 StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - StorageLive(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 _8 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) } - _3 = _8; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 + _2 = &raw const (*_8); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 StorageDead(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35 - StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36 StorageLive(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15 StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 _5 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 - _6 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 + _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - _7 = Lt(_5, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ _7 = Lt(const 3_usize, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 ++ _7 = const false; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 ++ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff index 27e41d4869d..38d402b8f21 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff @@ -23,24 +23,21 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10 StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - StorageLive(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 _8 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) } - _3 = _8; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 - _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 + _2 = &raw const (*_8); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35 StorageDead(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35 - StorageDead(_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36 StorageLive(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15 StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 _5 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 - _6 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 + _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - _7 = Lt(_5, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ _7 = Lt(const 3_usize, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 ++ _7 = const false; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 ++ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 } bb1: { diff --git a/tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff b/tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff index 0de80091753..549b4711e87 100644 --- a/tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff +++ b/tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff @@ -12,18 +12,12 @@ bb0: { StorageLive(_3); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15 - StorageLive(_4); // scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7 - _4 = _2; // scope 0 at $DIR/boolean_identities.rs:+1:6: +1:7 -- _3 = BitOr(move _4, const true); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15 +- _3 = BitOr(_2, const true); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15 + _3 = const true; // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:15 - StorageDead(_4); // scope 0 at $DIR/boolean_identities.rs:+1:14: +1:15 StorageLive(_5); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 - StorageLive(_6); // scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20 - _6 = _1; // scope 0 at $DIR/boolean_identities.rs:+1:19: +1:20 -- _5 = BitAnd(move _6, const false); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 -+ _5 = const false; // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 - StorageDead(_6); // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29 +- _5 = BitAnd(_1, const false); // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 - _0 = BitAnd(move _3, move _5); // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:29 ++ _5 = const false; // scope 0 at $DIR/boolean_identities.rs:+1:18: +1:29 + _0 = const false; // scope 0 at $DIR/boolean_identities.rs:+1:5: +1:29 StorageDead(_5); // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29 StorageDead(_3); // scope 0 at $DIR/boolean_identities.rs:+1:28: +1:29 diff --git a/tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff b/tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff index 629c8e60148..1cfe47d0a86 100644 --- a/tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff +++ b/tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff @@ -7,11 +7,8 @@ let mut _2: i32; // in scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4 bb0: { - StorageLive(_2); // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4 - _2 = _1; // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:4 -- _0 = Mul(move _2, const 0_i32); // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8 +- _0 = Mul(_1, const 0_i32); // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8 + _0 = const 0_i32; // scope 0 at $DIR/mult_by_zero.rs:+1:3: +1:8 - StorageDead(_2); // scope 0 at $DIR/mult_by_zero.rs:+1:7: +1:8 return; // scope 0 at $DIR/mult_by_zero.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff index 8a73f0390e1..924a267f3d8 100644 --- a/tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff @@ -13,14 +13,13 @@ StorageLive(_2); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 _4 = const _; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 // mir::Constant - // + span: $DIR/ref_deref.rs:6:6: 6:10 + // + span: $DIR/ref_deref.rs:5:6: 5:10 // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } - _2 = _4; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 -- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 -+ _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 + _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 + _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - nop; // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2 return; // scope 0 at $DIR/ref_deref.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/tests/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff deleted file mode 100644 index 015ec4d078c..00000000000 --- a/tests/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff +++ /dev/null @@ -1,30 +0,0 @@ -- // MIR for `main` before PromoteTemps -+ // MIR for `main` after PromoteTemps - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/ref_deref.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 - let mut _2: &i32; // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 - let _3: i32; // in scope 0 at $DIR/ref_deref.rs:+1:8: +1:9 -+ let mut _4: &i32; // in scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 - - bb0: { - StorageLive(_1); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 - StorageLive(_2); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 -- StorageLive(_3); // scope 0 at $DIR/ref_deref.rs:+1:8: +1:9 -- _3 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:+1:8: +1:9 -- _2 = &_3; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 -+ _4 = const _; // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 -+ // mir::Constant -+ // + span: $DIR/ref_deref.rs:6:6: 6:10 -+ // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } -+ _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:+1:6: +1:10 - _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:+1:5: +1:10 -- StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - StorageDead(_2); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - StorageDead(_1); // scope 0 at $DIR/ref_deref.rs:+1:10: +1:11 - _0 = const (); // scope 0 at $DIR/ref_deref.rs:+0:11: +2:2 - return; // scope 0 at $DIR/ref_deref.rs:+2:2: +2:2 - } - } - diff --git a/tests/mir-opt/const_prop/ref_deref.rs b/tests/mir-opt/const_prop/ref_deref.rs index d2549c8b6aa..76e56916af0 100644 --- a/tests/mir-opt/const_prop/ref_deref.rs +++ b/tests/mir-opt/const_prop/ref_deref.rs @@ -1,5 +1,4 @@ -// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop -// EMIT_MIR ref_deref.main.PromoteTemps.diff +// unit-test: ConstProp // EMIT_MIR ref_deref.main.ConstProp.diff fn main() { diff --git a/tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff index ec3d9043315..59095b44837 100644 --- a/tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff @@ -13,13 +13,13 @@ StorageLive(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 _4 = const _; // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 // mir::Constant - // + span: $DIR/ref_deref_project.rs:6:6: 6:17 + // + span: $DIR/ref_deref_project.rs:5:6: 5:17 // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) } _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - nop; // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2 return; // scope 0 at $DIR/ref_deref_project.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/tests/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff deleted file mode 100644 index cd0616e65ba..00000000000 --- a/tests/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff +++ /dev/null @@ -1,30 +0,0 @@ -- // MIR for `main` before PromoteTemps -+ // MIR for `main` after PromoteTemps - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/ref_deref_project.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 - let mut _2: &i32; // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 - let _3: (i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14 -+ let mut _4: &(i32, i32); // in scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 - - bb0: { - StorageLive(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 - StorageLive(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 -- StorageLive(_3); // scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14 -- _3 = (const 4_i32, const 5_i32); // scope 0 at $DIR/ref_deref_project.rs:+1:8: +1:14 -- _2 = &(_3.1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 -+ _4 = const _; // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 -+ // mir::Constant -+ // + span: $DIR/ref_deref_project.rs:6:6: 6:17 -+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) } -+ _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 - _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 -- StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - StorageDead(_1); // scope 0 at $DIR/ref_deref_project.rs:+1:17: +1:18 - _0 = const (); // scope 0 at $DIR/ref_deref_project.rs:+0:11: +2:2 - return; // scope 0 at $DIR/ref_deref_project.rs:+2:2: +2:2 - } - } - diff --git a/tests/mir-opt/const_prop/ref_deref_project.rs b/tests/mir-opt/const_prop/ref_deref_project.rs index 2fdd4e15319..04fc7f8daa1 100644 --- a/tests/mir-opt/const_prop/ref_deref_project.rs +++ b/tests/mir-opt/const_prop/ref_deref_project.rs @@ -1,5 +1,4 @@ -// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop -// EMIT_MIR ref_deref_project.main.PromoteTemps.diff +// unit-test: ConstProp // EMIT_MIR ref_deref_project.main.ConstProp.diff fn main() { diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff index d518eff04eb..e3f5b120a32 100644 --- a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff @@ -14,10 +14,7 @@ StorageLive(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:+1:9: +1:10 _1 = const 1_u32; // scope 0 at $DIR/scalar_literal_propagation.rs:+1:13: +1:14 StorageLive(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 - StorageLive(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14 -- _3 = _1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14 -- _2 = consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 -+ _3 = const 1_u32; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14 +- _2 = consume(_1) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 + _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15 // mir::Constant // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:12 @@ -25,9 +22,7 @@ } bb1: { - StorageDead(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:14: +2:15 StorageDead(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16 - StorageDead(_1); // scope 0 at $DIR/scalar_literal_propagation.rs:+3:1: +3:2 return; // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2 } } diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff index 9017fd18e48..b99b83b0cba 100644 --- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff @@ -20,7 +20,7 @@ StorageLive(_4); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 _9 = const _; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 // mir::Constant - // + span: $DIR/slice_len.rs:6:6: 6:19 + // + span: $DIR/slice_len.rs:7:6: 7:19 // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) } _4 = _9; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 @@ -33,7 +33,7 @@ - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 + _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 + _8 = const true; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 } bb1: { @@ -43,7 +43,7 @@ StorageDead(_4); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 StorageDead(_2); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 StorageDead(_1); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 - nop; // scope 0 at $DIR/slice_len.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/slice_len.rs:+0:11: +2:2 return; // scope 0 at $DIR/slice_len.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff index 9017fd18e48..b99b83b0cba 100644 --- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff @@ -20,7 +20,7 @@ StorageLive(_4); // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 _9 = const _; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 // mir::Constant - // + span: $DIR/slice_len.rs:6:6: 6:19 + // + span: $DIR/slice_len.rs:7:6: 7:19 // + literal: Const { ty: &[u32; 3], val: Unevaluated(main, [], Some(promoted[0])) } _4 = _9; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:+1:6: +1:19 @@ -33,7 +33,7 @@ - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 + _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 + _8 = const true; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:+1:5: +1:33 } bb1: { @@ -43,7 +43,7 @@ StorageDead(_4); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 StorageDead(_2); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 StorageDead(_1); // scope 0 at $DIR/slice_len.rs:+1:33: +1:34 - nop; // scope 0 at $DIR/slice_len.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/slice_len.rs:+0:11: +2:2 return; // scope 0 at $DIR/slice_len.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_prop/slice_len.rs b/tests/mir-opt/const_prop/slice_len.rs index eaaf34b960e..8183def0c63 100644 --- a/tests/mir-opt/const_prop/slice_len.rs +++ b/tests/mir-opt/const_prop/slice_len.rs @@ -1,4 +1,5 @@ -// compile-flags: -Zmir-enable-passes=-SimplifyLocals-before-const-prop +// unit-test: ConstProp +// compile-flags: -Zmir-enable-passes=+InstCombine // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR slice_len.main.ConstProp.diff diff --git a/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff b/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff index ea9fec0aa15..b6b542fb794 100644 --- a/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff +++ b/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff @@ -4,15 +4,16 @@ fn bar() -> () { let mut _0: (); // return place in scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +0:10 let mut _1: (i32,); // in scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14 - let mut _2: *mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 - let mut _4: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20 + let _2: (); // in scope 0 at $DIR/const_prop_miscompile.rs:+2:5: +4:6 + let mut _3: *mut i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 + let mut _5: i32; // in scope 0 at $DIR/const_prop_miscompile.rs:+5:13: +5:20 scope 1 { debug v => _1; // in scope 1 at $DIR/const_prop_miscompile.rs:+1:9: +1:14 - let _3: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 + let _4: bool; // in scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 scope 2 { } scope 3 { - debug y => _3; // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 + debug y => _4; // in scope 3 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 } } @@ -20,16 +21,20 @@ StorageLive(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14 Deinit(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21 (_1.0: i32) = const 1_i32; // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21 - StorageLive(_2); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 - _2 = &raw mut (_1.0: i32); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 - (*_2) = const 5_i32; // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26 - StorageDead(_2); // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27 - StorageLive(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 - StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20 - _4 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18 - _3 = Eq(move _4, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25 - StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25 - StorageDead(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2 + StorageLive(_2); // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +4:6 + StorageLive(_3); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 + _3 = &raw mut (_1.0: i32); // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22 + (*_3) = const 5_i32; // scope 2 at $DIR/const_prop_miscompile.rs:+3:9: +3:26 + StorageDead(_3); // scope 2 at $DIR/const_prop_miscompile.rs:+3:26: +3:27 + _2 = const (); // scope 2 at $DIR/const_prop_miscompile.rs:+2:5: +4:6 + StorageDead(_2); // scope 1 at $DIR/const_prop_miscompile.rs:+4:5: +4:6 + StorageLive(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+5:9: +5:10 + StorageLive(_5); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:20 + _5 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:15: +5:18 + _4 = Eq(move _5, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+5:13: +5:25 + StorageDead(_5); // scope 1 at $DIR/const_prop_miscompile.rs:+5:24: +5:25 + _0 = const (); // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +6:2 + StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+6:1: +6:2 StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+6:1: +6:2 return; // scope 0 at $DIR/const_prop_miscompile.rs:+6:2: +6:2 } diff --git a/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff b/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff index 043f4047417..e43735fd9e1 100644 --- a/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff +++ b/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff @@ -27,6 +27,7 @@ _4 = (_1.0: i32); // scope 1 at $DIR/const_prop_miscompile.rs:+3:15: +3:18 _3 = Eq(move _4, const 5_i32); // scope 1 at $DIR/const_prop_miscompile.rs:+3:13: +3:25 StorageDead(_4); // scope 1 at $DIR/const_prop_miscompile.rs:+3:24: +3:25 + _0 = const (); // scope 0 at $DIR/const_prop_miscompile.rs:+0:10: +4:2 StorageDead(_3); // scope 1 at $DIR/const_prop_miscompile.rs:+4:1: +4:2 StorageDead(_1); // scope 0 at $DIR/const_prop_miscompile.rs:+4:1: +4:2 return; // scope 0 at $DIR/const_prop_miscompile.rs:+4:2: +4:2 diff --git a/tests/mir-opt/const_prop_miscompile.rs b/tests/mir-opt/const_prop_miscompile.rs index bc54556b349..dbbe5ee0840 100644 --- a/tests/mir-opt/const_prop_miscompile.rs +++ b/tests/mir-opt/const_prop_miscompile.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp #![feature(raw_ref_op)] // EMIT_MIR const_prop_miscompile.foo.ConstProp.diff diff --git a/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff b/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff new file mode 100644 index 00000000000..b183865a9bc --- /dev/null +++ b/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff @@ -0,0 +1,34 @@ +- // MIR for `f` before CopyProp ++ // MIR for `f` after CopyProp + + fn f() -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/borrowed_local.rs:+0:11: +0:15 + let mut _1: u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _2: &u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _3: u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _4: &u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + _1 = const 5_u8; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _2 = &_1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _3 = _1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _4 = &_3; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _0 = cmp_ref(_2, _4) -> bb1; // scope 0 at $DIR/borrowed_local.rs:+8:13: +8:45 + // mir::Constant + // + span: $DIR/borrowed_local.rs:23:29: 23:36 + // + literal: Const { ty: for<'a, 'b> fn(&'a u8, &'b u8) -> bool {cmp_ref}, val: Value() } + } + + bb1: { +- _0 = opaque::(_3) -> bb2; // scope 0 at $DIR/borrowed_local.rs:+12:13: +12:38 ++ _0 = opaque::(_1) -> bb2; // scope 0 at $DIR/borrowed_local.rs:+12:13: +12:38 + // mir::Constant + // + span: $DIR/borrowed_local.rs:27:28: 27:34 + // + literal: Const { ty: fn(u8) -> bool {opaque::}, val: Value() } + } + + bb2: { + return; // scope 0 at $DIR/borrowed_local.rs:+15:13: +15:21 + } + } + diff --git a/tests/mir-opt/copy-prop/borrowed_local.rs b/tests/mir-opt/copy-prop/borrowed_local.rs new file mode 100644 index 00000000000..c4b980e2b35 --- /dev/null +++ b/tests/mir-opt/copy-prop/borrowed_local.rs @@ -0,0 +1,39 @@ +// unit-test: CopyProp + +#![feature(custom_mir, core_intrinsics)] +#![allow(unused_assignments)] +extern crate core; +use core::intrinsics::mir::*; + +fn opaque(_: impl Sized) -> bool { true } + +fn cmp_ref(a: &u8, b: &u8) -> bool { + std::ptr::eq(a as *const u8, b as *const u8) +} + +#[custom_mir(dialect = "analysis", phase = "post-cleanup")] +fn f() -> bool { + mir!( + { + let a = 5_u8; + let r1 = &a; + let b = a; + // We cannot propagate the place `a`. + let r2 = &b; + Call(RET, next, cmp_ref(r1, r2)) + } + next = { + // But we can propagate the value `a`. + Call(RET, ret, opaque(b)) + } + ret = { + Return() + } + ) +} + +fn main() { + assert!(!f()); +} + +// EMIT_MIR borrowed_local.f.CopyProp.diff diff --git a/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff b/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff new file mode 100644 index 00000000000..8b116532d9f --- /dev/null +++ b/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff @@ -0,0 +1,65 @@ +- // MIR for `foo` before CopyProp ++ // MIR for `foo` after CopyProp + + fn foo() -> i32 { + let mut _0: i32; // return place in scope 0 at $DIR/branch.rs:+0:13: +0:16 + let _1: i32; // in scope 0 at $DIR/branch.rs:+1:9: +1:10 + let mut _3: bool; // in scope 0 at $DIR/branch.rs:+3:16: +3:22 + let _4: i32; // in scope 0 at $DIR/branch.rs:+6:9: +6:14 + scope 1 { + debug x => _1; // in scope 1 at $DIR/branch.rs:+1:9: +1:10 + let _2: i32; // in scope 1 at $DIR/branch.rs:+3:9: +3:10 + scope 2 { + debug y => _2; // in scope 2 at $DIR/branch.rs:+3:9: +3:10 + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/branch.rs:+1:9: +1:10 + _1 = val() -> bb1; // scope 0 at $DIR/branch.rs:+1:13: +1:18 + // mir::Constant + // + span: $DIR/branch.rs:13:13: 13:16 + // + literal: Const { ty: fn() -> i32 {val}, val: Value() } + } + + bb1: { + StorageLive(_2); // scope 1 at $DIR/branch.rs:+3:9: +3:10 + StorageLive(_3); // scope 1 at $DIR/branch.rs:+3:16: +3:22 + _3 = cond() -> bb2; // scope 1 at $DIR/branch.rs:+3:16: +3:22 + // mir::Constant + // + span: $DIR/branch.rs:15:16: 15:20 + // + literal: Const { ty: fn() -> bool {cond}, val: Value() } + } + + bb2: { + switchInt(move _3) -> [0: bb4, otherwise: bb3]; // scope 1 at $DIR/branch.rs:+3:16: +3:22 + } + + bb3: { + _2 = _1; // scope 1 at $DIR/branch.rs:+4:9: +4:10 + goto -> bb6; // scope 1 at $DIR/branch.rs:+3:13: +8:6 + } + + bb4: { + StorageLive(_4); // scope 1 at $DIR/branch.rs:+6:9: +6:14 + _4 = val() -> bb5; // scope 1 at $DIR/branch.rs:+6:9: +6:14 + // mir::Constant + // + span: $DIR/branch.rs:18:9: 18:12 + // + literal: Const { ty: fn() -> i32 {val}, val: Value() } + } + + bb5: { + StorageDead(_4); // scope 1 at $DIR/branch.rs:+6:14: +6:15 + _2 = _1; // scope 1 at $DIR/branch.rs:+7:9: +7:10 + goto -> bb6; // scope 1 at $DIR/branch.rs:+3:13: +8:6 + } + + bb6: { + StorageDead(_3); // scope 1 at $DIR/branch.rs:+8:5: +8:6 + _0 = _2; // scope 2 at $DIR/branch.rs:+10:5: +10:6 + StorageDead(_2); // scope 1 at $DIR/branch.rs:+11:1: +11:2 + StorageDead(_1); // scope 0 at $DIR/branch.rs:+11:1: +11:2 + return; // scope 0 at $DIR/branch.rs:+11:2: +11:2 + } + } + diff --git a/tests/mir-opt/copy-prop/branch.rs b/tests/mir-opt/copy-prop/branch.rs new file mode 100644 index 00000000000..50b1e00fad4 --- /dev/null +++ b/tests/mir-opt/copy-prop/branch.rs @@ -0,0 +1,27 @@ +//! Tests that we bail out when there are multiple assignments to the same local. +// unit-test: CopyProp +fn val() -> i32 { + 1 +} + +fn cond() -> bool { + true +} + +// EMIT_MIR branch.foo.CopyProp.diff +fn foo() -> i32 { + let x = val(); + + let y = if cond() { + x + } else { + val(); + x + }; + + y +} + +fn main() { + foo(); +} diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff new file mode 100644 index 00000000000..69acebf7642 --- /dev/null +++ b/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff @@ -0,0 +1,21 @@ +- // MIR for `arg_src` before CopyProp ++ // MIR for `arg_src` after CopyProp + + fn arg_src(_1: i32) -> i32 { + debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:12: +0:17 + let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:27: +0:30 + let _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 + scope 1 { + debug y => _2; // in scope 1 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 + _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14 + _1 = const 123_i32; // scope 1 at $DIR/copy_propagation_arg.rs:+2:5: +2:12 + _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:+3:5: +3:6 + StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+4:1: +4:2 + return; // scope 0 at $DIR/copy_propagation_arg.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff new file mode 100644 index 00000000000..ac4e9a2bfa7 --- /dev/null +++ b/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff @@ -0,0 +1,28 @@ +- // MIR for `bar` before CopyProp ++ // MIR for `bar` after CopyProp + + fn bar(_1: u8) -> () { + debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13 + let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +0:19 + let _2: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13 + let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13 + StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12 + _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12 + _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:5: +1:13 + // mir::Constant + // + span: $DIR/copy_propagation_arg.rs:16:5: 16:10 + // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value() } + } + + bb1: { + StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+1:12: +1:13 + StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14 + _1 = const 5_u8; // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:10 + _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +3:2 + return; // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2 + } + } + diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.baz.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.baz.CopyProp.diff new file mode 100644 index 00000000000..7ab6ebb7d53 --- /dev/null +++ b/tests/mir-opt/copy-prop/copy_propagation_arg.baz.CopyProp.diff @@ -0,0 +1,18 @@ +- // MIR for `baz` before CopyProp ++ // MIR for `baz` after CopyProp + + fn baz(_1: i32) -> i32 { + debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13 + let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:23: +0:26 + let mut _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10 + _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10 + _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:10 + StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:10 + _0 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+3:5: +3:6 + return; // scope 0 at $DIR/copy_propagation_arg.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff new file mode 100644 index 00000000000..0a3e985e7c2 --- /dev/null +++ b/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff @@ -0,0 +1,28 @@ +- // MIR for `foo` before CopyProp ++ // MIR for `foo` after CopyProp + + fn foo(_1: u8) -> () { + debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:+0:8: +0:13 + let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +0:19 + let mut _2: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17 + let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17 + StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16 + _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+2:15: +2:16 + _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17 + // mir::Constant + // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14 + // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value() } + } + + bb1: { + StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:+2:16: +2:17 + _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:+2:5: +2:17 + StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+2:16: +2:17 + _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:+0:19: +3:2 + return; // scope 0 at $DIR/copy_propagation_arg.rs:+3:2: +3:2 + } + } + diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.rs b/tests/mir-opt/copy-prop/copy_propagation_arg.rs new file mode 100644 index 00000000000..cc98985f1fd --- /dev/null +++ b/tests/mir-opt/copy-prop/copy_propagation_arg.rs @@ -0,0 +1,40 @@ +// Check that CopyProp does not propagate an assignment to a function argument +// (doing so can break usages of the original argument value) +// unit-test: CopyProp +fn dummy(x: u8) -> u8 { + x +} + +// EMIT_MIR copy_propagation_arg.foo.CopyProp.diff +fn foo(mut x: u8) { + // calling `dummy` to make a use of `x` that copyprop cannot eliminate + x = dummy(x); // this will assign a local to `x` +} + +// EMIT_MIR copy_propagation_arg.bar.CopyProp.diff +fn bar(mut x: u8) { + dummy(x); + x = 5; +} + +// EMIT_MIR copy_propagation_arg.baz.CopyProp.diff +fn baz(mut x: i32) -> i32 { + // self-assignment to a function argument should be eliminated + x = x; + x +} + +// EMIT_MIR copy_propagation_arg.arg_src.CopyProp.diff +fn arg_src(mut x: i32) -> i32 { + let y = x; + x = 123; // Don't propagate this assignment to `y` + y +} + +fn main() { + // Make sure the function actually gets instantiated. + foo(0); + bar(0); + baz(0); + arg_src(0); +} diff --git a/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff b/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff new file mode 100644 index 00000000000..bc5083e1ad0 --- /dev/null +++ b/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff @@ -0,0 +1,60 @@ +- // MIR for `main` before CopyProp ++ // MIR for `main` after CopyProp + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:+0:11: +0:11 + let mut _1: i32; // in scope 0 at $DIR/cycle.rs:+1:9: +1:14 + let mut _4: i32; // in scope 0 at $DIR/cycle.rs:+4:9: +4:10 + let _5: (); // in scope 0 at $DIR/cycle.rs:+6:5: +6:12 + let mut _6: i32; // in scope 0 at $DIR/cycle.rs:+6:10: +6:11 + scope 1 { + debug x => _1; // in scope 1 at $DIR/cycle.rs:+1:9: +1:14 + let _2: i32; // in scope 1 at $DIR/cycle.rs:+2:9: +2:10 + scope 2 { + debug y => _2; // in scope 2 at $DIR/cycle.rs:+2:9: +2:10 + let _3: i32; // in scope 2 at $DIR/cycle.rs:+3:9: +3:10 + scope 3 { +- debug z => _3; // in scope 3 at $DIR/cycle.rs:+3:9: +3:10 ++ debug z => _2; // in scope 3 at $DIR/cycle.rs:+3:9: +3:10 + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/cycle.rs:+1:9: +1:14 + _1 = val() -> bb1; // scope 0 at $DIR/cycle.rs:+1:17: +1:22 + // mir::Constant + // + span: $DIR/cycle.rs:9:17: 9:20 + // + literal: Const { ty: fn() -> i32 {val}, val: Value() } + } + + bb1: { + StorageLive(_2); // scope 1 at $DIR/cycle.rs:+2:9: +2:10 + _2 = _1; // scope 1 at $DIR/cycle.rs:+2:13: +2:14 +- StorageLive(_3); // scope 2 at $DIR/cycle.rs:+3:9: +3:10 +- _3 = _2; // scope 2 at $DIR/cycle.rs:+3:13: +3:14 +- StorageLive(_4); // scope 3 at $DIR/cycle.rs:+4:9: +4:10 +- _4 = _3; // scope 3 at $DIR/cycle.rs:+4:9: +4:10 +- _1 = move _4; // scope 3 at $DIR/cycle.rs:+4:5: +4:10 +- StorageDead(_4); // scope 3 at $DIR/cycle.rs:+4:9: +4:10 ++ _1 = _2; // scope 3 at $DIR/cycle.rs:+4:5: +4:10 + StorageLive(_5); // scope 3 at $DIR/cycle.rs:+6:5: +6:12 + StorageLive(_6); // scope 3 at $DIR/cycle.rs:+6:10: +6:11 + _6 = _1; // scope 3 at $DIR/cycle.rs:+6:10: +6:11 + _5 = std::mem::drop::(move _6) -> bb2; // scope 3 at $DIR/cycle.rs:+6:5: +6:12 + // mir::Constant + // + span: $DIR/cycle.rs:14:5: 14:9 + // + literal: Const { ty: fn(i32) {std::mem::drop::}, val: Value() } + } + + bb2: { + StorageDead(_6); // scope 3 at $DIR/cycle.rs:+6:11: +6:12 + StorageDead(_5); // scope 3 at $DIR/cycle.rs:+6:12: +6:13 + _0 = const (); // scope 0 at $DIR/cycle.rs:+0:11: +7:2 +- StorageDead(_3); // scope 2 at $DIR/cycle.rs:+7:1: +7:2 +- StorageDead(_2); // scope 1 at $DIR/cycle.rs:+7:1: +7:2 + StorageDead(_1); // scope 0 at $DIR/cycle.rs:+7:1: +7:2 + return; // scope 0 at $DIR/cycle.rs:+7:2: +7:2 + } + } + diff --git a/tests/mir-opt/copy-prop/cycle.rs b/tests/mir-opt/copy-prop/cycle.rs new file mode 100644 index 00000000000..b74c397269d --- /dev/null +++ b/tests/mir-opt/copy-prop/cycle.rs @@ -0,0 +1,15 @@ +//! Tests that cyclic assignments don't hang CopyProp, and result in reasonable code. +// unit-test: CopyProp +fn val() -> i32 { + 1 +} + +// EMIT_MIR cycle.main.CopyProp.diff +fn main() { + let mut x = val(); + let y = x; + let z = y; + x = z; + + drop(x); +} diff --git a/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir b/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir new file mode 100644 index 00000000000..918817da56c --- /dev/null +++ b/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.mir @@ -0,0 +1,30 @@ +// MIR for `f` after CopyProp + +fn f(_1: usize) -> usize { + debug a => _1; // in scope 0 at $DIR/dead_stores_79191.rs:+0:6: +0:11 + let mut _0: usize; // return place in scope 0 at $DIR/dead_stores_79191.rs:+0:23: +0:28 + let _2: usize; // in scope 0 at $DIR/dead_stores_79191.rs:+1:9: +1:10 + let mut _3: usize; // in scope 0 at $DIR/dead_stores_79191.rs:+3:9: +3:10 + let mut _4: usize; // in scope 0 at $DIR/dead_stores_79191.rs:+4:8: +4:9 + scope 1 { + debug b => _2; // in scope 1 at $DIR/dead_stores_79191.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/dead_stores_79191.rs:+1:9: +1:10 + _2 = _1; // scope 0 at $DIR/dead_stores_79191.rs:+1:13: +1:14 + _1 = const 5_usize; // scope 1 at $DIR/dead_stores_79191.rs:+2:5: +2:10 + _1 = _2; // scope 1 at $DIR/dead_stores_79191.rs:+3:5: +3:10 + StorageLive(_4); // scope 1 at $DIR/dead_stores_79191.rs:+4:8: +4:9 + _4 = _1; // scope 1 at $DIR/dead_stores_79191.rs:+4:8: +4:9 + _0 = id::(move _4) -> bb1; // scope 1 at $DIR/dead_stores_79191.rs:+4:5: +4:10 + // mir::Constant + // + span: $DIR/dead_stores_79191.rs:12:5: 12:7 + // + literal: Const { ty: fn(usize) -> usize {id::}, val: Value() } + } + + bb1: { + StorageDead(_4); // scope 1 at $DIR/dead_stores_79191.rs:+4:9: +4:10 + return; // scope 0 at $DIR/dead_stores_79191.rs:+5:2: +5:2 + } +} diff --git a/tests/mir-opt/copy-prop/dead_stores_79191.rs b/tests/mir-opt/copy-prop/dead_stores_79191.rs new file mode 100644 index 00000000000..e3493b8b7a1 --- /dev/null +++ b/tests/mir-opt/copy-prop/dead_stores_79191.rs @@ -0,0 +1,17 @@ +// unit-test: CopyProp + +fn id(x: T) -> T { + x +} + +// EMIT_MIR dead_stores_79191.f.CopyProp.after.mir +fn f(mut a: usize) -> usize { + let b = a; + a = 5; + a = b; + id(a) +} + +fn main() { + f(0); +} diff --git a/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir b/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir new file mode 100644 index 00000000000..cf21fadd437 --- /dev/null +++ b/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.mir @@ -0,0 +1,30 @@ +// MIR for `f` after CopyProp + +fn f(_1: usize) -> usize { + debug a => _1; // in scope 0 at $DIR/dead_stores_better.rs:+0:10: +0:15 + let mut _0: usize; // return place in scope 0 at $DIR/dead_stores_better.rs:+0:27: +0:32 + let _2: usize; // in scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10 + let mut _3: usize; // in scope 0 at $DIR/dead_stores_better.rs:+3:9: +3:10 + let mut _4: usize; // in scope 0 at $DIR/dead_stores_better.rs:+4:8: +4:9 + scope 1 { + debug b => _2; // in scope 1 at $DIR/dead_stores_better.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/dead_stores_better.rs:+1:9: +1:10 + _2 = _1; // scope 0 at $DIR/dead_stores_better.rs:+1:13: +1:14 + _1 = const 5_usize; // scope 1 at $DIR/dead_stores_better.rs:+2:5: +2:10 + _1 = _2; // scope 1 at $DIR/dead_stores_better.rs:+3:5: +3:10 + StorageLive(_4); // scope 1 at $DIR/dead_stores_better.rs:+4:8: +4:9 + _4 = _1; // scope 1 at $DIR/dead_stores_better.rs:+4:8: +4:9 + _0 = id::(move _4) -> bb1; // scope 1 at $DIR/dead_stores_better.rs:+4:5: +4:10 + // mir::Constant + // + span: $DIR/dead_stores_better.rs:16:5: 16:7 + // + literal: Const { ty: fn(usize) -> usize {id::}, val: Value() } + } + + bb1: { + StorageDead(_4); // scope 1 at $DIR/dead_stores_better.rs:+4:9: +4:10 + return; // scope 0 at $DIR/dead_stores_better.rs:+5:2: +5:2 + } +} diff --git a/tests/mir-opt/copy-prop/dead_stores_better.rs b/tests/mir-opt/copy-prop/dead_stores_better.rs new file mode 100644 index 00000000000..8465b3c9853 --- /dev/null +++ b/tests/mir-opt/copy-prop/dead_stores_better.rs @@ -0,0 +1,21 @@ +// This is a copy of the `dead_stores_79191` test, except that we turn on DSE. This demonstrates +// that that pass enables this one to do more optimizations. + +// unit-test: CopyProp +// compile-flags: -Zmir-enable-passes=+DeadStoreElimination + +fn id(x: T) -> T { + x +} + +// EMIT_MIR dead_stores_better.f.CopyProp.after.mir +pub fn f(mut a: usize) -> usize { + let b = a; + a = 5; + a = b; + id(a) +} + +fn main() { + f(0); +} diff --git a/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff b/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff new file mode 100644 index 00000000000..d76bf1cfe7e --- /dev/null +++ b/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff @@ -0,0 +1,40 @@ +- // MIR for `f` before CopyProp ++ // MIR for `f` after CopyProp + + fn f(_1: T) -> () { + debug a => _1; // in scope 0 at $DIR/move_arg.rs:+0:19: +0:20 + let mut _0: (); // return place in scope 0 at $DIR/move_arg.rs:+0:25: +0:25 + let _2: T; // in scope 0 at $DIR/move_arg.rs:+1:9: +1:10 + let _3: (); // in scope 0 at $DIR/move_arg.rs:+2:5: +2:12 + let mut _4: T; // in scope 0 at $DIR/move_arg.rs:+2:7: +2:8 + let mut _5: T; // in scope 0 at $DIR/move_arg.rs:+2:10: +2:11 + scope 1 { +- debug b => _2; // in scope 1 at $DIR/move_arg.rs:+1:9: +1:10 ++ debug b => _1; // in scope 1 at $DIR/move_arg.rs:+1:9: +1:10 + } + + bb0: { +- StorageLive(_2); // scope 0 at $DIR/move_arg.rs:+1:9: +1:10 +- _2 = _1; // scope 0 at $DIR/move_arg.rs:+1:13: +1:14 + StorageLive(_3); // scope 1 at $DIR/move_arg.rs:+2:5: +2:12 +- StorageLive(_4); // scope 1 at $DIR/move_arg.rs:+2:7: +2:8 +- _4 = _1; // scope 1 at $DIR/move_arg.rs:+2:7: +2:8 +- StorageLive(_5); // scope 1 at $DIR/move_arg.rs:+2:10: +2:11 +- _5 = _2; // scope 1 at $DIR/move_arg.rs:+2:10: +2:11 +- _3 = g::(move _4, move _5) -> bb1; // scope 1 at $DIR/move_arg.rs:+2:5: +2:12 ++ _3 = g::(_1, _1) -> bb1; // scope 1 at $DIR/move_arg.rs:+2:5: +2:12 + // mir::Constant + // + span: $DIR/move_arg.rs:7:5: 7:6 + // + literal: Const { ty: fn(T, T) {g::}, val: Value() } + } + + bb1: { +- StorageDead(_5); // scope 1 at $DIR/move_arg.rs:+2:11: +2:12 +- StorageDead(_4); // scope 1 at $DIR/move_arg.rs:+2:11: +2:12 + StorageDead(_3); // scope 1 at $DIR/move_arg.rs:+2:12: +2:13 + _0 = const (); // scope 0 at $DIR/move_arg.rs:+0:25: +3:2 +- StorageDead(_2); // scope 0 at $DIR/move_arg.rs:+3:1: +3:2 + return; // scope 0 at $DIR/move_arg.rs:+3:2: +3:2 + } + } + diff --git a/tests/mir-opt/copy-prop/move_arg.rs b/tests/mir-opt/copy-prop/move_arg.rs new file mode 100644 index 00000000000..40ae1d8f466 --- /dev/null +++ b/tests/mir-opt/copy-prop/move_arg.rs @@ -0,0 +1,15 @@ +// Test that we do not move multiple times from the same local. +// unit-test: CopyProp + +// EMIT_MIR move_arg.f.CopyProp.diff +pub fn f(a: T) { + let b = a; + g(a, b); +} + +#[inline(never)] +pub fn g(_: T, _: T) {} + +fn main() { + f(5) +} diff --git a/tests/mir-opt/copy-prop/mutate_through_pointer.f.CopyProp.diff b/tests/mir-opt/copy-prop/mutate_through_pointer.f.CopyProp.diff new file mode 100644 index 00000000000..61fdd6f8c05 --- /dev/null +++ b/tests/mir-opt/copy-prop/mutate_through_pointer.f.CopyProp.diff @@ -0,0 +1,19 @@ +- // MIR for `f` before CopyProp ++ // MIR for `f` after CopyProp + + fn f(_1: bool) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/mutate_through_pointer.rs:+0:18: +0:22 + let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _3: *const bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _4: *mut bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + _2 = _1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _3 = &raw const _2; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + _4 = &raw mut (*_3); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + (*_4) = const false; // scope 0 at $DIR/mutate_through_pointer.rs:+5:9: +5:20 + _0 = _1; // scope 0 at $DIR/mutate_through_pointer.rs:+6:9: +6:16 + return; // scope 0 at $DIR/mutate_through_pointer.rs:+7:9: +7:17 + } + } + diff --git a/tests/mir-opt/copy-prop/mutate_through_pointer.rs b/tests/mir-opt/copy-prop/mutate_through_pointer.rs new file mode 100644 index 00000000000..609e49d6bc9 --- /dev/null +++ b/tests/mir-opt/copy-prop/mutate_through_pointer.rs @@ -0,0 +1,22 @@ +#![feature(custom_mir, core_intrinsics)] +#![allow(unused_assignments)] +extern crate core; +use core::intrinsics::mir::*; + +#[custom_mir(dialect = "analysis", phase = "post-cleanup")] +fn f(c: bool) -> bool { + mir!({ + let a = c; + let p = core::ptr::addr_of!(a); + let p2 = core::ptr::addr_of_mut!(*p); + *p2 = false; + RET = c; + Return() + }) +} + +fn main() { + assert_eq!(true, f(true)); +} + +// EMIT_MIR mutate_through_pointer.f.CopyProp.diff diff --git a/tests/mir-opt/copy-prop/non_dominate.f.CopyProp.diff b/tests/mir-opt/copy-prop/non_dominate.f.CopyProp.diff new file mode 100644 index 00000000000..9760fd3740f --- /dev/null +++ b/tests/mir-opt/copy-prop/non_dominate.f.CopyProp.diff @@ -0,0 +1,29 @@ +- // MIR for `f` before CopyProp ++ // MIR for `f` after CopyProp + + fn f(_1: bool) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/non_dominate.rs:+0:18: +0:22 + let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _3: bool; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + goto -> bb1; // scope 0 at $DIR/non_dominate.rs:+4:11: +4:20 + } + + bb1: { + _3 = _1; // scope 0 at $DIR/non_dominate.rs:+5:17: +5:22 + switchInt(_3) -> [0: bb3, otherwise: bb2]; // scope 0 at $DIR/non_dominate.rs:+5:24: +5:58 + } + + bb2: { + _2 = _3; // scope 0 at $DIR/non_dominate.rs:+8:17: +8:22 + _1 = const false; // scope 0 at $DIR/non_dominate.rs:+8:24: +8:33 + goto -> bb1; // scope 0 at $DIR/non_dominate.rs:+8:35: +8:44 + } + + bb3: { + _0 = _2; // scope 0 at $DIR/non_dominate.rs:+9:17: +9:24 + return; // scope 0 at $DIR/non_dominate.rs:+9:26: +9:34 + } + } + diff --git a/tests/mir-opt/copy-prop/non_dominate.rs b/tests/mir-opt/copy-prop/non_dominate.rs new file mode 100644 index 00000000000..c0ea838e1c8 --- /dev/null +++ b/tests/mir-opt/copy-prop/non_dominate.rs @@ -0,0 +1,26 @@ +// unit-test: CopyProp + +#![feature(custom_mir, core_intrinsics)] +#![allow(unused_assignments)] +extern crate core; +use core::intrinsics::mir::*; + +#[custom_mir(dialect = "analysis", phase = "post-cleanup")] +fn f(c: bool) -> bool { + mir!( + let a: bool; + let b: bool; + { Goto(bb1) } + bb1 = { b = c; match b { false => bb3, _ => bb2 }} + // This assignment to `a` does not dominate the use in `bb3`. + // It should not be replaced by `b`. + bb2 = { a = b; c = false; Goto(bb1) } + bb3 = { RET = a; Return() } + ) +} + +fn main() { + assert_eq!(true, f(true)); +} + +// EMIT_MIR non_dominate.f.CopyProp.diff diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.diff index 02aafd7acc4..6870d7d6c45 100644 --- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.diff +++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.diff @@ -20,19 +20,11 @@ _1 = const u8::MAX; // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47 StorageLive(_2); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47 _2 = const 1_u8; // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47 - StorageLive(_3); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL - _3 = const u8::MAX; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL - StorageLive(_4); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL - _4 = const 1_u8; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL _5 = CheckedAdd(const u8::MAX, const 1_u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> bb1; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL } bb1: { - StorageDead(_4); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL - StorageDead(_3); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL - StorageDead(_2); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47 - StorageDead(_1); // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47 return; // scope 0 at $DIR/inherit_overflow.rs:+4:2: +4:2 } } diff --git a/tests/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir b/tests/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir index d7f66a6bf4d..1a7fb916e56 100644 --- a/tests/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir +++ b/tests/mir-opt/div_overflow.const_dividend.PreCodegen.after.mir @@ -11,7 +11,7 @@ fn const_dividend(_1: i32) -> i32 { } bb1: { - _0 = Div(const 256_i32, move _1); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12 + _0 = Div(const 256_i32, _1); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12 return; // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir b/tests/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir index 7b7ab197825..5526a194be5 100644 --- a/tests/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir +++ b/tests/mir-opt/div_overflow.const_divisor.PreCodegen.after.mir @@ -5,7 +5,7 @@ fn const_divisor(_1: i32) -> i32 { let mut _0: i32; // return place in scope 0 at $DIR/div_overflow.rs:+0:33: +0:36 bb0: { - _0 = Div(move _1, const 256_i32); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12 + _0 = Div(_1, const 256_i32); // scope 0 at $DIR/div_overflow.rs:+1:5: +1:12 return; // scope 0 at $DIR/div_overflow.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff index c1c2cde71ab..df9f8dcf1a4 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff @@ -83,55 +83,39 @@ _10 = ((_7 as Some).0: usize); // scope 3 at $DIR/funky_arms.rs:+13:17: +13:26 StorageLive(_11); // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46 _11 = &mut (*_1); // scope 3 at $DIR/funky_arms.rs:+15:43: +15:46 - StorageLive(_12); // scope 3 at $DIR/funky_arms.rs:+15:48: +15:51 - _12 = _2; // scope 3 at $DIR/funky_arms.rs:+15:48: +15:51 StorageLive(_13); // scope 3 at $DIR/funky_arms.rs:+15:53: +15:57 _13 = _6; // scope 3 at $DIR/funky_arms.rs:+15:53: +15:57 StorageLive(_14); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:79 StorageLive(_15); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75 - StorageLive(_16); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:68 - _16 = _10; // scope 3 at $DIR/funky_arms.rs:+15:59: +15:68 - _15 = move _16 as u32 (IntToInt); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75 - StorageDead(_16); // scope 3 at $DIR/funky_arms.rs:+15:74: +15:75 + _15 = _10 as u32 (IntToInt); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:75 _14 = Add(move _15, const 1_u32); // scope 3 at $DIR/funky_arms.rs:+15:59: +15:79 StorageDead(_15); // scope 3 at $DIR/funky_arms.rs:+15:78: +15:79 - StorageLive(_17); // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86 - _17 = _3; // scope 3 at $DIR/funky_arms.rs:+15:81: +15:86 - _0 = float_to_exponential_common_exact::(move _11, move _12, move _13, move _14, move _17) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87 + _0 = float_to_exponential_common_exact::(move _11, _2, move _13, move _14, _3) -> bb7; // scope 3 at $DIR/funky_arms.rs:+15:9: +15:87 // mir::Constant // + span: $DIR/funky_arms.rs:26:9: 26:42 // + literal: Const { ty: for<'a, 'b, 'c> fn(&'a mut Formatter<'b>, &'c T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::}, val: Value() } } bb7: { - StorageDead(_17); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 StorageDead(_14); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 StorageDead(_13); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 - StorageDead(_12); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 StorageDead(_11); // scope 3 at $DIR/funky_arms.rs:+15:86: +15:87 - StorageDead(_10); // scope 2 at $DIR/funky_arms.rs:+16:5: +16:6 goto -> bb10; // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6 } bb8: { StorageLive(_18); // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49 _18 = &mut (*_1); // scope 2 at $DIR/funky_arms.rs:+17:46: +17:49 - StorageLive(_19); // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54 - _19 = _2; // scope 2 at $DIR/funky_arms.rs:+17:51: +17:54 StorageLive(_20); // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60 _20 = _6; // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60 - StorageLive(_21); // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67 - _21 = _3; // scope 2 at $DIR/funky_arms.rs:+17:62: +17:67 - _0 = float_to_exponential_common_shortest::(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68 + _0 = float_to_exponential_common_shortest::(move _18, _2, move _20, _3) -> bb9; // scope 2 at $DIR/funky_arms.rs:+17:9: +17:68 // mir::Constant // + span: $DIR/funky_arms.rs:28:9: 28:45 // + literal: Const { ty: for<'a, 'b, 'c> fn(&'a mut Formatter<'b>, &'c T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::}, val: Value() } } bb9: { - StorageDead(_21); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 StorageDead(_20); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 - StorageDead(_19); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 StorageDead(_18); // scope 2 at $DIR/funky_arms.rs:+17:67: +17:68 goto -> bb10; // scope 2 at $DIR/funky_arms.rs:+13:5: +18:6 } diff --git a/tests/mir-opt/inline/dyn_trait.get_query.Inline.diff b/tests/mir-opt/inline/dyn_trait.get_query.Inline.diff index 8ea1a0757f2..64c3e47ff46 100644 --- a/tests/mir-opt/inline/dyn_trait.get_query.Inline.diff +++ b/tests/mir-opt/inline/dyn_trait.get_query.Inline.diff @@ -35,8 +35,8 @@ _4 = &(*_2); // scope 1 at $DIR/dyn_trait.rs:+2:23: +2:24 - _0 = try_execute_query::<::C>(move _4) -> bb2; // scope 1 at $DIR/dyn_trait.rs:+2:5: +2:25 + StorageLive(_5); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15 -+ _5 = move _4 as &dyn Cache::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15 -+ _0 = ::V> as Cache>::store_nocache(move _5) -> bb2; // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22 ++ _5 = _4 as &dyn Cache::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15 ++ _0 = ::V> as Cache>::store_nocache(_5) -> bb2; // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22 // mir::Constant - // + span: $DIR/dyn_trait.rs:34:5: 34:22 - // + literal: Const { ty: for<'a> fn(&'a ::C) {try_execute_query::<::C>}, val: Value() } diff --git a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff index a71d73b7453..3fa9c3e88f6 100644 --- a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff +++ b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff @@ -17,7 +17,7 @@ _2 = move _3 as &dyn Cache::V> (Pointer(Unsize)); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15 StorageDead(_3); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15 - _0 = mk_cycle::<::V>(move _2) -> bb1; // scope 0 at $DIR/dyn_trait.rs:+1:5: +1:16 -+ _0 = ::V> as Cache>::store_nocache(move _2) -> bb1; // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22 ++ _0 = ::V> as Cache>::store_nocache(_2) -> bb1; // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22 // mir::Constant - // + span: $DIR/dyn_trait.rs:27:5: 27:13 - // + literal: Const { ty: for<'a> fn(&'a (dyn Cache::V> + 'a)) {mk_cycle::<::V>}, val: Value() } diff --git a/tests/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/tests/mir-opt/inline/inline_any_operand.bar.Inline.after.mir index 3502c25864b..20f737cc29f 100644 --- a/tests/mir-opt/inline/inline_any_operand.bar.Inline.after.mir +++ b/tests/mir-opt/inline/inline_any_operand.bar.Inline.after.mir @@ -26,7 +26,7 @@ fn bar() -> bool { _3 = const 1_i32; // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13 StorageLive(_4); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13 _4 = const -1_i32; // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13 - _0 = Eq(move _3, move _4); // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:11 + _0 = Eq(_3, _4); // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:11 StorageDead(_4); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13 StorageDead(_3); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13 StorageDead(_2); // scope 1 at $DIR/inline_any_operand.rs:+2:12: +2:13 diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.diff b/tests/mir-opt/inline/inline_generator.main.Inline.diff index f27b64c3054..57574acf923 100644 --- a/tests/mir-opt/inline/inline_generator.main.Inline.diff +++ b/tests/mir-opt/inline/inline_generator.main.Inline.diff @@ -92,7 +92,7 @@ + + bb3: { + StorageLive(_8); // scope 6 at $DIR/inline_generator.rs:15:17: 15:39 -+ switchInt(move _7) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21 ++ switchInt(_7) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21 + } + + bb4: { @@ -118,7 +118,7 @@ + StorageLive(_8); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 + StorageDead(_8); // scope 6 at $DIR/inline_generator.rs:15:38: 15:39 + Deinit(_1); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 -+ ((_1 as Complete).0: bool) = move _7; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 ++ ((_1 as Complete).0: bool) = _7; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 + discriminant(_1) = 1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 + _12 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 + discriminant((*_12)) = 1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 diff --git a/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir b/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir index 73aea719eed..b7c5bbecb68 100644 --- a/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir +++ b/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir @@ -15,7 +15,7 @@ fn test2(_1: &dyn X) -> bool { _3 = &(*_1); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11 _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11 StorageDead(_3); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11 - _0 = ::y(move _2) -> bb1; // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10 + _0 = ::y(_2) -> bb1; // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10 // mir::Constant // + span: $DIR/inline_trait_method_2.rs:10:7: 10:8 // + literal: Const { ty: for<'a> fn(&'a dyn X) -> bool {::y}, val: Value() } diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.diff b/tests/mir-opt/issue_101973.inner.ConstProp.diff index b2706e5a436..30bf2c0684e 100644 --- a/tests/mir-opt/issue_101973.inner.ConstProp.diff +++ b/tests/mir-opt/issue_101973.inner.ConstProp.diff @@ -15,7 +15,7 @@ let mut _10: (u32, bool); // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 let mut _11: (u32, bool); // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 scope 1 (inlined imm8) { // at $DIR/issue_101973.rs:14:5: 14:17 - debug x => _5; // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14 + debug x => _1; // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14 let mut _12: u32; // in scope 1 at $DIR/issue_101973.rs:7:12: 7:27 let mut _13: u32; // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20 let mut _14: (u32, bool); // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20 @@ -34,17 +34,14 @@ StorageLive(_2); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65 StorageLive(_3); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:58 StorageLive(_4); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:17 - StorageLive(_5); // scope 0 at $DIR/issue_101973.rs:+1:10: +1:16 - _5 = _1; // scope 0 at $DIR/issue_101973.rs:+1:10: +1:16 StorageLive(_12); // scope 2 at $DIR/issue_101973.rs:7:12: 7:27 StorageLive(_13); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20 - _14 = CheckedShr(_5, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20 + _14 = CheckedShr(_1, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20 assert(!move (_14.1: bool), "attempt to shift right by `{}`, which would overflow", const 0_i32) -> bb3; // scope 2 at $DIR/issue_101973.rs:7:12: 7:20 } bb1: { _8 = move (_10.0: u32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 - StorageDead(_9); // scope 0 at $DIR/issue_101973.rs:+1:44: +1:45 _7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52 StorageDead(_8); // scope 0 at $DIR/issue_101973.rs:+1:51: +1:52 _11 = CheckedShl(_7, const 1_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 @@ -54,11 +51,7 @@ bb2: { _6 = move (_11.0: u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 StorageDead(_7); // scope 0 at $DIR/issue_101973.rs:+1:56: +1:57 - StorageLive(_15); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - _15 = _4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - StorageLive(_16); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - _16 = _6; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - _3 = rotate_right::(move _15, move _16) -> bb4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + _3 = rotate_right::(_4, _6) -> bb4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL // + literal: Const { ty: extern "rust-intrinsic" fn(u32, u32) -> u32 {rotate_right::}, val: Value() } @@ -70,21 +63,14 @@ StorageDead(_13); // scope 2 at $DIR/issue_101973.rs:7:26: 7:27 _4 = BitOr(const 0_u32, move _12); // scope 2 at $DIR/issue_101973.rs:7:5: 7:27 StorageDead(_12); // scope 2 at $DIR/issue_101973.rs:7:26: 7:27 - StorageDead(_5); // scope 0 at $DIR/issue_101973.rs:+1:16: +1:17 StorageLive(_6); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 StorageLive(_7); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52 StorageLive(_8); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 - StorageLive(_9); // scope 0 at $DIR/issue_101973.rs:+1:33: +1:39 - _9 = _1; // scope 0 at $DIR/issue_101973.rs:+1:33: +1:39 - _10 = CheckedShr(_9, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 + _10 = CheckedShr(_1, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 assert(!move (_10.1: bool), "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 } bb4: { - StorageDead(_16); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - StorageDead(_15); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - StorageDead(_6); // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58 - StorageDead(_4); // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58 _2 = move _3 as i32 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65 StorageDead(_3); // scope 0 at $DIR/issue_101973.rs:+1:64: +1:65 _0 = move _2 as i64 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:72 diff --git a/tests/mir-opt/issue_76432.rs b/tests/mir-opt/issue_76432.rs index c8b405ca8ea..fbbfd4ceb11 100644 --- a/tests/mir-opt/issue_76432.rs +++ b/tests/mir-opt/issue_76432.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmir-enable-passes=-NormalizeArrayLen // Check that we do not insert StorageDead at each target if StorageDead was never seen // EMIT_MIR issue_76432.test.SimplifyComparisonIntegral.diff diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff index c24543daeac..c14780052fb 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff @@ -29,24 +29,11 @@ bb0: { StorageLive(_2); // scope 0 at $DIR/issue_76432.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 StorageLive(_4); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 StorageLive(_5); // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29 - StorageLive(_6); // scope 0 at $DIR/issue_76432.rs:+1:21: +1:22 - _6 = _1; // scope 0 at $DIR/issue_76432.rs:+1:21: +1:22 - StorageLive(_7); // scope 0 at $DIR/issue_76432.rs:+1:24: +1:25 - _7 = _1; // scope 0 at $DIR/issue_76432.rs:+1:24: +1:25 - StorageLive(_8); // scope 0 at $DIR/issue_76432.rs:+1:27: +1:28 - _8 = _1; // scope 0 at $DIR/issue_76432.rs:+1:27: +1:28 - _5 = [move _6, move _7, move _8]; // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29 - StorageDead(_8); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29 - StorageDead(_7); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29 - StorageDead(_6); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29 + _5 = [_1, _1, _1]; // scope 0 at $DIR/issue_76432.rs:+1:20: +1:29 _4 = &_5; // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - _3 = _4; // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 - StorageDead(_3); // scope 0 at $DIR/issue_76432.rs:+1:28: +1:29 - StorageDead(_4); // scope 0 at $DIR/issue_76432.rs:+1:29: +1:30 + _2 = _4 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:+1:19: +1:29 _9 = Len((*_2)); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33 _10 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33 - _11 = Eq(move _9, const 3_usize); // scope 1 at $DIR/issue_76432.rs:+3:9: +3:33 diff --git a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff index 9bc7060e958..59de067f4a4 100644 --- a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff +++ b/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff @@ -13,7 +13,6 @@ let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 bb0: { StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 @@ -23,13 +22,10 @@ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _11 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 - _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 ++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 } diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff index cf427cfd1e6..17574b1b635 100644 --- a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff +++ b/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff @@ -16,7 +16,6 @@ let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 bb0: { StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 @@ -26,13 +25,10 @@ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _14 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 - _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 ++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 } diff --git a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff index 3ed68f5f725..66feff62f42 100644 --- a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff +++ b/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff @@ -6,19 +6,15 @@ let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57 let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 bb0: { StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 - _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 ++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 } diff --git a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff index f0e0cdcfdc0..c0a277edc46 100644 --- a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff +++ b/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff @@ -6,19 +6,15 @@ let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65 let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 bb0: { StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 - _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 ++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 } diff --git a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.diff new file mode 100644 index 00000000000..8b35fd57fa0 --- /dev/null +++ b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.diff @@ -0,0 +1,50 @@ +- // MIR for `array_len_raw` before NormalizeArrayLen ++ // MIR for `array_len_raw` after NormalizeArrayLen + + fn array_len_raw(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:38: +0:41 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:55: +0:60 + let _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + let _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+3:5: +3:27 + let _7: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+3:14: +3:19 + scope 1 { + debug arr => _2; // in scope 1 at $DIR/lower_array_len.rs:+1:9: +1:12 + let _5: *const [u8]; // in scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12 + scope 2 { + debug arr => _5; // in scope 2 at $DIR/lower_array_len.rs:+2:9: +2:12 + scope 3 { + } + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + _4 = &_1; // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + _3 = &(*_4); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:24: +1:25 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:26 + StorageLive(_5); // scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12 + _5 = &raw const (*_2); // scope 1 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageLive(_6); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 + StorageLive(_7); // scope 2 at $DIR/lower_array_len.rs:+3:14: +3:19 + _7 = &(*_5); // scope 3 at $DIR/lower_array_len.rs:+3:14: +3:19 + _6 = &(*_7); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 +- _0 = Len((*_6)); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 ++ _0 = const N; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 + goto -> bb1; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 + } + + bb1: { + StorageDead(_6); // scope 2 at $DIR/lower_array_len.rs:+3:26: +3:27 + StorageDead(_5); // scope 1 at $DIR/lower_array_len.rs:+4:1: +4:2 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+4:1: +4:2 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+4:1: +4:2 + return; // scope 0 at $DIR/lower_array_len.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.diff new file mode 100644 index 00000000000..8bdd2ede6bc --- /dev/null +++ b/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.diff @@ -0,0 +1,44 @@ +- // MIR for `array_len_reborrow` before NormalizeArrayLen ++ // MIR for `array_len_reborrow` after NormalizeArrayLen + + fn array_len_reborrow(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:50 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:64: +0:69 + let _2: &mut [u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12 + let mut _3: &mut [u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + let mut _4: &mut [u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+3:5: +3:14 + scope 1 { + debug arr => _2; // in scope 1 at $DIR/lower_array_len.rs:+1:9: +1:12 + let _5: &[u8]; // in scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12 + scope 2 { + debug arr => _5; // in scope 2 at $DIR/lower_array_len.rs:+2:9: +2:12 + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + _4 = &mut _1; // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + _3 = &mut (*_4); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + _2 = move _3 as &mut [u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:32: +1:33 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:33: +1:34 + StorageLive(_5); // scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12 + _5 = &(*_2); // scope 1 at $DIR/lower_array_len.rs:+2:15: +2:20 + StorageLive(_6); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 + _6 = &(*_5); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 +- _0 = Len((*_6)); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 ++ _0 = const N; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 + goto -> bb1; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 + } + + bb1: { + StorageDead(_6); // scope 2 at $DIR/lower_array_len.rs:+3:13: +3:14 + StorageDead(_5); // scope 1 at $DIR/lower_array_len.rs:+4:1: +4:2 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+4:1: +4:2 + return; // scope 0 at $DIR/lower_array_len.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/lower_array_len.rs b/tests/mir-opt/lower_array_len.rs index ea0224b21d7..972d46cb8e2 100644 --- a/tests/mir-opt/lower_array_len.rs +++ b/tests/mir-opt/lower_array_len.rs @@ -31,10 +31,26 @@ arr.len() } +// EMIT_MIR lower_array_len.array_len_reborrow.NormalizeArrayLen.diff +pub fn array_len_reborrow(mut arr: [u8; N]) -> usize { + let arr: &mut [_] = &mut arr; + let arr = &*arr; + arr.len() +} + +// EMIT_MIR lower_array_len.array_len_raw.NormalizeArrayLen.diff +pub fn array_len_raw(arr: [u8; N]) -> usize { + let arr: &[_] = &arr; + let arr = std::ptr::addr_of!(*arr); + unsafe { &*arr }.len() +} + fn main() { let _ = array_bound(3, &[0, 1, 2, 3]); let mut tmp = [0, 1, 2, 3, 4]; let _ = array_bound_mut(3, &mut [0, 1, 2, 3]); let _ = array_len(&[0]); let _ = array_len_by_value([0, 2]); + let _ = array_len_reborrow([0, 2]); + let _ = array_len_raw([0, 2]); } diff --git a/tests/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir deleted file mode 100644 index 701c2ad705a..00000000000 --- a/tests/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir +++ /dev/null @@ -1,45 +0,0 @@ -// MIR for `array_bound` after PreCodegen - -fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:36: +0:41 - debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:50: +0:55 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:70: +0:72 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - let mut _6: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - let mut _7: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - - bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 - switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - } - - bb1: { - _6 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - _7 = Lt(_1, _6); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - } - - bb2: { - _0 = (*_2)[_1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - goto -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6 - } - - bb3: { - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:11 - goto -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6 - } - - bb4: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+5:5: +5:6 - return; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:2: +6:2 - } -} diff --git a/tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir deleted file mode 100644 index 0440cfce289..00000000000 --- a/tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir +++ /dev/null @@ -1,58 +0,0 @@ -// MIR for `array_bound_mut` after PreCodegen - -fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:40: +0:45 - debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:54: +0:59 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:78: +0:80 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - let mut _6: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - let mut _7: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - let _8: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 - let mut _9: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - let mut _10: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - - bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 - switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - } - - bb1: { - _6 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - _7 = Lt(_1, _6); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - } - - bb2: { - _0 = (*_2)[_1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6 - } - - bb3: { - StorageLive(_8); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 - _8 = const 0_usize; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 - _9 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - _10 = Lt(const 0_usize, _9); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - } - - bb4: { - (*_2)[_8] = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22 - StorageDead(_8); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23 - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:9: +6:11 - goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6 - } - - bb5: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+7:5: +7:6 - return; // scope 0 at $DIR/lower_array_len_e2e.rs:+8:2: +8:2 - } -} diff --git a/tests/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir deleted file mode 100644 index 4b19f679558..00000000000 --- a/tests/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir +++ /dev/null @@ -1,11 +0,0 @@ -// MIR for `array_len` after PreCodegen - -fn array_len(_1: &[u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:34: +0:37 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:52: +0:57 - - bb0: { - _0 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14 - return; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2 - } -} diff --git a/tests/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir deleted file mode 100644 index 4dc0ba9a268..00000000000 --- a/tests/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir +++ /dev/null @@ -1,11 +0,0 @@ -// MIR for `array_len_by_value` after PreCodegen - -fn array_len_by_value(_1: [u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:43: +0:46 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:60: +0:65 - - bb0: { - _0 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14 - return; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2 - } -} diff --git a/tests/mir-opt/lower_array_len_e2e.rs b/tests/mir-opt/lower_array_len_e2e.rs deleted file mode 100644 index d8e4e521ee6..00000000000 --- a/tests/mir-opt/lower_array_len_e2e.rs +++ /dev/null @@ -1,39 +0,0 @@ -// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts - -// EMIT_MIR lower_array_len_e2e.array_bound.PreCodegen.after.mir -pub fn array_bound(index: usize, slice: &[u8; N]) -> u8 { - if index < slice.len() { - slice[index] - } else { - 42 - } -} - -// EMIT_MIR lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir -pub fn array_bound_mut(index: usize, slice: &mut [u8; N]) -> u8 { - if index < slice.len() { - slice[index] - } else { - slice[0] = 42; - - 42 - } -} - -// EMIT_MIR lower_array_len_e2e.array_len.PreCodegen.after.mir -pub fn array_len(arr: &[u8; N]) -> usize { - arr.len() -} - -// EMIT_MIR lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir -pub fn array_len_by_value(arr: [u8; N]) -> usize { - arr.len() -} - -fn main() { - let _ = array_bound(3, &[0, 1, 2, 3]); - let mut tmp = [0, 1, 2, 3, 4]; - let _ = array_bound_mut(3, &mut [0, 1, 2, 3]); - let _ = array_len(&[0]); - let _ = array_len_by_value([0, 2]); -} diff --git a/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir b/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir index 916f99049c6..760f48d956d 100644 --- a/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir +++ b/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir @@ -37,7 +37,7 @@ fn ezmap(_1: Option) -> Option { bb3: { _5 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15 StorageLive(_4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 - _4 = Add(move _5, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21 + _4 = Add(_5, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21 Deinit(_0); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30 ((_0 as Some).0: i32) = move _4; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30 discriminant(_0) = 1; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30 diff --git a/tests/mir-opt/simplify_match.main.ConstProp.diff b/tests/mir-opt/simplify_match.main.ConstProp.diff index 70bfbf1b3e3..35ffc4963cb 100644 --- a/tests/mir-opt/simplify_match.main.ConstProp.diff +++ b/tests/mir-opt/simplify_match.main.ConstProp.diff @@ -10,13 +10,9 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/simplify_match.rs:+1:11: +1:31 StorageLive(_2); // scope 0 at $DIR/simplify_match.rs:+1:17: +1:18 _2 = const false; // scope 0 at $DIR/simplify_match.rs:+1:21: +1:26 -- _1 = _2; // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29 -+ _1 = const false; // scope 1 at $DIR/simplify_match.rs:+1:28: +1:29 - StorageDead(_2); // scope 0 at $DIR/simplify_match.rs:+1:30: +1:31 -- switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31 +- switchInt(_2) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31 + switchInt(const false) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_match.rs:+1:5: +1:31 } @@ -32,7 +28,6 @@ } bb3: { - StorageDead(_1); // scope 0 at $DIR/simplify_match.rs:+5:1: +5:2 return; // scope 0 at $DIR/simplify_match.rs:+5:2: +5:2 } } diff --git a/tests/mir-opt/slice_filter.rs b/tests/mir-opt/slice_filter.rs new file mode 100644 index 00000000000..97c18af31de --- /dev/null +++ b/tests/mir-opt/slice_filter.rs @@ -0,0 +1,18 @@ +fn main() { + let input = vec![]; + let _variant_a_result = variant_a(&input); + let _variant_b_result = variant_b(&input); +} + +pub fn variant_a(input: &[(usize, usize, usize, usize)]) -> usize { + input.iter().filter(|(a, b, c, d)| a <= c && d <= b || c <= a && b <= d).count() +} + +pub fn variant_b(input: &[(usize, usize, usize, usize)]) -> usize { + input.iter().filter(|&&(a, b, c, d)| a <= c && d <= b || c <= a && b <= d).count() +} + +// EMIT_MIR slice_filter.variant_a-{closure#0}.CopyProp.diff +// EMIT_MIR slice_filter.variant_a-{closure#0}.DestinationPropagation.diff +// EMIT_MIR slice_filter.variant_b-{closure#0}.CopyProp.diff +// EMIT_MIR slice_filter.variant_b-{closure#0}.DestinationPropagation.diff diff --git a/tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff b/tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff new file mode 100644 index 00000000000..d1f6fd97dc7 --- /dev/null +++ b/tests/mir-opt/slice_filter.variant_a-{closure#0}.CopyProp.diff @@ -0,0 +1,279 @@ +- // MIR for `variant_a::{closure#0}` before CopyProp ++ // MIR for `variant_a::{closure#0}` after CopyProp + + fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:8:25: 8:39], _2: &&(usize, usize, usize, usize)) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:40: +0:40 + let _3: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + let _4: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + let _5: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + let _6: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:56 + let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:46 + let mut _9: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:41 + let mut _10: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46 + let _11: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46 + let mut _12: bool; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:56 + let mut _13: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:51 + let mut _14: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56 + let _15: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56 + let mut _16: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:76 + let mut _17: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:66 + let mut _18: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:61 + let mut _19: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66 + let _20: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66 + let mut _21: bool; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:76 + let mut _22: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:71 + let mut _23: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 + let _24: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 + let mut _25: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _26: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _27: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _28: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + scope 1 { + debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28 + debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31 + debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34 + debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37 + scope 2 (inlined cmp::impls::::le) { // at $DIR/slice_filter.rs:8:40: 8:46 + debug self => _9; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _10; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _29: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _30: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _31: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _32: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 3 (inlined cmp::impls::::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _29; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _30; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => _31; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => _32; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _33: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _34: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + scope 4 (inlined cmp::impls::::le) { // at $DIR/slice_filter.rs:8:60: 8:66 + debug self => _18; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _19; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _35: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _36: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _37: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _38: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 5 (inlined cmp::impls::::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _35; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _36; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => _37; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => _38; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _39: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _40: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + scope 6 (inlined cmp::impls::::le) { // at $DIR/slice_filter.rs:8:50: 8:56 + debug self => _13; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _14; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _41: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _42: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _43: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _44: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 7 (inlined cmp::impls::::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _41; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _42; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => _43; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => _44; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _45: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _46: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + scope 8 (inlined cmp::impls::::le) { // at $DIR/slice_filter.rs:8:70: 8:76 + debug self => _22; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _23; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _47: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _48: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _49: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _50: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 9 (inlined cmp::impls::::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _47; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _48; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => _49; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => _50; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _51: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _52: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + _25 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + _3 = &((*_25).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + _26 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + _4 = &((*_26).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + _27 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + _5 = &((*_27).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + _28 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + _6 = &((*_28).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46 + StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 + _9 = &_3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 + StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + _11 = _5; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + _10 = &_11; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 +- StorageLive(_29); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + _31 = deref_copy (*_9); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _29 = _31; // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageLive(_30); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + _32 = deref_copy (*_10); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _30 = _32; // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_33); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _33 = (*_29); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _33 = (*_31); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_34); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _34 = (*_30); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _34 = (*_32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + _8 = Le(move _33, move _34); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_34); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_33); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_30); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_29); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + } + + bb1: { + _0 = const true; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + } + + bb2: { + StorageLive(_16); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + StorageLive(_17); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66 + StorageLive(_18); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 + _18 = &_5; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 + StorageLive(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + StorageLive(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + _20 = _3; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + _19 = &_20; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 +- StorageLive(_35); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + _37 = deref_copy (*_18); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _35 = _37; // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageLive(_36); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + _38 = deref_copy (*_19); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _36 = _38; // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_39); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _39 = (*_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _39 = (*_37); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_40); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _40 = (*_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _40 = (*_38); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + _17 = Le(move _39, move _40); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_40); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_39); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_36); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_35); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + StorageDead(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + StorageDead(_18); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + switchInt(move _17) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + } + + bb3: { + StorageDead(_16); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_6); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_5); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_4); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_3); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 + return; // scope 0 at $DIR/slice_filter.rs:+0:76: +0:76 + } + + bb4: { + _7 = const false; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + } + + bb5: { + StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56 + StorageLive(_13); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 + _13 = &_6; // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 + StorageLive(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageLive(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + _15 = _4; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + _14 = &_15; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- StorageLive(_41); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + _43 = deref_copy (*_13); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _41 = _43; // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageLive(_42); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + _44 = deref_copy (*_14); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _42 = _44; // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_45); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _45 = (*_41); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _45 = (*_43); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_46); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _46 = (*_42); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _46 = (*_44); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + _12 = Le(move _45, move _46); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_46); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_45); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_42); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_41); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_13); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + _7 = move _12; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + } + + bb6: { + _16 = const false; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + } + + bb7: { + StorageLive(_21); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76 + StorageLive(_22); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 + _22 = &_4; // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 + StorageLive(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageLive(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _24 = _6; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _23 = &_24; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageLive(_47); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + _49 = deref_copy (*_22); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _47 = _49; // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageLive(_48); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + _50 = deref_copy (*_23); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _48 = _50; // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_51); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _51 = (*_47); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _51 = (*_49); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_52); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _52 = (*_48); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _52 = (*_50); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + _21 = Le(move _51, move _52); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_52); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_51); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_48); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL +- StorageDead(_47); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_22); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _16 = move _21; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + } + + bb8: { + StorageDead(_21); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_17); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _0 = move _16; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + } + } + diff --git a/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff b/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff new file mode 100644 index 00000000000..259cd411896 --- /dev/null +++ b/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff @@ -0,0 +1,241 @@ +- // MIR for `variant_a::{closure#0}` before DestinationPropagation ++ // MIR for `variant_a::{closure#0}` after DestinationPropagation + + fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:8:25: 8:39], _2: &&(usize, usize, usize, usize)) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:40: +0:40 + let _3: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + let _4: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + let _5: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + let _6: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:56 + let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:46 + let mut _9: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:41 + let mut _10: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46 + let _11: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46 + let mut _12: bool; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:56 + let mut _13: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:51 + let mut _14: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56 + let _15: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56 + let mut _16: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:76 + let mut _17: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:66 + let mut _18: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:61 + let mut _19: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66 + let _20: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66 + let mut _21: bool; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:76 + let mut _22: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:71 + let mut _23: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 + let _24: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 + let mut _25: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _26: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _27: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _28: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + scope 1 { + debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28 + debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31 + debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34 + debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37 + scope 2 (inlined cmp::impls::::le) { // at $DIR/slice_filter.rs:8:40: 8:46 + debug self => _9; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _10; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _29: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _30: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 3 (inlined cmp::impls::::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => _29; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _30; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _31: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _32: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + scope 4 (inlined cmp::impls::::le) { // at $DIR/slice_filter.rs:8:60: 8:66 + debug self => _18; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _19; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _33: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _34: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 5 (inlined cmp::impls::::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => _33; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _34; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _35: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _36: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + scope 6 (inlined cmp::impls::::le) { // at $DIR/slice_filter.rs:8:50: 8:56 + debug self => _13; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _14; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _37: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _38: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 7 (inlined cmp::impls::::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => _37; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _38; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _39: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _40: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + scope 8 (inlined cmp::impls::::le) { // at $DIR/slice_filter.rs:8:70: 8:76 + debug self => _22; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _23; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _41: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _42: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + scope 9 (inlined cmp::impls::::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => _41; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => _42; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _43: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _44: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + } + } + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + _25 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + _3 = &((*_25).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + _26 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + _4 = &((*_26).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + _27 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + _5 = &((*_27).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + _28 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + _6 = &((*_28).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 +- StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46 + StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 + _9 = &_3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 + StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + _11 = _5; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + _10 = &_11; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + _29 = deref_copy (*_9); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + _30 = deref_copy (*_10); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_31); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + _31 = (*_29); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + _32 = (*_30); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + _8 = Le(move _31, move _32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_31); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 + switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + } + + bb1: { + _0 = const true; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + } + + bb2: { +- StorageLive(_16); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + StorageLive(_17); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66 + StorageLive(_18); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 + _18 = &_5; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 + StorageLive(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + StorageLive(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + _20 = _3; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + _19 = &_20; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + _33 = deref_copy (*_18); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + _34 = deref_copy (*_19); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + _35 = (*_33); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + _36 = (*_34); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + _17 = Le(move _35, move _36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + StorageDead(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + StorageDead(_18); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 + switchInt(move _17) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + } + + bb3: { +- StorageDead(_16); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + return; // scope 0 at $DIR/slice_filter.rs:+0:76: +0:76 + } + + bb4: { +- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + } + + bb5: { +- StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56 + StorageLive(_13); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 + _13 = &_6; // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 + StorageLive(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageLive(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + _15 = _4; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + _14 = &_15; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + _37 = deref_copy (*_13); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + _38 = deref_copy (*_14); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_39); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + _39 = (*_37); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_40); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + _40 = (*_38); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + _12 = Le(move _39, move _40); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_40); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_39); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_13); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- _7 = move _12; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 +- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 ++ switchInt(move _12) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + } + + bb6: { +- _16 = const false; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 ++ _0 = const false; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + } + + bb7: { +- StorageLive(_21); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76 + StorageLive(_22); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 + _22 = &_4; // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 + StorageLive(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageLive(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _24 = _6; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _23 = &_24; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + _41 = deref_copy (*_22); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + _42 = deref_copy (*_23); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_43); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + _43 = (*_41); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + _44 = (*_42); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _21 = Le(move _43, move _44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _0 = Le(move _43, move _44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_43); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_22); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- _16 = move _21; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + } + + bb8: { +- StorageDead(_21); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + StorageDead(_17); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- _0 = move _16; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + } + } + diff --git a/tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff b/tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff new file mode 100644 index 00000000000..c3b8e7d2eba --- /dev/null +++ b/tests/mir-opt/slice_filter.variant_b-{closure#0}.CopyProp.diff @@ -0,0 +1,139 @@ +- // MIR for `variant_b::{closure#0}` before CopyProp ++ // MIR for `variant_b::{closure#0}` after CopyProp + + fn variant_b::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:12:25: 12:41], _2: &&(usize, usize, usize, usize)) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:42: +0:42 + let _3: usize; // in scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + let _4: usize; // in scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + let _5: usize; // in scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + let _6: usize; // in scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:58 + let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:48 + let mut _9: usize; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:43 + let mut _10: usize; // in scope 0 at $DIR/slice_filter.rs:+0:47: +0:48 + let mut _11: bool; // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:58 + let mut _12: usize; // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:53 + let mut _13: usize; // in scope 0 at $DIR/slice_filter.rs:+0:57: +0:58 + let mut _14: bool; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:78 + let mut _15: bool; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:68 + let mut _16: usize; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:63 + let mut _17: usize; // in scope 0 at $DIR/slice_filter.rs:+0:67: +0:68 + let mut _18: bool; // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:78 + let mut _19: usize; // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:73 + let mut _20: usize; // in scope 0 at $DIR/slice_filter.rs:+0:77: +0:78 + let mut _21: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + let mut _22: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + let mut _23: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + let mut _24: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + scope 1 { + debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:29: +0:30 + debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:32: +0:33 + debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:35: +0:36 + debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:38: +0:39 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + _21 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + _3 = ((*_21).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + _22 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + _4 = ((*_22).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + _23 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + _5 = ((*_23).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + _24 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + _6 = ((*_24).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48 +- StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:43 +- _9 = _3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:43 +- StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48 +- _10 = _5; // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48 +- _8 = Le(move _9, move _10); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48 +- StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48 +- StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:47: +0:48 ++ _8 = Le(_3, _5); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48 + switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + } + + bb1: { + _0 = const true; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + } + + bb2: { + StorageLive(_14); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + StorageLive(_15); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68 +- StorageLive(_16); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:63 +- _16 = _5; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:63 +- StorageLive(_17); // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68 +- _17 = _3; // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68 +- _15 = Le(move _16, move _17); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68 +- StorageDead(_17); // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68 +- StorageDead(_16); // scope 1 at $DIR/slice_filter.rs:+0:67: +0:68 ++ _15 = Le(_5, _3); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68 + switchInt(move _15) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + } + + bb3: { + StorageDead(_14); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 + StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 +- StorageDead(_6); // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78 +- StorageDead(_5); // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78 +- StorageDead(_4); // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78 +- StorageDead(_3); // scope 0 at $DIR/slice_filter.rs:+0:77: +0:78 + return; // scope 0 at $DIR/slice_filter.rs:+0:78: +0:78 + } + + bb4: { + _7 = const false; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + } + + bb5: { + StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58 +- StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:53 +- _12 = _6; // scope 1 at $DIR/slice_filter.rs:+0:52: +0:53 +- StorageLive(_13); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 +- _13 = _4; // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 +- _11 = Le(move _12, move _13); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58 +- StorageDead(_13); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 +- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 ++ _11 = Le(_6, _4); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58 + _7 = move _11; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + } + + bb6: { + _14 = const false; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + } + + bb7: { + StorageLive(_18); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 +- StorageLive(_19); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:73 +- _19 = _4; // scope 1 at $DIR/slice_filter.rs:+0:72: +0:73 +- StorageLive(_20); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 +- _20 = _6; // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 +- _18 = Le(move _19, move _20); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 +- StorageDead(_20); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 +- StorageDead(_19); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 ++ _18 = Le(_4, _6); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 + _14 = move _18; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + } + + bb8: { + StorageDead(_18); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 + StorageDead(_15); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 + _0 = move _14; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + } + } + diff --git a/tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.diff b/tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.diff new file mode 100644 index 00000000000..a43e84d29c7 --- /dev/null +++ b/tests/mir-opt/slice_filter.variant_b-{closure#0}.DestinationPropagation.diff @@ -0,0 +1,113 @@ +- // MIR for `variant_b::{closure#0}` before DestinationPropagation ++ // MIR for `variant_b::{closure#0}` after DestinationPropagation + + fn variant_b::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:12:25: 12:41], _2: &&(usize, usize, usize, usize)) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:42: +0:42 + let _3: usize; // in scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + let _4: usize; // in scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + let _5: usize; // in scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + let _6: usize; // in scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:58 + let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:42: +0:48 + let mut _9: bool; // in scope 0 at $DIR/slice_filter.rs:+0:52: +0:58 + let mut _10: bool; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:78 + let mut _11: bool; // in scope 0 at $DIR/slice_filter.rs:+0:62: +0:68 + let mut _12: bool; // in scope 0 at $DIR/slice_filter.rs:+0:72: +0:78 + let mut _13: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + let mut _14: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + let mut _15: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + let mut _16: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:40 + scope 1 { + debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:29: +0:30 + debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:32: +0:33 + debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:35: +0:36 + debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:38: +0:39 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + _13 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + _3 = ((*_13).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:29: +0:30 + StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + _14 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + _4 = ((*_14).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:32: +0:33 + StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + _15 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + _5 = ((*_15).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:35: +0:36 + StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + _16 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 + _6 = ((*_16).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:38: +0:39 +- StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48 + _8 = Le(_3, _5); // scope 1 at $DIR/slice_filter.rs:+0:42: +0:48 + switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + } + + bb1: { + _0 = const true; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + } + + bb2: { +- StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68 + _11 = Le(_5, _3); // scope 1 at $DIR/slice_filter.rs:+0:62: +0:68 + switchInt(move _11) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + } + + bb3: { +- StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 +- StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 + return; // scope 0 at $DIR/slice_filter.rs:+0:78: +0:78 + } + + bb4: { +- StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 + } + + bb5: { +- StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58 + _9 = Le(_6, _4); // scope 1 at $DIR/slice_filter.rs:+0:52: +0:58 +- _7 = move _9; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 +- StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:58 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 + StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:57: +0:58 +- switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 ++ switchInt(move _9) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + } + + bb6: { +- _10 = const false; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 ++ _0 = const false; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + } + + bb7: { +- StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 +- _12 = Le(_4, _6); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 +- _10 = move _12; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 ++ _0 = Le(_4, _6); // scope 1 at $DIR/slice_filter.rs:+0:72: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:62: +0:78 + } + + bb8: { +- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 + StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:77: +0:78 +- _0 = move _10; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 ++ nop; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:42: +0:78 + } + } + diff --git a/tests/mir-opt/try_identity_e2e.new.PreCodegen.after.mir b/tests/mir-opt/try_identity_e2e.new.PreCodegen.after.mir index b254bfeb7c9..7c67d2abcf7 100644 --- a/tests/mir-opt/try_identity_e2e.new.PreCodegen.after.mir +++ b/tests/mir-opt/try_identity_e2e.new.PreCodegen.after.mir @@ -5,11 +5,11 @@ fn new(_1: Result) -> Result { let mut _0: std::result::Result; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46 let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10 let mut _3: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:22 - let mut _4: T; // in scope 0 at $DIR/try_identity_e2e.rs:+4:48: +4:49 - let mut _5: E; // in scope 0 at $DIR/try_identity_e2e.rs:+5:46: +5:47 + let _4: T; // in scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21 + let _5: E; // in scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22 let mut _6: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+8:13: +8:37 let _7: T; // in scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36 - let mut _8: E; // in scope 0 at $DIR/try_identity_e2e.rs:+9:49: +9:50 + let _8: E; // in scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33 scope 1 { debug v => _4; // in scope 1 at $DIR/try_identity_e2e.rs:+4:20: +4:21 } @@ -30,6 +30,7 @@ fn new(_1: Result) -> Result { } bb1: { + StorageLive(_5); // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22 _5 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22 Deinit(_2); // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48 ((_2 as Break).0: E) = move _5; // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48 @@ -39,6 +40,7 @@ fn new(_1: Result) -> Result { } bb2: { + StorageLive(_4); // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21 _4 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21 Deinit(_2); // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50 ((_2 as Continue).0: T) = move _4; // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50 @@ -48,6 +50,7 @@ fn new(_1: Result) -> Result { } bb3: { + StorageLive(_8); // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33 _8 = move ((_2 as Break).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33 Deinit(_0); // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51 ((_0 as Err).0: E) = move _8; // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51 @@ -61,6 +64,7 @@ fn new(_1: Result) -> Result { } bb5: { + StorageLive(_7); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36 _7 = move ((_2 as Continue).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36 Deinit(_0); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6 ((_0 as Ok).0: T) = move _7; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6 diff --git a/tests/mir-opt/try_identity_e2e.old.PreCodegen.after.mir b/tests/mir-opt/try_identity_e2e.old.PreCodegen.after.mir index cdbc0681cb8..4a838e14026 100644 --- a/tests/mir-opt/try_identity_e2e.old.PreCodegen.after.mir +++ b/tests/mir-opt/try_identity_e2e.old.PreCodegen.after.mir @@ -5,7 +5,7 @@ fn old(_1: Result) -> Result { let mut _0: std::result::Result; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46 let mut _2: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:18 let _3: T; // in scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17 - let mut _4: E; // in scope 0 at $DIR/try_identity_e2e.rs:+4:34: +4:35 + let _4: E; // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18 scope 1 { debug v => _3; // in scope 1 at $DIR/try_identity_e2e.rs:+3:16: +3:17 } @@ -19,6 +19,7 @@ fn old(_1: Result) -> Result { } bb1: { + StorageLive(_4); // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18 _4 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18 Deinit(_0); // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36 ((_0 as Err).0: E) = move _4; // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36 @@ -31,6 +32,7 @@ fn old(_1: Result) -> Result { } bb3: { + StorageLive(_3); // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17 _3 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17 Deinit(_0); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6 ((_0 as Ok).0: T) = move _3; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6 diff --git a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir index b95d91b13dd..318119bd477 100644 --- a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir +++ b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir @@ -4,9 +4,7 @@ fn while_loop(_1: bool) -> () { debug c => _1; // in scope 0 at $DIR/while_storage.rs:+0:15: +0:16 let mut _0: (); // return place in scope 0 at $DIR/while_storage.rs:+0:24: +0:24 let mut _2: bool; // in scope 0 at $DIR/while_storage.rs:+1:11: +1:22 - let mut _3: bool; // in scope 0 at $DIR/while_storage.rs:+1:20: +1:21 - let mut _4: bool; // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23 - let mut _5: bool; // in scope 0 at $DIR/while_storage.rs:+2:21: +2:22 + let mut _3: bool; // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23 bb0: { goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6 @@ -14,41 +12,35 @@ fn while_loop(_1: bool) -> () { bb1: { StorageLive(_2); // scope 0 at $DIR/while_storage.rs:+1:11: +1:22 - StorageLive(_3); // scope 0 at $DIR/while_storage.rs:+1:20: +1:21 - _3 = _1; // scope 0 at $DIR/while_storage.rs:+1:20: +1:21 - _2 = get_bool(move _3) -> bb2; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22 + _2 = get_bool(_1) -> bb2; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22 // mir::Constant // + span: $DIR/while_storage.rs:10:11: 10:19 // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value() } } bb2: { - StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+1:21: +1:22 switchInt(move _2) -> [0: bb7, otherwise: bb3]; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22 } bb3: { - StorageLive(_4); // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 - StorageLive(_5); // scope 0 at $DIR/while_storage.rs:+2:21: +2:22 - _5 = _1; // scope 0 at $DIR/while_storage.rs:+2:21: +2:22 - _4 = get_bool(move _5) -> bb4; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 + StorageLive(_3); // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 + _3 = get_bool(_1) -> bb4; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 // mir::Constant // + span: $DIR/while_storage.rs:11:12: 11:20 // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value() } } bb4: { - StorageDead(_5); // scope 0 at $DIR/while_storage.rs:+2:22: +2:23 - switchInt(move _4) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 + switchInt(move _3) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 } bb5: { - StorageDead(_4); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 + StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 goto -> bb7; // scope 0 at no-location } bb6: { - StorageDead(_4); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 + StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 StorageDead(_2); // scope 0 at $DIR/while_storage.rs:+5:5: +5:6 goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6 } diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp index 44d21625a2d..e0fa1fe2824 100644 --- a/tests/pretty/issue-4264.pp +++ b/tests/pretty/issue-4264.pp @@ -34,10 +34,11 @@ fn bar() ({ ((::alloc::fmt::format as for<'a> fn(Arguments<'a>) -> String {format})(((<#[lang = "format_arguments"]>::new_v1 as - fn(&[&'static str], &[ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test" + fn(&[&'static str], &[core::fmt::ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test" as &str)] as [&str; 1]) as &[&str; 1]), - (&([] as [ArgumentV1<'_>; 0]) as &[ArgumentV1<'_>; 0])) as - Arguments<'_>)) as String); + (&([] as [core::fmt::ArgumentV1<'_>; 0]) as + &[core::fmt::ArgumentV1<'_>; 0])) as Arguments<'_>)) as + String); (res as String) } as String); } as ()) diff --git a/tests/run-make/native-link-modifier-bundle/Makefile b/tests/run-make/native-link-modifier-bundle/Makefile index 7c78d7783e0..e8a1121bfcd 100644 --- a/tests/run-make/native-link-modifier-bundle/Makefile +++ b/tests/run-make/native-link-modifier-bundle/Makefile @@ -5,7 +5,12 @@ include ../../run-make-fulldeps/tools.mk # We're using the llvm-nm instead of the system nm to ensure it is compatible # with the LLVM bitcode generated by rustc. +# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm. +ifndef IS_WINDOWS NM = "$(LLVM_BIN_DIR)"/llvm-nm +else +NM = nm +endif all: $(call NATIVE_STATICLIB,native-staticlib) # Build a staticlib and a rlib, the `native_func` symbol will be bundled into them diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/Makefile b/tests/run-make/raw-dylib-inline-cross-dylib/Makefile index 9e603f95835..722a49b02cb 100644 --- a/tests/run-make/raw-dylib-inline-cross-dylib/Makefile +++ b/tests/run-make/raw-dylib-inline-cross-dylib/Makefile @@ -4,15 +4,19 @@ include ../../run-make-fulldeps/tools.mk +# We'd be using the llvm-objdump instead of the system objdump to ensure compatibility +# with the LLVM bitcode generated by rustc but on Windows piping/IO redirection under MSYS2 is wonky with llvm-objdump. +OBJDUMP = objdump + all: $(RUSTC) --crate-type dylib --crate-name raw_dylib_test lib.rs -C prefer-dynamic $(RUSTC) --crate-type dylib --crate-name raw_dylib_test_wrapper lib_wrapper.rs -C prefer-dynamic $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" -C prefer-dynamic # Make sure we don't find an import to the functions we expect to be inlined. - "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function" - "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline" + $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function" + $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline" # Make sure we do find an import to the functions we expect to be imported. - "$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function" + $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function" $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c) $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c) ifdef IS_MSVC diff --git a/tests/run-make/rlib-format-packed-bundled-libs-2/Makefile b/tests/run-make/rlib-format-packed-bundled-libs-2/Makefile index 4574cf17f0e..37b8d809a27 100644 --- a/tests/run-make/rlib-format-packed-bundled-libs-2/Makefile +++ b/tests/run-make/rlib-format-packed-bundled-libs-2/Makefile @@ -6,7 +6,12 @@ # We're using the llvm-nm instead of the system nm to ensure it is compatible # with the LLVM bitcode generated by rustc. +# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm. +ifndef IS_WINDOWS NM = "$(LLVM_BIN_DIR)"/llvm-nm +else +NM = nm +endif all: # Build strange-named dep. diff --git a/tests/run-make/rlib-format-packed-bundled-libs/Makefile b/tests/run-make/rlib-format-packed-bundled-libs/Makefile index 0b991ac42e3..7fb6ce8d1e4 100644 --- a/tests/run-make/rlib-format-packed-bundled-libs/Makefile +++ b/tests/run-make/rlib-format-packed-bundled-libs/Makefile @@ -6,7 +6,12 @@ # We're using the llvm-nm instead of the system nm to ensure it is compatible # with the LLVM bitcode generated by rustc. +# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm. +ifndef IS_WINDOWS NM = "$(LLVM_BIN_DIR)"/llvm-nm +else +NM = nm +endif all: $(call NATIVE_STATICLIB,native_dep_1) $(call NATIVE_STATICLIB,native_dep_2) $(call NATIVE_STATICLIB,native_dep_3) $(RUSTC) rust_dep_up.rs --crate-type=rlib -Zpacked_bundled_libs diff --git a/tests/rustdoc-gui/src-font-size.goml b/tests/rustdoc-gui/src-font-size.goml index 9233f37444b..bab66dae70c 100644 --- a/tests/rustdoc-gui/src-font-size.goml +++ b/tests/rustdoc-gui/src-font-size.goml @@ -4,13 +4,13 @@ goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" show-text: true // Check the impl headers. -assert-css: (".impl.has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL) -assert-css: (".impl.has-srclink .code-header", {"font-size": "18px", "font-weight": 600}, ALL) +assert-css: (".impl .srclink", {"font-size": "16px", "font-weight": 400}, ALL) +assert-css: (".impl .code-header", {"font-size": "18px", "font-weight": 600}, ALL) // Check the impl items. -assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL) -assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px", "font-weight": 600}, ALL) +assert-css: (".impl-items .srclink", {"font-size": "16px", "font-weight": 400}, ALL) +assert-css: (".impl-items .code-header", {"font-size": "16px", "font-weight": 600}, ALL) // Check that we can click on source link store-document-property: (url, "URL") -click: ".impl-items .has-srclink .srclink" +click: ".impl-items .srclink" assert-document-property-false: {"URL": |url|} diff --git a/tests/rustdoc/anchors.no_const_anchor.html b/tests/rustdoc/anchors.no_const_anchor.html index 75e67330a3e..a8587829d3e 100644 --- a/tests/rustdoc/anchors.no_const_anchor.html +++ b/tests/rustdoc/anchors.no_const_anchor.html @@ -1 +1 @@ - \ No newline at end of file +
source

const YOLO: u32

\ No newline at end of file diff --git a/tests/rustdoc/anchors.no_const_anchor2.html b/tests/rustdoc/anchors.no_const_anchor2.html index c0025197602..4c5e45fea2d 100644 --- a/tests/rustdoc/anchors.no_const_anchor2.html +++ b/tests/rustdoc/anchors.no_const_anchor2.html @@ -1 +1 @@ - \ No newline at end of file +
source

pub const X: i32 = 0i32

\ No newline at end of file diff --git a/tests/rustdoc/anchors.no_method_anchor.html b/tests/rustdoc/anchors.no_method_anchor.html index b9ec8bf4c09..44957a5b71a 100644 --- a/tests/rustdoc/anchors.no_method_anchor.html +++ b/tests/rustdoc/anchors.no_method_anchor.html @@ -1 +1 @@ - \ No newline at end of file +
source

pub fn new() -> Self

\ No newline at end of file diff --git a/tests/rustdoc/anchors.no_trait_method_anchor.html b/tests/rustdoc/anchors.no_trait_method_anchor.html index 4308ddad412..75c2caf87a8 100644 --- a/tests/rustdoc/anchors.no_trait_method_anchor.html +++ b/tests/rustdoc/anchors.no_trait_method_anchor.html @@ -1 +1 @@ - \ No newline at end of file +
source

fn bar()

\ No newline at end of file diff --git a/tests/rustdoc/anchors.no_tymethod_anchor.html b/tests/rustdoc/anchors.no_tymethod_anchor.html index 91eed8a3742..38575eadfa9 100644 --- a/tests/rustdoc/anchors.no_tymethod_anchor.html +++ b/tests/rustdoc/anchors.no_tymethod_anchor.html @@ -1 +1 @@ - \ No newline at end of file +
source

fn foo()

\ No newline at end of file diff --git a/tests/rustdoc/anchors.no_type_anchor.html b/tests/rustdoc/anchors.no_type_anchor.html index 2c66d5aa315..dd65d98fee6 100644 --- a/tests/rustdoc/anchors.no_type_anchor.html +++ b/tests/rustdoc/anchors.no_type_anchor.html @@ -1 +1 @@ - \ No newline at end of file +
source

type T

\ No newline at end of file diff --git a/tests/rustdoc/anchors.no_type_anchor2.html b/tests/rustdoc/anchors.no_type_anchor2.html index 72a1186bf7e..f8b59160f15 100644 --- a/tests/rustdoc/anchors.no_type_anchor2.html +++ b/tests/rustdoc/anchors.no_type_anchor2.html @@ -1 +1 @@ - +

type Y = u32

\ No newline at end of file diff --git a/tests/rustdoc/async-fn.rs b/tests/rustdoc/async-fn.rs index fb7ebb5f822..8cafb5a2497 100644 --- a/tests/rustdoc/async-fn.rs +++ b/tests/rustdoc/async-fn.rs @@ -77,12 +77,12 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T } impl Foo { // @has async_fn/struct.Foo.html - // @has - '//*[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator' + // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator' pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator {} // taken from `tokio` as an example of a method that was particularly bad before - // @has - '//*[@class="method has-srclink"]' "pub async fn readable(&self) -> Result, ()>" + // @has - '//*[@class="method"]' "pub async fn readable(&self) -> Result, ()>" pub async fn readable(&self) -> Result, ()> {} - // @has - '//*[@class="method has-srclink"]' "pub async fn mut_self(&mut self)" + // @has - '//*[@class="method"]' "pub async fn mut_self(&mut self)" pub async fn mut_self(&mut self) {} } diff --git a/tests/rustdoc/const-fn.rs b/tests/rustdoc/const-fn.rs index 4366ad4d0ad..18863abaeac 100644 --- a/tests/rustdoc/const-fn.rs +++ b/tests/rustdoc/const-fn.rs @@ -8,7 +8,7 @@ pub const fn bar() -> usize { } // @has foo/struct.Foo.html -// @has - '//*[@class="method has-srclink"]' 'const fn new()' +// @has - '//*[@class="method"]' 'const fn new()' pub struct Foo(usize); impl Foo { diff --git a/tests/rustdoc/const-generics/const-generic-slice.rs b/tests/rustdoc/const-generics/const-generic-slice.rs index 4279de91f56..80a9ab3f12e 100644 --- a/tests/rustdoc/const-generics/const-generic-slice.rs +++ b/tests/rustdoc/const-generics/const-generic-slice.rs @@ -5,7 +5,7 @@ pub trait Array { } // @has foo/trait.Array.html -// @has - '//*[@class="impl has-srclink"]' 'impl Array for [T; N]' +// @has - '//*[@class="impl"]' 'impl Array for [T; N]' impl Array for [T; N] { type Item = T; } diff --git a/tests/rustdoc/doc-assoc-item.rs b/tests/rustdoc/doc-assoc-item.rs index 4f15418650c..4d5c9f83e1e 100644 --- a/tests/rustdoc/doc-assoc-item.rs +++ b/tests/rustdoc/doc-assoc-item.rs @@ -8,7 +8,7 @@ pub trait Bar { fn foo(foo: Self::Fuu); } -// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl> Foo' +// @has doc_assoc_item/struct.Foo.html '//*[@class="impl"]' 'impl> Foo' impl> Foo { pub fn new(t: T) -> Foo { Foo { diff --git a/tests/rustdoc/duplicate_impls/issue-33054.rs b/tests/rustdoc/duplicate_impls/issue-33054.rs index c1f95ac91c3..4c2071b8322 100644 --- a/tests/rustdoc/duplicate_impls/issue-33054.rs +++ b/tests/rustdoc/duplicate_impls/issue-33054.rs @@ -3,8 +3,8 @@ // @has issue_33054/impls/struct.Foo.html // @has - '//h3[@class="code-header"]' 'impl Foo' // @has - '//h3[@class="code-header"]' 'impl Bar for Foo' -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1 +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl"]' 1 // @has issue_33054/impls/bar/trait.Bar.html // @has - '//h3[@class="code-header"]' 'impl Bar for Foo' // @count - '//*[@class="struct"]' 1 diff --git a/tests/rustdoc/duplicated_impl.rs b/tests/rustdoc/duplicated_impl.rs index 4e901b31c90..f32cf310055 100644 --- a/tests/rustdoc/duplicated_impl.rs +++ b/tests/rustdoc/duplicated_impl.rs @@ -7,7 +7,7 @@ // blanket implementations. // @has 'foo/struct.Whatever.html' -// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl has-srclink"]' 1 +// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl"]' 1 pub trait Something { } pub struct Whatever; diff --git a/tests/rustdoc/empty-impl-block-private-with-doc.rs b/tests/rustdoc/empty-impl-block-private-with-doc.rs index 43971996163..e6cff97b184 100644 --- a/tests/rustdoc/empty-impl-block-private-with-doc.rs +++ b/tests/rustdoc/empty-impl-block-private-with-doc.rs @@ -10,7 +10,7 @@ // There are 3 impl blocks with public item and one that should not be displayed // by default because it only contains private items (but not in this case because // we used `--document-private-items`). -// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 4 +// @count - '//*[@class="impl"]' 'impl Foo' 4 // Impl block only containing private items should not be displayed unless the // `--document-private-items` flag is used. diff --git a/tests/rustdoc/empty-impl-block-private.rs b/tests/rustdoc/empty-impl-block-private.rs index 5caf020658c..d44b4a47cee 100644 --- a/tests/rustdoc/empty-impl-block-private.rs +++ b/tests/rustdoc/empty-impl-block-private.rs @@ -7,7 +7,7 @@ // There are 3 impl blocks with public item and one that should not be displayed // because it only contains private items. -// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 3 +// @count - '//*[@class="impl"]' 'impl Foo' 3 // Impl block only containing private items should not be displayed. /// Private diff --git a/tests/rustdoc/empty-impl-block.rs b/tests/rustdoc/empty-impl-block.rs index 95d4db06b31..da780580bd0 100644 --- a/tests/rustdoc/empty-impl-block.rs +++ b/tests/rustdoc/empty-impl-block.rs @@ -8,7 +8,7 @@ /// Hello empty impl block! impl Foo {} // We ensure that this empty impl block without doc isn't rendered. -// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 1 +// @count - '//*[@class="impl"]' 'impl Foo' 1 impl Foo {} // Just to ensure that empty trait impl blocks are rendered. diff --git a/tests/rustdoc/impl-parts.rs b/tests/rustdoc/impl-parts.rs index 90cbb77cb6b..f7738060e99 100644 --- a/tests/rustdoc/impl-parts.rs +++ b/tests/rustdoc/impl-parts.rs @@ -5,7 +5,7 @@ pub struct Foo { field: T } -// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has impl_parts/struct.Foo.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !AnAutoTrait for Foowhere T: Sync + Clone," // @has impl_parts/trait.AnAutoTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \ // "impl !AnAutoTrait for Foowhere T: Sync + Clone," diff --git a/tests/rustdoc/inline_cross/issue-31948-1.rs b/tests/rustdoc/inline_cross/issue-31948-1.rs index 6e89167b3a4..571eaf6be96 100644 --- a/tests/rustdoc/inline_cross/issue-31948-1.rs +++ b/tests/rustdoc/inline_cross/issue-31948-1.rs @@ -5,8 +5,8 @@ extern crate rustdoc_nonreachable_impls; // @has issue_31948_1/struct.Wobble.html -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for' // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for' // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for' pub use rustdoc_nonreachable_impls::hidden::Wobble; diff --git a/tests/rustdoc/inline_cross/issue-31948-2.rs b/tests/rustdoc/inline_cross/issue-31948-2.rs index 141e07656a0..7eae21046cc 100644 --- a/tests/rustdoc/inline_cross/issue-31948-2.rs +++ b/tests/rustdoc/inline_cross/issue-31948-2.rs @@ -5,9 +5,9 @@ extern crate rustdoc_nonreachable_impls; // @has issue_31948_2/struct.Wobble.html -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Qux for' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for' // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for' pub use rustdoc_nonreachable_impls::hidden::Wobble; diff --git a/tests/rustdoc/inline_cross/issue-31948.rs b/tests/rustdoc/inline_cross/issue-31948.rs index 96fc6ca47e7..9c271bf4ad4 100644 --- a/tests/rustdoc/inline_cross/issue-31948.rs +++ b/tests/rustdoc/inline_cross/issue-31948.rs @@ -5,9 +5,9 @@ extern crate rustdoc_nonreachable_impls; // @has issue_31948/struct.Foo.html -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bark for' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Woof for' -// @!has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'Bar for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for' +// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for' // @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for' pub use rustdoc_nonreachable_impls::Foo; diff --git a/tests/rustdoc/issue-21474.rs b/tests/rustdoc/issue-21474.rs index 43ce13fd9b1..5de26abace6 100644 --- a/tests/rustdoc/issue-21474.rs +++ b/tests/rustdoc/issue-21474.rs @@ -7,5 +7,5 @@ impl super::Blah for super::What { } pub trait Blah { } // @count issue_21474/struct.What.html \ -// '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 +// '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 pub struct What; diff --git a/tests/rustdoc/issue-33302.rs b/tests/rustdoc/issue-33302.rs index b4c52e2f17a..7af00c77836 100644 --- a/tests/rustdoc/issue-33302.rs +++ b/tests/rustdoc/issue-33302.rs @@ -22,7 +22,7 @@ fn ignore(_: &X) {} } // @has issue_33302/struct.S.html \ - // '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S' + // '//*[@class="impl"]' 'impl T<[i32; 16]> for S' // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]' // @has - '//*[@id="associatedconstant.D"]' 'const D: i32' impl T<[i32; ($n * $n)]> for S { @@ -30,7 +30,7 @@ fn ignore(_: &X) {} } // @has issue_33302/struct.S.html \ - // '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S' + // '//*[@class="impl"]' 'impl T<[i32; 16]> for S' // @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)' // @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32' impl T<(i32,)> for S { @@ -38,7 +38,7 @@ impl T<(i32,)> for S { } // @has issue_33302/struct.S.html \ - // '//*[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S' + // '//*[@class="impl"]' 'impl T<(i32, i32)> for S' // @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)' // @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32' impl T<(i32, i32)> for S { diff --git a/tests/rustdoc/issue-45584.rs b/tests/rustdoc/issue-45584.rs index 86479e6fb2e..8a5f0413826 100644 --- a/tests/rustdoc/issue-45584.rs +++ b/tests/rustdoc/issue-45584.rs @@ -4,12 +4,12 @@ pub trait Bar {} // @has 'foo/struct.Foo1.html' pub struct Foo1; -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @has - '//*[@class="impl has-srclink"]' "impl Bar for Foo1" +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @has - '//*[@class="impl"]' "impl Bar for Foo1" impl Bar for Foo1 {} // @has 'foo/struct.Foo2.html' pub struct Foo2; -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8" +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8" impl Bar<&'static Foo2, Foo2> for u8 {} diff --git a/tests/rustdoc/issue-50159.rs b/tests/rustdoc/issue-50159.rs index 04bc4f304d6..13bedd5dbb0 100644 --- a/tests/rustdoc/issue-50159.rs +++ b/tests/rustdoc/issue-50159.rs @@ -14,7 +14,7 @@ impl Signal2 for B where B: Signal { // @has - '//h3[@class="code-header"]' 'impl Send for Switchwhere ::Item: Send' // @has - '//h3[@class="code-header"]' 'impl Sync for Switchwhere ::Item: Sync' // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 pub struct Switch { pub inner: ::Item2, } diff --git a/tests/rustdoc/issue-51236.rs b/tests/rustdoc/issue-51236.rs index 1c7aa9c7eef..04664805a88 100644 --- a/tests/rustdoc/issue-51236.rs +++ b/tests/rustdoc/issue-51236.rs @@ -7,7 +7,7 @@ pub trait Owned<'a> { } // @has issue_51236/struct.Owned.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl Send for Ownedwhere >::Reader: Send" pub struct Owned where T: for<'a> ::traits::Owned<'a> { marker: PhantomData<>::Reader>, diff --git a/tests/rustdoc/issue-53812.rs b/tests/rustdoc/issue-53812.rs index c68ffd52186..dc1eb304c3d 100644 --- a/tests/rustdoc/issue-53812.rs +++ b/tests/rustdoc/issue-53812.rs @@ -12,9 +12,9 @@ macro_rules! array_impls { } // @has issue_53812/trait.MyIterator.html -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>' -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>' -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>' -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>' -// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][1]' 'MyStruct<[T; 0]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][2]' 'MyStruct<[T; 1]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][3]' 'MyStruct<[T; 2]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][4]' 'MyStruct<[T; 3]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl"][5]' 'MyStruct<[T; 10]>' array_impls! { 10 3 2 1 0 } diff --git a/tests/rustdoc/issue-54705.rs b/tests/rustdoc/issue-54705.rs index 7b7290ab4b7..a886eb0de24 100644 --- a/tests/rustdoc/issue-54705.rs +++ b/tests/rustdoc/issue-54705.rs @@ -1,10 +1,10 @@ pub trait ScopeHandle<'scope> {} // @has issue_54705/struct.ScopeFutureContents.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'scope, S> Send for ScopeFutureContents<'scope, S>where S: Sync" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'scope, S> Sync for ScopeFutureContents<'scope, S>where S: Sync" pub struct ScopeFutureContents<'scope, S> where S: ScopeHandle<'scope>, diff --git a/tests/rustdoc/issue-55321.rs b/tests/rustdoc/issue-55321.rs index 22a18ef90e1..d3c2070d915 100644 --- a/tests/rustdoc/issue-55321.rs +++ b/tests/rustdoc/issue-55321.rs @@ -1,9 +1,9 @@ #![feature(negative_impls)] // @has issue_55321/struct.A.html -// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Send for A" -// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Sync for A" pub struct A(); @@ -11,8 +11,8 @@ impl !Send for A {} impl !Sync for A {} // @has issue_55321/struct.B.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Send for B" -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Sync for B" pub struct B(A, Box); diff --git a/tests/rustdoc/issue-56822.rs b/tests/rustdoc/issue-56822.rs index b4eef344b5f..c9a74335702 100644 --- a/tests/rustdoc/issue-56822.rs +++ b/tests/rustdoc/issue-56822.rs @@ -17,7 +17,7 @@ impl<'a, T> MyTrait for Inner<'a, T> { } // @has issue_56822/struct.Parser.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'a> Send for Parser<'a>" pub struct Parser<'a> { field: > as MyTrait>::Output diff --git a/tests/rustdoc/issue-60726.rs b/tests/rustdoc/issue-60726.rs index fbb0f82ae39..e337e4a4f7a 100644 --- a/tests/rustdoc/issue-60726.rs +++ b/tests/rustdoc/issue-60726.rs @@ -26,9 +26,9 @@ unsafe impl Send for DynTrait {} // @has issue_60726/struct.IntoIter.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Send for IntoIter" -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Sync for IntoIter" pub struct IntoIter{ hello:DynTrait>, diff --git a/tests/rustdoc/issue-76501.rs b/tests/rustdoc/issue-76501.rs index a90e0fea092..5caea0ec992 100644 --- a/tests/rustdoc/issue-76501.rs +++ b/tests/rustdoc/issue-76501.rs @@ -8,7 +8,7 @@ pub const fn bloop() -> i32 { pub struct Struct {} impl Struct { - // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \ + // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' \ // 'pub const fn blurp() -> i32' /// A useless function that always returns 1. pub const fn blurp() -> i32 { diff --git a/tests/rustdoc/issue-78673.rs b/tests/rustdoc/issue-78673.rs index 2e4bec2544c..d09141c3204 100644 --- a/tests/rustdoc/issue-78673.rs +++ b/tests/rustdoc/issue-78673.rs @@ -7,8 +7,8 @@ pub trait AnAmazingTrait {} impl AnAmazingTrait for T {} // @has 'issue_78673/struct.MyStruct.html' -// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct' -// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T' +// @has - '//*[@class="impl"]' 'AnAmazingTrait for MyStruct' +// @!has - '//*[@class="impl"]' 'AnAmazingTrait for T' pub struct MyStruct; impl AnAmazingTrait for MyStruct {} @@ -16,8 +16,8 @@ impl AnAmazingTrait for MyStruct {} // generic structs may have _both_ specific and blanket impls that apply // @has 'issue_78673/struct.AnotherStruct.html' -// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>' -// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T' +// @has - '//*[@class="impl"]' 'AnAmazingTrait for AnotherStruct<()>' +// @has - '//*[@class="impl"]' 'AnAmazingTrait for T' pub struct AnotherStruct(T); impl Something for AnotherStruct {} diff --git a/tests/rustdoc/mut-params.rs b/tests/rustdoc/mut-params.rs index 3b862e651c9..431db51d95f 100644 --- a/tests/rustdoc/mut-params.rs +++ b/tests/rustdoc/mut-params.rs @@ -5,7 +5,7 @@ pub struct Foo; -// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2 +// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method"]' 2 // @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut' impl Foo { pub fn foo(mut self) {} diff --git a/tests/rustdoc/negative-impl.rs b/tests/rustdoc/negative-impl.rs index af19c784d6d..51223af6737 100644 --- a/tests/rustdoc/negative-impl.rs +++ b/tests/rustdoc/negative-impl.rs @@ -5,10 +5,10 @@ // @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo" pub struct Bravo(B); -// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @matches negative_impl/struct.Alpha.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Send for Alpha" impl !Send for Alpha {} -// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' "\ +// @matches negative_impl/struct.Bravo.html '//*[@class="impl"]//h3[@class="code-header"]' "\ // impl !Send for Bravo" impl !Send for Bravo {} diff --git a/tests/rustdoc/primitive-reference.rs b/tests/rustdoc/primitive-reference.rs index c3a5eb6d324..10efbefd2b1 100644 --- a/tests/rustdoc/primitive-reference.rs +++ b/tests/rustdoc/primitive-reference.rs @@ -13,7 +13,7 @@ // @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' // There should be only one implementation listed. -// @count - '//*[@class="impl has-srclink"]' 1 +// @count - '//*[@class="impl"]' 1 // @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header"]' \ // 'impl Foo<&A> for &B' #[doc(primitive = "reference")] diff --git a/tests/rustdoc/pub-method.rs b/tests/rustdoc/pub-method.rs index 0dca3f672cd..7115a01d079 100644 --- a/tests/rustdoc/pub-method.rs +++ b/tests/rustdoc/pub-method.rs @@ -10,8 +10,8 @@ pub fn bar() -> usize { } // @has foo/struct.Foo.html -// @has - '//*[@class="method has-srclink"]' 'pub fn new()' -// @has - '//*[@class="method has-srclink"]' 'fn not_pub()' +// @has - '//*[@class="method"]' 'pub fn new()' +// @has - '//*[@class="method"]' 'fn not_pub()' pub struct Foo(usize); impl Foo { diff --git a/tests/rustdoc/synthetic_auto/basic.rs b/tests/rustdoc/synthetic_auto/basic.rs index 7c6a388653c..043ac241488 100644 --- a/tests/rustdoc/synthetic_auto/basic.rs +++ b/tests/rustdoc/synthetic_auto/basic.rs @@ -1,8 +1,8 @@ // @has basic/struct.Foo.html // @has - '//h3[@class="code-header"]' 'impl Send for Foowhere T: Send' // @has - '//h3[@class="code-header"]' 'impl Sync for Foowhere T: Sync' -// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5 +// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 pub struct Foo { field: T, } diff --git a/tests/rustdoc/synthetic_auto/complex.rs b/tests/rustdoc/synthetic_auto/complex.rs index 43393c21fdd..4c39f0bf1e0 100644 --- a/tests/rustdoc/synthetic_auto/complex.rs +++ b/tests/rustdoc/synthetic_auto/complex.rs @@ -20,7 +20,7 @@ pub struct Foo { } // @has complex/struct.NotOuter.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K>where K: for<'b> Fn((&'b bool, &'a u8)) \ // -> &'b i8, T: MyTrait<'a>, >::MyItem: Copy, 'a: 'static" diff --git a/tests/rustdoc/synthetic_auto/lifetimes.rs b/tests/rustdoc/synthetic_auto/lifetimes.rs index 33170a84435..71265b3078a 100644 --- a/tests/rustdoc/synthetic_auto/lifetimes.rs +++ b/tests/rustdoc/synthetic_auto/lifetimes.rs @@ -9,10 +9,10 @@ unsafe impl<'a, T> Send for Inner<'a, T> {} // @has lifetimes/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'c, K> Send for Foo<'c, K>where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'c, K> Sync for Foo<'c, K>where K: Sync" pub struct Foo<'c, K: 'c> { inner_field: Inner<'c, K>, diff --git a/tests/rustdoc/synthetic_auto/manual.rs b/tests/rustdoc/synthetic_auto/manual.rs index 77c04ad2ad9..7fc8447df3e 100644 --- a/tests/rustdoc/synthetic_auto/manual.rs +++ b/tests/rustdoc/synthetic_auto/manual.rs @@ -1,12 +1,12 @@ // @has manual/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // 'impl Sync for Foowhere T: Sync' // -// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // 'impl Send for Foo' // -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4 +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4 pub struct Foo { field: T, } diff --git a/tests/rustdoc/synthetic_auto/negative.rs b/tests/rustdoc/synthetic_auto/negative.rs index 2c2c848a5e0..97da2d57424 100644 --- a/tests/rustdoc/synthetic_auto/negative.rs +++ b/tests/rustdoc/synthetic_auto/negative.rs @@ -3,10 +3,10 @@ pub struct Inner { } // @has negative/struct.Outer.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Send for Outer" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl !Sync for Outer" pub struct Outer { inner_field: Inner, diff --git a/tests/rustdoc/synthetic_auto/nested.rs b/tests/rustdoc/synthetic_auto/nested.rs index 423bf115ab1..e4aead71bf2 100644 --- a/tests/rustdoc/synthetic_auto/nested.rs +++ b/tests/rustdoc/synthetic_auto/nested.rs @@ -9,10 +9,10 @@ unsafe impl Send for Inner } // @has nested/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // 'impl Send for Foowhere T: Copy' // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // 'impl Sync for Foowhere T: Sync' pub struct Foo { inner_field: Inner, diff --git a/tests/rustdoc/synthetic_auto/no-redundancy.rs b/tests/rustdoc/synthetic_auto/no-redundancy.rs index 59f33623322..ea57d7388b8 100644 --- a/tests/rustdoc/synthetic_auto/no-redundancy.rs +++ b/tests/rustdoc/synthetic_auto/no-redundancy.rs @@ -9,7 +9,7 @@ unsafe impl Send for Inner } // @has no_redundancy/struct.Outer.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl Send for Outerwhere T: Send + Copy" pub struct Outer { inner_field: Inner, diff --git a/tests/rustdoc/synthetic_auto/project.rs b/tests/rustdoc/synthetic_auto/project.rs index 558ff2add40..7c9412ae962 100644 --- a/tests/rustdoc/synthetic_auto/project.rs +++ b/tests/rustdoc/synthetic_auto/project.rs @@ -23,10 +23,10 @@ unsafe impl<'a, T> Sync for Inner<'a, T> } // @has project/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'c, K> Send for Foo<'c, K>where K: MyTrait, 'c: 'static" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl<'c, K> Sync for Foo<'c, K>where K: MyTrait, ::MyItem: OtherTrait, \ // 'c: 'static," pub struct Foo<'c, K: 'c> { diff --git a/tests/rustdoc/synthetic_auto/self-referential.rs b/tests/rustdoc/synthetic_auto/self-referential.rs index c6ae96de776..145a2b7e00c 100644 --- a/tests/rustdoc/synthetic_auto/self-referential.rs +++ b/tests/rustdoc/synthetic_auto/self-referential.rs @@ -23,7 +23,7 @@ impl Pattern for Wrapper { // @has self_referential/struct.WriteAndThen.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl Send for WriteAndThenwhere ::Value: Send" pub struct WriteAndThen(pub P1::Value,pub > as Pattern>::Value) where P1: Pattern; diff --git a/tests/rustdoc/synthetic_auto/static-region.rs b/tests/rustdoc/synthetic_auto/static-region.rs index 1a76cb919c2..9dc6211ec20 100644 --- a/tests/rustdoc/synthetic_auto/static-region.rs +++ b/tests/rustdoc/synthetic_auto/static-region.rs @@ -3,7 +3,7 @@ pub trait OwnedTrait<'a> { } // @has static_region/struct.Owned.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ // "impl Send for Ownedwhere >::Reader: Send" pub struct Owned where T: OwnedTrait<'static> { marker: >::Reader, diff --git a/tests/rustdoc/typedef.rs b/tests/rustdoc/typedef.rs index d5dfa948489..63e2973c759 100644 --- a/tests/rustdoc/typedef.rs +++ b/tests/rustdoc/typedef.rs @@ -9,8 +9,8 @@ pub fn method_on_mystruct() {} } // @has typedef/type.MyAlias.html -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyAlias' -// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyAlias' +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias' // @hasraw - 'Alias docstring' // @has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias' // @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods' diff --git a/tests/rustdoc/where.rs b/tests/rustdoc/where.rs index 3ac0c6872a8..644a0058244 100644 --- a/tests/rustdoc/where.rs +++ b/tests/rustdoc/where.rs @@ -13,7 +13,7 @@ pub fn charlie() where C: MyTrait {} pub struct Delta(D); -// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has foo/struct.Delta.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl Deltawhere D: MyTrait" impl Delta where D: MyTrait { pub fn delta() {} @@ -43,7 +43,7 @@ fn lines(self) -> Lines { todo!() } } -// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has foo/struct.Echo.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl MyTrait for Echowhere E: MyTrait" // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \ // "impl MyTrait for Echowhere E: MyTrait" @@ -51,7 +51,7 @@ impl MyTrait for Echowhere E: MyTrait {} pub enum Foxtrot { Foxtrot1(F) } -// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header"]' \ +// @has foo/enum.Foxtrot.html '//*[@class="impl"]//h3[@class="code-header"]' \ // "impl MyTrait for Foxtrotwhere F: MyTrait" // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header"]' \ // "impl MyTrait for Foxtrotwhere F: MyTrait" diff --git a/tests/ui/derives/deriving-with-repr-packed-2.rs b/tests/ui/derives/deriving-with-repr-packed-2.rs new file mode 100644 index 00000000000..cbd7432fce4 --- /dev/null +++ b/tests/ui/derives/deriving-with-repr-packed-2.rs @@ -0,0 +1,22 @@ +#![deny(unaligned_references)] + +// Check that deriving certain builtin traits on certain packed structs cause +// errors. To avoid potentially misaligned references, field copies must be +// used, which involves adding `T: Copy` bounds. + +#[derive(Copy, Clone, Default, PartialEq, Eq)] +#[repr(packed)] +pub struct Foo(T, T, T); + +struct NonCopy; + +fn main() { + // This one is fine because `u32` impls `Copy`. + let x: Foo = Foo(1, 2, 3); + _ = x.clone(); + + // This one is an error because `NonCopy` doesn't impl `Copy`. + let x: Foo = Foo(NonCopy, NonCopy, NonCopy); + _ = x.clone(); + //~^ ERROR the method `clone` exists for struct `Foo`, but its trait bounds were not satisfied +} diff --git a/tests/ui/derives/deriving-with-repr-packed-2.stderr b/tests/ui/derives/deriving-with-repr-packed-2.stderr new file mode 100644 index 00000000000..83540739ee3 --- /dev/null +++ b/tests/ui/derives/deriving-with-repr-packed-2.stderr @@ -0,0 +1,33 @@ +error[E0599]: the method `clone` exists for struct `Foo`, but its trait bounds were not satisfied + --> $DIR/deriving-with-repr-packed-2.rs:20:11 + | +LL | pub struct Foo(T, T, T); + | ----------------- + | | + | method `clone` not found for this struct + | doesn't satisfy `Foo: Clone` +LL | +LL | struct NonCopy; + | -------------- + | | + | doesn't satisfy `NonCopy: Clone` + | doesn't satisfy `NonCopy: Copy` +... +LL | _ = x.clone(); + | ^^^^^ method cannot be called on `Foo` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `NonCopy: Clone` + `NonCopy: Copy` + --> $DIR/deriving-with-repr-packed-2.rs:7:16 + | +LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] + | ^^^^^ unsatisfied trait bound introduced in this `derive` macro +help: consider annotating `NonCopy` with `#[derive(Clone, Copy)]` + | +LL | #[derive(Clone, Copy)] + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/derives/deriving-with-repr-packed.rs b/tests/ui/derives/deriving-with-repr-packed.rs index 3884e397764..eddf41f5553 100644 --- a/tests/ui/derives/deriving-with-repr-packed.rs +++ b/tests/ui/derives/deriving-with-repr-packed.rs @@ -1,45 +1,38 @@ #![deny(unaligned_references)] // Check that deriving certain builtin traits on certain packed structs cause -// errors. This happens when the derived trait would need to use a potentially -// misaligned reference. But there are two cases that are allowed: -// - If all the fields within the struct meet the required alignment: 1 for -// `repr(packed)`, or `N` for `repr(packed(N))`. -// - If `Default` is the only trait derived, because it doesn't involve any -// references. +// errors. To avoid potentially misaligned references, field copies must be +// used, which involves adding `T: Copy` bounds. #[derive(Copy, Clone, Default, PartialEq, Eq)] -//~^ ERROR `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters -//~| hard error -//~^^^ ERROR `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters -//~| hard error #[repr(packed)] pub struct Foo(T, T, T); +// This one is fine because the fields all impl `Copy`. #[derive(Default, Hash)] -//~^ ERROR `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` -//~| hard error #[repr(packed)] pub struct Bar(u32, u32, u32); -// This one is fine because the field alignment is 1. -#[derive(Default, Hash)] -#[repr(packed)] -pub struct Bar2(u8, i8, bool); - -// This one is fine because the field alignment is 2, matching `packed(2)`. -#[derive(Default, Hash)] -#[repr(packed(2))] -pub struct Bar3(u16, i16, bool); - // This one is fine because it's not packed. #[derive(Debug, Default)] struct Y(usize); +// This one has an error because `Y` doesn't impl `Copy`. +// Note: there is room for improvement in the error message. #[derive(Debug, Default)] -//~^ ERROR `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` -//~| hard error #[repr(packed)] struct X(Y); +//~^ ERROR cannot move out of `self` which is behind a shared reference + +// This is currently allowed, but will be phased out at some point. From +// `zerovec` within icu4x-0.9.0. +#[derive(Debug)] +#[repr(packed)] +struct FlexZeroSlice { + width: u8, + data: [u8], + //~^ WARNING byte slice in a packed struct that derives a built-in trait + //~^^ this was previously accepted +} fn main() {} diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr index 0ad800c3981..2cb2a696d97 100644 --- a/tests/ui/derives/deriving-with-repr-packed.stderr +++ b/tests/ui/derives/deriving-with-repr-packed.stderr @@ -1,111 +1,45 @@ -error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:16 +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-with-repr-packed.rs:33:5 | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^ +LL | #[derive(Debug)] + | ----- in this derive macro expansion +... +LL | data: [u8], + | ^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:32 - | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:19:19 - | -LL | #[derive(Default, Hash)] - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: for more information, see issue #107457 + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) -error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:39:10 +error[E0507]: cannot move out of `self` which is behind a shared reference + --> $DIR/deriving-with-repr-packed.rs:24:10 | LL | #[derive(Debug, Default)] - | ^^^^^ + | ----- in this derive macro expansion +LL | #[repr(packed)] +LL | struct X(Y); + | ^ move occurs because `self.0` has type `Y`, which does not implement the `Copy` trait | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: aborting due to previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0507`. Future incompatibility report: Future breakage diagnostic: -error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:16 - | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) - -Future breakage diagnostic: -error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters - --> $DIR/deriving-with-repr-packed.rs:11:32 - | -LL | #[derive(Copy, Clone, Default, PartialEq, Eq)] - | ^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) - -Future breakage diagnostic: -error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:19:19 - | -LL | #[derive(Default, Hash)] - | ^^^^ +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-with-repr-packed.rs:33:5 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) - -Future breakage diagnostic: -error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy` - --> $DIR/deriving-with-repr-packed.rs:39:10 - | -LL | #[derive(Debug, Default)] - | ^^^^^ +LL | #[derive(Debug)] + | ----- in this derive macro expansion +... +LL | data: [u8], + | ^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82523 -note: the lint level is defined here - --> $DIR/deriving-with-repr-packed.rs:1:9 - | -LL | #![deny(unaligned_references)] - | ^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: for more information, see issue #107457 + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs index ba7809413bd..51f9708d3cd 100644 --- a/tests/ui/deriving/deriving-all-codegen.rs +++ b/tests/ui/deriving/deriving-all-codegen.rs @@ -21,36 +21,88 @@ #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Empty; -// A basic struct. +// A basic struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Point { x: u32, y: u32, } -// A large struct. -#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +// A basic packed struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[repr(packed)] +struct PackedPoint { + x: u32, + y: u32, +} + +// A large struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Big { b1: u32, b2: u32, b3: u32, b4: u32, b5: u32, b6: u32, b7: u32, b8: u32, } +// A struct that doesn't impl `Copy`, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +#[derive(Clone)] +struct NonCopy(u32); + +// A packed struct that doesn't impl `Copy`, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +#[derive(Clone)] +#[repr(packed)] +struct PackedNonCopy(u32); + +// A struct that impls `Copy` manually, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +#[derive(Clone)] +struct ManualCopy(u32); +impl Copy for ManualCopy {} + +// A packed struct that impls `Copy` manually, which means it gets the +// non-simple `clone` implemention that clones the fields individually. +#[derive(Clone)] +#[repr(packed)] +struct PackedManualCopy(u32); +impl Copy for PackedManualCopy {} + // A struct with an unsized field. Some derives are not usable in this case. #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Unsized([u32]); -// A packed tuple struct that impls `Copy`. -#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +// A packed struct with an unsized `[u8]` field. This is currently allowed, but +// causes a warning and will be phased out at some point. +#[derive(Debug, Hash)] #[repr(packed)] -struct PackedCopy(u32); +struct PackedUnsizedU8([u8]); +//~^ WARNING byte slice in a packed struct that derives a built-in trait +//~^^ WARNING byte slice in a packed struct that derives a built-in trait +//~^^^ this was previously accepted +//~^^^^ this was previously accepted -// A packed tuple struct that does not impl `Copy`. Note that the alignment of -// the field must be 1 for this code to be valid. Otherwise it triggers an -// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not -// derive Copy (error E0133)" at MIR building time. This is a weird case and -// it's possible that this struct is not supposed to work, but for now it does. -#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +trait Trait { + type A; +} + +// A generic struct involving an associated type. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +struct Generic { + t: T, + ta: T::A, + u: U, +} + +// A packed, generic tuple struct involving an associated type. Because it is +// packed, a `T: Copy` bound is added to all impls (and where clauses within +// them) except for `Default`. This is because we must access fields using +// copies (e.g. `&{self.0}`), instead of using direct references (e.g. +// `&self.0`) which may be misaligned in a packed struct. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] #[repr(packed)] -struct PackedNonCopy(u8); +struct PackedGeneric(T, T::A, U); // An empty enum. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -97,6 +149,13 @@ enum Fielded { Z(Option), } +// A generic enum. Note that `Default` cannot be derived for this enum. +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +enum EnumGeneric { + One(T), + Two(U), +} + // A union. Most builtin traits are not derivable for unions. #[derive(Clone, Copy)] pub union Union { diff --git a/tests/ui/deriving/deriving-all-codegen.stderr b/tests/ui/deriving/deriving-all-codegen.stderr new file mode 100644 index 00000000000..503f0cae73b --- /dev/null +++ b/tests/ui/deriving/deriving-all-codegen.stderr @@ -0,0 +1,63 @@ +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:80:24 + | +LL | #[derive(Debug, Hash)] + | ----- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #107457 + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:80:24 + | +LL | #[derive(Debug, Hash)] + | ---- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #107457 + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 2 warnings emitted + +Future incompatibility report: Future breakage diagnostic: +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:80:24 + | +LL | #[derive(Debug, Hash)] + | ----- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #107457 + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: byte slice in a packed struct that derives a built-in trait + --> $DIR/deriving-all-codegen.rs:80:24 + | +LL | #[derive(Debug, Hash)] + | ---- in this derive macro expansion +LL | #[repr(packed)] +LL | struct PackedUnsizedU8([u8]); + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #107457 + = help: consider implementing the trait by hand, or remove the `packed` attribute + = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default + = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 2a93a05c627..b4874cef134 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -78,7 +78,8 @@ impl ::core::cmp::Ord for Empty { } } -// A basic struct. +// A basic struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. struct Point { x: u32, y: u32, @@ -161,7 +162,95 @@ impl ::core::cmp::Ord for Point { } } -// A large struct. +// A basic packed struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. +#[repr(packed)] +struct PackedPoint { + x: u32, + y: u32, +} +#[automatically_derived] +impl ::core::clone::Clone for PackedPoint { + #[inline] + fn clone(&self) -> PackedPoint { + let _: ::core::clone::AssertParamIsClone; + *self + } +} +#[automatically_derived] +impl ::core::marker::Copy for PackedPoint { } +#[automatically_derived] +impl ::core::fmt::Debug for PackedPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_struct_field2_finish(f, "PackedPoint", + "x", &&{ self.x }, "y", &&{ self.y }) + } +} +#[automatically_derived] +impl ::core::default::Default for PackedPoint { + #[inline] + fn default() -> PackedPoint { + PackedPoint { + x: ::core::default::Default::default(), + y: ::core::default::Default::default(), + } + } +} +#[automatically_derived] +impl ::core::hash::Hash for PackedPoint { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + ::core::hash::Hash::hash(&{ self.x }, state); + ::core::hash::Hash::hash(&{ self.y }, state) + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for PackedPoint { } +#[automatically_derived] +impl ::core::cmp::PartialEq for PackedPoint { + #[inline] + fn eq(&self, other: &PackedPoint) -> bool { + { self.x } == { other.x } && { self.y } == { other.y } + } +} +#[automatically_derived] +impl ::core::marker::StructuralEq for PackedPoint { } +#[automatically_derived] +impl ::core::cmp::Eq for PackedPoint { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq; + } +} +#[automatically_derived] +impl ::core::cmp::PartialOrd for PackedPoint { + #[inline] + fn partial_cmp(&self, other: &PackedPoint) + -> ::core::option::Option<::core::cmp::Ordering> { + match ::core::cmp::PartialOrd::partial_cmp(&{ self.x }, &{ other.x }) + { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + ::core::cmp::PartialOrd::partial_cmp(&{ self.y }, + &{ other.y }), + cmp => cmp, + } + } +} +#[automatically_derived] +impl ::core::cmp::Ord for PackedPoint { + #[inline] + fn cmp(&self, other: &PackedPoint) -> ::core::cmp::Ordering { + match ::core::cmp::Ord::cmp(&{ self.x }, &{ other.x }) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(&{ self.y }, &{ other.y }), + cmp => cmp, + } + } +} + +// A large struct. Note: because this derives `Copy`, it gets the simple +// `clone` implemention that just does `*self`. struct Big { b1: u32, b2: u32, @@ -176,19 +265,13 @@ struct Big { impl ::core::clone::Clone for Big { #[inline] fn clone(&self) -> Big { - Big { - b1: ::core::clone::Clone::clone(&self.b1), - b2: ::core::clone::Clone::clone(&self.b2), - b3: ::core::clone::Clone::clone(&self.b3), - b4: ::core::clone::Clone::clone(&self.b4), - b5: ::core::clone::Clone::clone(&self.b5), - b6: ::core::clone::Clone::clone(&self.b6), - b7: ::core::clone::Clone::clone(&self.b7), - b8: ::core::clone::Clone::clone(&self.b8), - } + let _: ::core::clone::AssertParamIsClone; + *self } } #[automatically_derived] +impl ::core::marker::Copy for Big { } +#[automatically_derived] impl ::core::fmt::Debug for Big { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { let names: &'static _ = @@ -336,6 +419,54 @@ impl ::core::cmp::Ord for Big { } } +// A struct that doesn't impl `Copy`, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +struct NonCopy(u32); +#[automatically_derived] +impl ::core::clone::Clone for NonCopy { + #[inline] + fn clone(&self) -> NonCopy { + NonCopy(::core::clone::Clone::clone(&self.0)) + } +} + +// A packed struct that doesn't impl `Copy`, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +#[repr(packed)] +struct PackedNonCopy(u32); +#[automatically_derived] +impl ::core::clone::Clone for PackedNonCopy { + #[inline] + fn clone(&self) -> PackedNonCopy { + PackedNonCopy(::core::clone::Clone::clone(&{ self.0 })) + } +} + +// A struct that impls `Copy` manually, which means it gets the non-simple +// `clone` implemention that clones the fields individually. +struct ManualCopy(u32); +#[automatically_derived] +impl ::core::clone::Clone for ManualCopy { + #[inline] + fn clone(&self) -> ManualCopy { + ManualCopy(::core::clone::Clone::clone(&self.0)) + } +} +impl Copy for ManualCopy {} + +// A packed struct that impls `Copy` manually, which means it gets the +// non-simple `clone` implemention that clones the fields individually. +#[repr(packed)] +struct PackedManualCopy(u32); +#[automatically_derived] +impl ::core::clone::Clone for PackedManualCopy { + #[inline] + fn clone(&self) -> PackedManualCopy { + PackedManualCopy(::core::clone::Clone::clone(&{ self.0 })) + } +} +impl Copy for PackedManualCopy {} + // A struct with an unsized field. Some derives are not usable in this case. struct Unsized([u32]); #[automatically_derived] @@ -385,138 +516,265 @@ impl ::core::cmp::Ord for Unsized { } } -// A packed tuple struct that impls `Copy`. +// A packed struct with an unsized `[u8]` field. This is currently allowed, but +// causes a warning and will be phased out at some point. #[repr(packed)] -struct PackedCopy(u32); +struct PackedUnsizedU8([u8]); +#[automatically_derived] +impl ::core::fmt::Debug for PackedUnsizedU8 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_tuple_field1_finish(f, + "PackedUnsizedU8", &&self.0) + } +} #[automatically_derived] -impl ::core::clone::Clone for PackedCopy { +impl ::core::hash::Hash for PackedUnsizedU8 { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + ::core::hash::Hash::hash(&self.0, state) + } +} + +trait Trait { + type A; +} + +// A generic struct involving an associated type. +struct Generic { + t: T, + ta: T::A, + u: U, +} +#[automatically_derived] +impl + ::core::clone::Clone for Generic where T::A: ::core::clone::Clone { #[inline] - fn clone(&self) -> PackedCopy { - let _: ::core::clone::AssertParamIsClone; - *self + fn clone(&self) -> Generic { + Generic { + t: ::core::clone::Clone::clone(&self.t), + ta: ::core::clone::Clone::clone(&self.ta), + u: ::core::clone::Clone::clone(&self.u), + } } } #[automatically_derived] -impl ::core::marker::Copy for PackedCopy { } +impl + ::core::marker::Copy for Generic where T::A: ::core::marker::Copy { +} #[automatically_derived] -impl ::core::fmt::Debug for PackedCopy { +impl ::core::fmt::Debug + for Generic where T::A: ::core::fmt::Debug { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedCopy", - &&{ self.0 }) + ::core::fmt::Formatter::debug_struct_field3_finish(f, "Generic", "t", + &&self.t, "ta", &&self.ta, "u", &&self.u) } } #[automatically_derived] -impl ::core::default::Default for PackedCopy { +impl + ::core::default::Default for Generic where + T::A: ::core::default::Default { #[inline] - fn default() -> PackedCopy { - PackedCopy(::core::default::Default::default()) + fn default() -> Generic { + Generic { + t: ::core::default::Default::default(), + ta: ::core::default::Default::default(), + u: ::core::default::Default::default(), + } } } #[automatically_derived] -impl ::core::hash::Hash for PackedCopy { +impl ::core::hash::Hash + for Generic where T::A: ::core::hash::Hash { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - ::core::hash::Hash::hash(&{ self.0 }, state) + ::core::hash::Hash::hash(&self.t, state); + ::core::hash::Hash::hash(&self.ta, state); + ::core::hash::Hash::hash(&self.u, state) } } #[automatically_derived] -impl ::core::marker::StructuralPartialEq for PackedCopy { } +impl ::core::marker::StructuralPartialEq for Generic { } #[automatically_derived] -impl ::core::cmp::PartialEq for PackedCopy { +impl + ::core::cmp::PartialEq for Generic where + T::A: ::core::cmp::PartialEq { #[inline] - fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } } + fn eq(&self, other: &Generic) -> bool { + self.t == other.t && self.ta == other.ta && self.u == other.u + } } #[automatically_derived] -impl ::core::marker::StructuralEq for PackedCopy { } +impl ::core::marker::StructuralEq for Generic { } #[automatically_derived] -impl ::core::cmp::Eq for PackedCopy { +impl ::core::cmp::Eq for + Generic where T::A: ::core::cmp::Eq { #[inline] #[doc(hidden)] #[no_coverage] fn assert_receiver_is_total_eq(&self) -> () { - let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; } } #[automatically_derived] -impl ::core::cmp::PartialOrd for PackedCopy { +impl + ::core::cmp::PartialOrd for Generic where + T::A: ::core::cmp::PartialOrd { #[inline] - fn partial_cmp(&self, other: &PackedCopy) + fn partial_cmp(&self, other: &Generic) -> ::core::option::Option<::core::cmp::Ordering> { - ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) + match ::core::cmp::PartialOrd::partial_cmp(&self.t, &other.t) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match ::core::cmp::PartialOrd::partial_cmp(&self.ta, + &other.ta) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => ::core::cmp::PartialOrd::partial_cmp(&self.u, &other.u), + cmp => cmp, + }, + cmp => cmp, + } } } #[automatically_derived] -impl ::core::cmp::Ord for PackedCopy { +impl ::core::cmp::Ord for + Generic where T::A: ::core::cmp::Ord { #[inline] - fn cmp(&self, other: &PackedCopy) -> ::core::cmp::Ordering { - ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 }) + fn cmp(&self, other: &Generic) -> ::core::cmp::Ordering { + match ::core::cmp::Ord::cmp(&self.t, &other.t) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.ta, &other.ta) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(&self.u, &other.u), + cmp => cmp, + }, + cmp => cmp, + } } } -// A packed tuple struct that does not impl `Copy`. Note that the alignment of -// the field must be 1 for this code to be valid. Otherwise it triggers an -// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not -// derive Copy (error E0133)" at MIR building time. This is a weird case and -// it's possible that this struct is not supposed to work, but for now it does. +// A packed, generic tuple struct involving an associated type. Because it is +// packed, a `T: Copy` bound is added to all impls (and where clauses within +// them) except for `Default`. This is because we must access fields using +// copies (e.g. `&{self.0}`), instead of using direct references (e.g. +// `&self.0`) which may be misaligned in a packed struct. #[repr(packed)] -struct PackedNonCopy(u8); +struct PackedGeneric(T, T::A, U); #[automatically_derived] -impl ::core::clone::Clone for PackedNonCopy { +impl ::core::clone::Clone for + PackedGeneric where T::A: ::core::clone::Clone + + ::core::marker::Copy { #[inline] - fn clone(&self) -> PackedNonCopy { - PackedNonCopy(::core::clone::Clone::clone(&self.0)) + fn clone(&self) -> PackedGeneric { + PackedGeneric(::core::clone::Clone::clone(&{ self.0 }), + ::core::clone::Clone::clone(&{ self.1 }), + ::core::clone::Clone::clone(&{ self.2 })) } } #[automatically_derived] -impl ::core::fmt::Debug for PackedNonCopy { +impl + ::core::marker::Copy for PackedGeneric where + T::A: ::core::marker::Copy { +} +#[automatically_derived] +impl ::core::fmt::Debug for + PackedGeneric where T::A: ::core::fmt::Debug + ::core::marker::Copy + { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedNonCopy", - &&self.0) + ::core::fmt::Formatter::debug_tuple_field3_finish(f, "PackedGeneric", + &&{ self.0 }, &&{ self.1 }, &&{ self.2 }) } } #[automatically_derived] -impl ::core::default::Default for PackedNonCopy { +impl + ::core::default::Default for PackedGeneric where + T::A: ::core::default::Default { #[inline] - fn default() -> PackedNonCopy { - PackedNonCopy(::core::default::Default::default()) + fn default() -> PackedGeneric { + PackedGeneric(::core::default::Default::default(), + ::core::default::Default::default(), + ::core::default::Default::default()) } } #[automatically_derived] -impl ::core::hash::Hash for PackedNonCopy { +impl ::core::hash::Hash for + PackedGeneric where T::A: ::core::hash::Hash + ::core::marker::Copy + { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - ::core::hash::Hash::hash(&self.0, state) + ::core::hash::Hash::hash(&{ self.0 }, state); + ::core::hash::Hash::hash(&{ self.1 }, state); + ::core::hash::Hash::hash(&{ self.2 }, state) } } #[automatically_derived] -impl ::core::marker::StructuralPartialEq for PackedNonCopy { } +impl ::core::marker::StructuralPartialEq for PackedGeneric + { +} #[automatically_derived] -impl ::core::cmp::PartialEq for PackedNonCopy { +impl ::core::cmp::PartialEq + for PackedGeneric where T::A: ::core::cmp::PartialEq + + ::core::marker::Copy { #[inline] - fn eq(&self, other: &PackedNonCopy) -> bool { self.0 == other.0 } + fn eq(&self, other: &PackedGeneric) -> bool { + { self.0 } == { other.0 } && { self.1 } == { other.1 } && + { self.2 } == { other.2 } + } } #[automatically_derived] -impl ::core::marker::StructuralEq for PackedNonCopy { } +impl ::core::marker::StructuralEq for PackedGeneric { } #[automatically_derived] -impl ::core::cmp::Eq for PackedNonCopy { +impl ::core::cmp::Eq for PackedGeneric where + T::A: ::core::cmp::Eq + ::core::marker::Copy { #[inline] #[doc(hidden)] #[no_coverage] fn assert_receiver_is_total_eq(&self) -> () { - let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; } } #[automatically_derived] -impl ::core::cmp::PartialOrd for PackedNonCopy { +impl ::core::cmp::PartialOrd + for PackedGeneric where T::A: ::core::cmp::PartialOrd + + ::core::marker::Copy { #[inline] - fn partial_cmp(&self, other: &PackedNonCopy) + fn partial_cmp(&self, other: &PackedGeneric) -> ::core::option::Option<::core::cmp::Ordering> { - ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0) + match ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) + { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match ::core::cmp::PartialOrd::partial_cmp(&{ self.1 }, + &{ other.1 }) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + ::core::cmp::PartialOrd::partial_cmp(&{ self.2 }, + &{ other.2 }), + cmp => cmp, + }, + cmp => cmp, + } } } #[automatically_derived] -impl ::core::cmp::Ord for PackedNonCopy { +impl ::core::cmp::Ord for PackedGeneric where + T::A: ::core::cmp::Ord + ::core::marker::Copy { #[inline] - fn cmp(&self, other: &PackedNonCopy) -> ::core::cmp::Ordering { - ::core::cmp::Ord::cmp(&self.0, &other.0) + fn cmp(&self, other: &PackedGeneric) -> ::core::cmp::Ordering { + match ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 }) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&{ self.1 }, &{ other.1 }) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(&{ self.2 }, &{ other.2 }), + cmp => cmp, + }, + cmp => cmp, + } } } @@ -1051,6 +1309,125 @@ impl ::core::cmp::Ord for Fielded { } } +// A generic enum. Note that `Default` cannot be derived for this enum. +enum EnumGeneric { One(T), Two(U), } +#[automatically_derived] +impl ::core::clone::Clone + for EnumGeneric { + #[inline] + fn clone(&self) -> EnumGeneric { + match self { + EnumGeneric::One(__self_0) => + EnumGeneric::One(::core::clone::Clone::clone(__self_0)), + EnumGeneric::Two(__self_0) => + EnumGeneric::Two(::core::clone::Clone::clone(__self_0)), + } + } +} +#[automatically_derived] +impl ::core::marker::Copy + for EnumGeneric { +} +#[automatically_derived] +impl ::core::fmt::Debug for + EnumGeneric { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + EnumGeneric::One(__self_0) => + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "One", + &__self_0), + EnumGeneric::Two(__self_0) => + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Two", + &__self_0), + } + } +} +#[automatically_derived] +impl ::core::hash::Hash for + EnumGeneric { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + let __self_tag = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_tag, state); + match self { + EnumGeneric::One(__self_0) => + ::core::hash::Hash::hash(__self_0, state), + EnumGeneric::Two(__self_0) => + ::core::hash::Hash::hash(__self_0, state), + } + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for EnumGeneric { } +#[automatically_derived] +impl + ::core::cmp::PartialEq for EnumGeneric { + #[inline] + fn eq(&self, other: &EnumGeneric) -> bool { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + __self_tag == __arg1_tag && + match (self, other) { + (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => + *__self_0 == *__arg1_0, + (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) => + *__self_0 == *__arg1_0, + _ => unsafe { ::core::intrinsics::unreachable() } + } + } +} +#[automatically_derived] +impl ::core::marker::StructuralEq for EnumGeneric { } +#[automatically_derived] +impl ::core::cmp::Eq for + EnumGeneric { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } +} +#[automatically_derived] +impl + ::core::cmp::PartialOrd for EnumGeneric { + #[inline] + fn partial_cmp(&self, other: &EnumGeneric) + -> ::core::option::Option<::core::cmp::Ordering> { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + match (self, other) { + (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + _ => + ::core::cmp::PartialOrd::partial_cmp(&__self_tag, + &__arg1_tag), + } + } +} +#[automatically_derived] +impl ::core::cmp::Ord for + EnumGeneric { + #[inline] + fn cmp(&self, other: &EnumGeneric) -> ::core::cmp::Ordering { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) { + ::core::cmp::Ordering::Equal => + match (self, other) { + (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => + ::core::cmp::Ord::cmp(__self_0, __arg1_0), + (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) => + ::core::cmp::Ord::cmp(__self_0, __arg1_0), + _ => unsafe { ::core::intrinsics::unreachable() } + }, + cmp => cmp, + } + } +} + // A union. Most builtin traits are not derivable for unions. pub union Union { pub b: bool, diff --git a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs new file mode 100644 index 00000000000..0467dea621b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs @@ -0,0 +1,12 @@ +// check-pass + +#![deny(multiple_supertrait_upcastable)] +//~^ WARNING unknown lint: `multiple_supertrait_upcastable` +//~| WARNING unknown lint: `multiple_supertrait_upcastable` +//~| WARNING unknown lint: `multiple_supertrait_upcastable` +#![warn(multiple_supertrait_upcastable)] +//~^ WARNING unknown lint: `multiple_supertrait_upcastable` +//~| WARNING unknown lint: `multiple_supertrait_upcastable` +//~| WARNING unknown lint: `multiple_supertrait_upcastable` + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr new file mode 100644 index 00000000000..1f725f35417 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr @@ -0,0 +1,57 @@ +warning: unknown lint: `multiple_supertrait_upcastable` + --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1 + | +LL | #![deny(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `multiple_supertrait_upcastable` lint is unstable + = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable + = note: `#[warn(unknown_lints)]` on by default + +warning: unknown lint: `multiple_supertrait_upcastable` + --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1 + | +LL | #![warn(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `multiple_supertrait_upcastable` lint is unstable + = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable + +warning: unknown lint: `multiple_supertrait_upcastable` + --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1 + | +LL | #![deny(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `multiple_supertrait_upcastable` lint is unstable + = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable + +warning: unknown lint: `multiple_supertrait_upcastable` + --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1 + | +LL | #![warn(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `multiple_supertrait_upcastable` lint is unstable + = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable + +warning: unknown lint: `multiple_supertrait_upcastable` + --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1 + | +LL | #![deny(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `multiple_supertrait_upcastable` lint is unstable + = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable + +warning: unknown lint: `multiple_supertrait_upcastable` + --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1 + | +LL | #![warn(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `multiple_supertrait_upcastable` lint is unstable + = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable + +warning: 6 warnings emitted + diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index be321c3c5c0..3480a2ec815 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -15,7 +15,7 @@ LL | format!("{:X}", "3"); NonZeroIsize and 21 others = note: required for `&str` to implement `UpperHex` -note: required by a bound in `ArgumentV1::<'a>::new_upper_hex` +note: required by a bound in `core::fmt::ArgumentV1::<'a>::new_upper_hex` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `arg_new` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/fmt/send-sync.stderr b/tests/ui/fmt/send-sync.stderr index 3ed040c3ab3..d43f4f0d957 100644 --- a/tests/ui/fmt/send-sync.stderr +++ b/tests/ui/fmt/send-sync.stderr @@ -6,11 +6,11 @@ LL | send(format_args!("{:?}", c)); | | | required by a bound introduced by this call | - = help: within `[ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque` + = help: within `[core::fmt::ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque` = note: required because it appears within the type `&core::fmt::Opaque` = note: required because it appears within the type `ArgumentV1<'_>` = note: required because it appears within the type `[ArgumentV1<'_>]` - = note: required for `&[ArgumentV1<'_>]` to implement `Send` + = note: required for `&[core::fmt::ArgumentV1<'_>]` to implement `Send` = note: required because it appears within the type `Arguments<'_>` note: required by a bound in `send` --> $DIR/send-sync.rs:1:12 diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs new file mode 100644 index 00000000000..7ba2b6d857c --- /dev/null +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs @@ -0,0 +1,8 @@ +fn main() { + let x = 42; + match x { + 0..=73 => {}, + 74..=> {}, //~ ERROR unexpected `=>` after open range + //~^ ERROR expected one of `=>`, `if`, or `|`, found `>` + } +} diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr new file mode 100644 index 00000000000..9ba6d15113c --- /dev/null +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr @@ -0,0 +1,19 @@ +error: unexpected `=>` after open range + --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:11 + | +LL | 74..=> {}, + | ^^^ + | +help: add a space between the pattern and `=>` + | +LL | 74.. => {}, + | + + +error: expected one of `=>`, `if`, or `|`, found `>` + --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:14 + | +LL | 74..=> {}, + | ^ expected one of `=>`, `if`, or `|` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/mir/mir_codegen_ssa.rs b/tests/ui/mir/mir_codegen_ssa.rs new file mode 100644 index 00000000000..5e2f10cefe9 --- /dev/null +++ b/tests/ui/mir/mir_codegen_ssa.rs @@ -0,0 +1,19 @@ +// build-pass +// compile-flags: --crate-type=lib +#![feature(custom_mir, core_intrinsics)] +use std::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub fn f(a: u32) -> u32 { + mir!( + let x: u32; + { + // Previously code generation failed with ICE "use of .. before def ..." because the + // definition of x was incorrectly identified as dominating the use of x located in the + // same statement: + x = x + a; + RET = x; + Return() + } + ) +} diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed new file mode 100644 index 00000000000..0b9a3bae961 --- /dev/null +++ b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed @@ -0,0 +1,11 @@ +// run-rustfix +use std::pin::Pin; + +fn foo(_: &mut ()) {} + +fn main() { + let mut uwu = (); + let mut r = Pin::new(&mut uwu); + foo(r.as_mut().get_mut()); + foo(r.get_mut()); //~ ERROR use of moved value +} diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs new file mode 100644 index 00000000000..0e952b06ee1 --- /dev/null +++ b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs @@ -0,0 +1,11 @@ +// run-rustfix +use std::pin::Pin; + +fn foo(_: &mut ()) {} + +fn main() { + let mut uwu = (); + let mut r = Pin::new(&mut uwu); + foo(r.get_mut()); + foo(r.get_mut()); //~ ERROR use of moved value +} diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr new file mode 100644 index 00000000000..7e513b73c21 --- /dev/null +++ b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr @@ -0,0 +1,20 @@ +error[E0382]: use of moved value: `r` + --> $DIR/pin-mut-reborrow-infer-var-issue-107419.rs:10:9 + | +LL | let mut r = Pin::new(&mut uwu); + | ----- move occurs because `r` has type `Pin<&mut ()>`, which does not implement the `Copy` trait +LL | foo(r.get_mut()); + | --------- `r` moved due to this method call +LL | foo(r.get_mut()); + | ^ value used here after move + | +note: `Pin::<&'a mut T>::get_mut` takes ownership of the receiver `self`, which moves `r` + --> $SRC_DIR/core/src/pin.rs:LL:COL +help: consider reborrowing the `Pin` instead of moving it + | +LL | foo(r.as_mut().get_mut()); + | +++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/parser/bastion-of-the-turbofish.rs b/tests/ui/parser/bastion-of-the-turbofish.rs index e12857008a5..7ceea676d3a 100644 --- a/tests/ui/parser/bastion-of-the-turbofish.rs +++ b/tests/ui/parser/bastion-of-the-turbofish.rs @@ -34,7 +34,7 @@ // See https://github.com/rust-lang/rust/pull/53562 // and https://github.com/rust-lang/rfcs/pull/2527 -// and https://twitter.com/garblefart/status/1393236602856611843 +// and https://web.archive.org/web/20211010063452/https://twitter.com/garblefart/status/1393236602856611843 // for context. fn main() { diff --git a/tests/ui/parser/trait-object-delimiters.rs b/tests/ui/parser/trait-object-delimiters.rs index cc04ac05204..c41cda18743 100644 --- a/tests/ui/parser/trait-object-delimiters.rs +++ b/tests/ui/parser/trait-object-delimiters.rs @@ -5,6 +5,8 @@ fn foo1(_: &dyn Drop + AsRef) {} //~ ERROR ambiguous `+` in a type fn foo2(_: &dyn (Drop + AsRef)) {} //~ ERROR incorrect braces around trait bounds +fn foo2_no_space(_: &dyn(Drop + AsRef)) {} //~ ERROR incorrect braces around trait bounds + fn foo3(_: &dyn {Drop + AsRef}) {} //~ ERROR expected parameter name, found `{` //~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` //~| ERROR at least one trait is required for an object type diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr index 99c4515459d..ccce3a8053e 100644 --- a/tests/ui/parser/trait-object-delimiters.stderr +++ b/tests/ui/parser/trait-object-delimiters.stderr @@ -13,17 +13,29 @@ LL | fn foo2(_: &dyn (Drop + AsRef)) {} help: remove the parentheses | LL - fn foo2(_: &dyn (Drop + AsRef)) {} -LL + fn foo2(_: &dyn Drop + AsRef) {} +LL + fn foo2(_: &dyn Drop + AsRef) {} + | + +error: incorrect braces around trait bounds + --> $DIR/trait-object-delimiters.rs:8:25 + | +LL | fn foo2_no_space(_: &dyn(Drop + AsRef)) {} + | ^ ^ + | +help: remove the parentheses + | +LL - fn foo2_no_space(_: &dyn(Drop + AsRef)) {} +LL + fn foo2_no_space(_: &dyn Drop + AsRef) {} | error: expected parameter name, found `{` - --> $DIR/trait-object-delimiters.rs:8:17 + --> $DIR/trait-object-delimiters.rs:10:17 | LL | fn foo3(_: &dyn {Drop + AsRef}) {} | ^ expected parameter name error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` - --> $DIR/trait-object-delimiters.rs:8:17 + --> $DIR/trait-object-delimiters.rs:10:17 | LL | fn foo3(_: &dyn {Drop + AsRef}) {} | -^ expected one of 10 possible tokens @@ -31,13 +43,13 @@ LL | fn foo3(_: &dyn {Drop + AsRef}) {} | help: missing `,` error: expected identifier, found `<` - --> $DIR/trait-object-delimiters.rs:12:17 + --> $DIR/trait-object-delimiters.rs:14:17 | LL | fn foo4(_: &dyn >) {} | ^ expected identifier error: invalid `dyn` keyword - --> $DIR/trait-object-delimiters.rs:14:25 + --> $DIR/trait-object-delimiters.rs:16:25 | LL | fn foo5(_: &(dyn Drop + dyn AsRef)) {} | ^^^ help: remove this keyword @@ -56,13 +68,13 @@ LL | fn foo1(_: &dyn Drop + AsRef) {} = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0224]: at least one trait is required for an object type - --> $DIR/trait-object-delimiters.rs:8:13 + --> $DIR/trait-object-delimiters.rs:10:13 | LL | fn foo3(_: &dyn {Drop + AsRef}) {} | ^^^ error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/trait-object-delimiters.rs:14:29 + --> $DIR/trait-object-delimiters.rs:16:29 | LL | fn foo5(_: &(dyn Drop + dyn AsRef)) {} | ---- ^^^^^^^^^^ additional non-auto trait @@ -72,7 +84,7 @@ LL | fn foo5(_: &(dyn Drop + dyn AsRef)) {} = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Drop + AsRef {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0224, E0225. For more information about an error, try `rustc --explain E0224`. diff --git a/tests/ui/suggestions/recover-invalid-float-invalid.rs b/tests/ui/suggestions/recover-invalid-float-invalid.rs new file mode 100644 index 00000000000..79430d8c051 --- /dev/null +++ b/tests/ui/suggestions/recover-invalid-float-invalid.rs @@ -0,0 +1,24 @@ +// Check that suggestions to add a zero to integers with a preceding dot only appear when the change +// will result in a valid floating point literal. + +fn main() {} + +fn a() { + _ = .3u32; + //~^ ERROR expected expression, found `.` +} + +fn b() { + _ = .0b0; + //~^ ERROR expected expression, found `.` +} + +fn c() { + _ = .0o07; + //~^ ERROR expected expression, found `.` +} + +fn d() { + _ = .0x0ABC; + //~^ ERROR expected expression, found `.` +} diff --git a/tests/ui/suggestions/recover-invalid-float-invalid.stderr b/tests/ui/suggestions/recover-invalid-float-invalid.stderr new file mode 100644 index 00000000000..5764afc1a21 --- /dev/null +++ b/tests/ui/suggestions/recover-invalid-float-invalid.stderr @@ -0,0 +1,26 @@ +error: expected expression, found `.` + --> $DIR/recover-invalid-float-invalid.rs:7:9 + | +LL | _ = .3u32; + | ^ expected expression + +error: expected expression, found `.` + --> $DIR/recover-invalid-float-invalid.rs:12:9 + | +LL | _ = .0b0; + | ^ expected expression + +error: expected expression, found `.` + --> $DIR/recover-invalid-float-invalid.rs:17:9 + | +LL | _ = .0o07; + | ^ expected expression + +error: expected expression, found `.` + --> $DIR/recover-invalid-float-invalid.rs:22:9 + | +LL | _ = .0x0ABC; + | ^ expected expression + +error: aborting due to 4 previous errors + diff --git a/tests/ui/thir-print/thir-flat.rs b/tests/ui/thir-print/thir-flat.rs new file mode 100644 index 00000000000..8fa95ce62b5 --- /dev/null +++ b/tests/ui/thir-print/thir-flat.rs @@ -0,0 +1,4 @@ +// compile-flags: -Z unpretty=thir-flat +// check-pass + +pub fn main() {} diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout new file mode 100644 index 00000000000..c399fa66b6a --- /dev/null +++ b/tests/ui/thir-print/thir-flat.stdout @@ -0,0 +1,56 @@ +DefId(0:3 ~ thir_flat[45a6]::main): +Thir { + arms: [], + blocks: [ + Block { + targeted_by_break: false, + region_scope: Node(1), + opt_destruction_scope: None, + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), + stmts: [], + expr: None, + safety_mode: Safe, + }, + ], + exprs: [ + Expr { + ty: (), + temp_lifetime: Some( + Node(2), + ), + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), + kind: Block { + block: b0, + }, + }, + Expr { + ty: (), + temp_lifetime: Some( + Node(2), + ), + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), + kind: Scope { + region_scope: Node(2), + lint_level: Explicit( + HirId(DefId(0:3 ~ thir_flat[45a6]::main).2), + ), + value: e0, + }, + }, + Expr { + ty: (), + temp_lifetime: Some( + Node(2), + ), + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), + kind: Scope { + region_scope: Destruction(2), + lint_level: Inherited, + value: e1, + }, + }, + ], + stmts: [], + params: [], +} + diff --git a/tests/ui/thir-print/thir-tree-match.rs b/tests/ui/thir-print/thir-tree-match.rs new file mode 100644 index 00000000000..a5511ec9543 --- /dev/null +++ b/tests/ui/thir-print/thir-tree-match.rs @@ -0,0 +1,23 @@ +// check-pass +// compile-flags: -Zunpretty=thir-tree + +enum Bar { + First, + Second, + Third, +} + +enum Foo { + FooOne(Bar), + FooTwo, +} + +fn has_match(foo: Foo) -> bool { + match foo { + Foo::FooOne(Bar::First) => true, + Foo::FooOne(_) => false, + Foo::FooTwo => true, + } +} + +fn main() {} diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout new file mode 100644 index 00000000000..d6174ec262a --- /dev/null +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -0,0 +1,342 @@ +DefId(0:16 ~ thir_tree_match[3c9a]::has_match): +params: [ + Param { + ty: Foo + ty_span: Some($DIR/thir-tree-match.rs:15:19: 15:22 (#0)) + self_kind: None + hir_id: Some(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).1)) + param: Some( + Pat: { + ty: Foo + span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0) + kind: PatKind { + Binding { + mutability: Not + name: "foo" + mode: ByValue + var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2)) + ty: Foo + is_primary: true + subpattern: None + } + } + } + ) + } +] +body: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) + kind: + Scope { + region_scope: Destruction(26) + lint_level: Inherited + value: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) + kind: + Scope { + region_scope: Node(26) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).26)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) + kind: + Block { + targeted_by_break: false + opt_destruction_scope: None + span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) + region_scope: Node(25) + safety_mode: Safe + stmts: [] + expr: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0) + kind: + Scope { + region_scope: Node(3) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).3)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0) + kind: + Match { + scrutinee: + Expr { + ty: Foo + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) + kind: + Scope { + region_scope: Node(4) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).4)) + value: + Expr { + ty: Foo + temp_lifetime: Some(Node(26)) + span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) + kind: + VarRef { + id: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2)) + } + } + } + } + arms: [ + Arm { + pattern: + Pat: { + ty: Foo + span: $DIR/thir-tree-match.rs:17:9: 17:32 (#0) + kind: PatKind { + Variant { + adt_def: + AdtDef { + did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo) + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }] + flags: IS_ENUM + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 } + substs: [] + variant_index: 0 + subpatterns: [ + Pat: { + ty: Bar + span: $DIR/thir-tree-match.rs:17:21: 17:31 (#0) + kind: PatKind { + Variant { + adt_def: + AdtDef { + did: DefId(0:3 ~ thir_tree_match[3c9a]::Bar) + variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[3c9a]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[3c9a]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[3c9a]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[3c9a]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[3c9a]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[3c9a]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], flags: NO_VARIANT_FLAGS }] + flags: IS_ENUM + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 3125160937860410723 } + substs: [] + variant_index: 0 + subpatterns: [] + } + } + } + ] + } + } + } + guard: None + body: + Expr { + ty: bool + temp_lifetime: Some(Node(13)) + span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) + kind: + Scope { + region_scope: Destruction(13) + lint_level: Inherited + value: + Expr { + ty: bool + temp_lifetime: Some(Node(13)) + span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) + kind: + Scope { + region_scope: Node(13) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).13)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(13)) + span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) + kind: + Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false) + + } + } + } + } + } + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).12)) + scope: Node(12) + span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0) + } + Arm { + pattern: + Pat: { + ty: Foo + span: $DIR/thir-tree-match.rs:18:9: 18:23 (#0) + kind: PatKind { + Variant { + adt_def: + AdtDef { + did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo) + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }] + flags: IS_ENUM + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 } + substs: [] + variant_index: 0 + subpatterns: [ + Pat: { + ty: Bar + span: $DIR/thir-tree-match.rs:18:21: 18:22 (#0) + kind: PatKind { + Wild + } + } + ] + } + } + } + guard: None + body: + Expr { + ty: bool + temp_lifetime: Some(Node(19)) + span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) + kind: + Scope { + region_scope: Destruction(19) + lint_level: Inherited + value: + Expr { + ty: bool + temp_lifetime: Some(Node(19)) + span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) + kind: + Scope { + region_scope: Node(19) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).19)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(19)) + span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) + kind: + Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false) + + } + } + } + } + } + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).18)) + scope: Node(18) + span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0) + } + Arm { + pattern: + Pat: { + ty: Foo + span: $DIR/thir-tree-match.rs:19:9: 19:20 (#0) + kind: PatKind { + Variant { + adt_def: + AdtDef { + did: DefId(0:10 ~ thir_tree_match[3c9a]::Foo) + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[3c9a]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[3c9a]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[3c9a]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[3c9a])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[3c9a]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[3c9a]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }] + flags: IS_ENUM + repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 11573694388057581 } + substs: [] + variant_index: 1 + subpatterns: [] + } + } + } + guard: None + body: + Expr { + ty: bool + temp_lifetime: Some(Node(24)) + span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) + kind: + Scope { + region_scope: Destruction(24) + lint_level: Inherited + value: + Expr { + ty: bool + temp_lifetime: Some(Node(24)) + span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) + kind: + Scope { + region_scope: Node(24) + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).24)) + value: + Expr { + ty: bool + temp_lifetime: Some(Node(24)) + span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) + kind: + Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false) + + } + } + } + } + } + lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).23)) + scope: Node(23) + span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0) + } + ] + } + } + } + } + } + } + } + } + } + } + + +DefId(0:17 ~ thir_tree_match[3c9a]::main): +params: [ +] +body: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) + kind: + Scope { + region_scope: Destruction(2) + lint_level: Inherited + value: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) + kind: + Scope { + region_scope: Node(2) + lint_level: Explicit(HirId(DefId(0:17 ~ thir_tree_match[3c9a]::main).2)) + value: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) + kind: + Block { + targeted_by_break: false + opt_destruction_scope: None + span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) + region_scope: Node(1) + safety_mode: Safe + stmts: [] + expr: [] + } + } + } + } + } + } + + diff --git a/tests/ui/thir-print/thir-tree.rs b/tests/ui/thir-print/thir-tree.rs new file mode 100644 index 00000000000..32df7905adb --- /dev/null +++ b/tests/ui/thir-print/thir-tree.rs @@ -0,0 +1,4 @@ +// compile-flags: -Z unpretty=thir-tree +// check-pass + +pub fn main() {} diff --git a/tests/ui/thir-print/thir-tree.stdout b/tests/ui/thir-print/thir-tree.stdout new file mode 100644 index 00000000000..0a35d9fb78c --- /dev/null +++ b/tests/ui/thir-print/thir-tree.stdout @@ -0,0 +1,43 @@ +DefId(0:3 ~ thir_tree[8f1d]::main): +params: [ +] +body: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree.rs:4:15: 4:17 (#0) + kind: + Scope { + region_scope: Destruction(2) + lint_level: Inherited + value: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree.rs:4:15: 4:17 (#0) + kind: + Scope { + region_scope: Node(2) + lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2)) + value: + Expr { + ty: () + temp_lifetime: Some(Node(2)) + span: $DIR/thir-tree.rs:4:15: 4:17 (#0) + kind: + Block { + targeted_by_break: false + opt_destruction_scope: None + span: $DIR/thir-tree.rs:4:15: 4:17 (#0) + region_scope: Node(1) + safety_mode: Safe + stmts: [] + expr: [] + } + } + } + } + } + } + + diff --git a/tests/ui/thir-tree.rs b/tests/ui/thir-tree.rs deleted file mode 100644 index 32df7905adb..00000000000 --- a/tests/ui/thir-tree.rs +++ /dev/null @@ -1,4 +0,0 @@ -// compile-flags: -Z unpretty=thir-tree -// check-pass - -pub fn main() {} diff --git a/tests/ui/thir-tree.stdout b/tests/ui/thir-tree.stdout deleted file mode 100644 index 4b6915f7715..00000000000 --- a/tests/ui/thir-tree.stdout +++ /dev/null @@ -1,56 +0,0 @@ -DefId(0:3 ~ thir_tree[8f1d]::main): -Thir { - arms: [], - blocks: [ - Block { - targeted_by_break: false, - region_scope: Node(1), - opt_destruction_scope: None, - span: $DIR/thir-tree.rs:4:15: 4:17 (#0), - stmts: [], - expr: None, - safety_mode: Safe, - }, - ], - exprs: [ - Expr { - ty: (), - temp_lifetime: Some( - Node(2), - ), - span: $DIR/thir-tree.rs:4:15: 4:17 (#0), - kind: Block { - block: b0, - }, - }, - Expr { - ty: (), - temp_lifetime: Some( - Node(2), - ), - span: $DIR/thir-tree.rs:4:15: 4:17 (#0), - kind: Scope { - region_scope: Node(2), - lint_level: Explicit( - HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2), - ), - value: e0, - }, - }, - Expr { - ty: (), - temp_lifetime: Some( - Node(2), - ), - span: $DIR/thir-tree.rs:4:15: 4:17 (#0), - kind: Scope { - region_scope: Destruction(2), - lint_level: Inherited, - value: e1, - }, - }, - ], - stmts: [], - params: [], -} - diff --git a/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs new file mode 100644 index 00000000000..3c6ab86e4c6 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs @@ -0,0 +1,10 @@ +#![feature(multiple_supertrait_upcastable)] +#![deny(multiple_supertrait_upcastable)] + +trait A {} +trait B {} + +trait C: A + B {} +//~^ ERROR `C` is object-safe and has multiple supertraits + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr new file mode 100644 index 00000000000..ad80a009ece --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr @@ -0,0 +1,14 @@ +error: `C` is object-safe and has multiple supertraits + --> $DIR/multiple_supertrait_upcastable.rs:7:1 + | +LL | trait C: A + B {} + | ^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/multiple_supertrait_upcastable.rs:2:9 + | +LL | #![deny(multiple_supertrait_upcastable)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error +