diff --git a/.editorconfig b/.editorconfig index ec6e107d547f..03aab32bfc6e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,7 @@ trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 4 +max_line_length = 100 [*.md] # double whitespace at end of line diff --git a/.gitmodules b/.gitmodules index 0bbccb571302..4596ae17d023 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,7 +25,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/16.0-2023-03-06 + branch = rustc/16.0-2023-04-05 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/Cargo.lock b/Cargo.lock index c7bd689b2d86..6dd6fbe71b83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -632,7 +632,7 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.102", - "synstructure", + "synstructure 0.12.6", ] [[package]] @@ -1418,9 +1418,9 @@ dependencies = [ [[package]] name = "elsa" -version = "1.8.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f74077c3c3aedb99a2683919698285596662518ea13e5eedcf8bdd43b0d0453b" +checksum = "848fe615fbb0a74d9ae68dcaa510106d32e37d9416207bbea4bd008bd89c47ed" dependencies = [ "stable_deref_trait", ] @@ -1673,12 +1673,6 @@ version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64db3e262960f0662f43a6366788d5f10f7f244b8f7d7d987f560baf5ded5c50" -[[package]] -name = "fs_extra" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" - [[package]] name = "futf" version = "0.1.5" @@ -2861,12 +2855,11 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "jemalloc-sys" -version = "0.5.0+5.3.0" +version = "0.5.3+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f655c3ecfa6b0d03634595b4b54551d4bd5ac208b9e0124873949a7ab168f70b" +checksum = "f9bd5d616ea7ed58b571b2e209a65759664d7fb021a0819d7a790afc67e47ca1" dependencies = [ "cc", - "fs_extra", "libc", ] @@ -3475,18 +3468,30 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.38" +version = "0.10.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" +checksum = "4d2f106ab837a24e03672c59b1239669a0596406ff657c3c0835b6b7f0f35a33" dependencies = [ "bitflags", "cfg-if", "foreign-types", "libc", "once_cell", + "openssl-macros", "openssl-sys", ] +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.8", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -3495,20 +3500,19 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "111.22.0+1.1.1q" +version = "111.25.0+1.1.1t" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f31f0d509d1c1ae9cada2f9539ff8f37933831fd5098879e482aa687d659853" +checksum = "3173cd3626c43e3854b1b727422a276e568d9ec5fe8cec197822cf52cfb743d6" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.72" +version = "0.9.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" +checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa" dependencies = [ - "autocfg", "cc", "libc", "openssl-src", @@ -4178,7 +4182,7 @@ name = "rustbook" version = "0.1.0" dependencies = [ "clap 4.2.1", - "env_logger 0.7.1", + "env_logger 0.10.0", "mdbook", ] @@ -4994,8 +4998,8 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 1.0.102", - "synstructure", + "syn 2.0.8", + "synstructure 0.13.0", "unic-langid", ] @@ -6131,6 +6135,18 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "synstructure" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.8", + "unicode-xid", +] + [[package]] name = "tar" version = "0.4.38" @@ -6299,7 +6315,7 @@ name = "tidy" version = "0.1.0" dependencies = [ "cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.14.0", + "cargo_metadata 0.15.3", "ignore", "lazy_static", "miropt-test-tools", @@ -7154,7 +7170,7 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.102", - "synstructure", + "synstructure 0.12.6", ] [[package]] @@ -7175,7 +7191,7 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.102", - "synstructure", + "synstructure 0.12.6", ] [[package]] @@ -7204,5 +7220,5 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.102", - "synstructure", + "synstructure 0.12.6", ] diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index aea59ee6aea3..c863acde7b03 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -8,19 +8,6 @@ use rand_xoshiro::Xoshiro128StarStar; use tracing::debug; -// Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`. -// This is used to go between `memory_index` (source field order to memory order) -// and `inverse_memory_index` (memory order to source field order). -// See also `FieldsShape::Arbitrary::memory_index` for more details. -// FIXME(eddyb) build a better abstraction for permutations, if possible. -fn invert_mapping(map: &[u32]) -> Vec { - let mut inverse = vec![0; map.len()]; - for i in 0..map.len() { - inverse[map[i] as usize] = i as u32; - } - inverse -} - pub trait LayoutCalculator { type TargetDataLayoutRef: Borrow; @@ -45,8 +32,8 @@ pub trait LayoutCalculator { LayoutS { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Arbitrary { - offsets: vec![Size::ZERO, b_offset], - memory_index: vec![0, 1], + offsets: [Size::ZERO, b_offset].into(), + memory_index: [0, 1].into(), }, abi: Abi::ScalarPair(a, b), largest_niche, @@ -58,18 +45,18 @@ pub trait LayoutCalculator { fn univariant( &self, dl: &TargetDataLayout, - fields: &[Layout<'_>], + fields: &IndexSlice>, repr: &ReprOptions, kind: StructKind, ) -> Option { let pack = repr.pack; let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; - let mut inverse_memory_index: Vec = (0..fields.len() as u32).collect(); + let mut inverse_memory_index: IndexVec = fields.indices().collect(); let optimize = !repr.inhibit_struct_field_reordering_opt(); if optimize { let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; - let optimizing = &mut inverse_memory_index[..end]; + let optimizing = &mut inverse_memory_index.raw[..end]; let effective_field_align = |layout: Layout<'_>| { if let Some(pack) = pack { // return the packed alignment in bytes @@ -105,7 +92,7 @@ pub trait LayoutCalculator { // Place ZSTs first to avoid "interesting offsets", // especially with only one or two non-ZST fields. // Then place largest alignments first, largest niches within an alignment group last - let f = fields[x as usize]; + let f = fields[x]; let niche_size = f.largest_niche().map_or(0, |n| n.available(dl)); (!f.0.is_zst(), cmp::Reverse(effective_field_align(f)), niche_size) }); @@ -117,7 +104,7 @@ pub trait LayoutCalculator { // And put the largest niche in an alignment group at the end // so it can be used as discriminant in jagged enums optimizing.sort_by_key(|&x| { - let f = fields[x as usize]; + let f = fields[x]; let niche_size = f.largest_niche().map_or(0, |n| n.available(dl)); (effective_field_align(f), niche_size) }); @@ -135,7 +122,7 @@ pub trait LayoutCalculator { // At the bottom of this function, we invert `inverse_memory_index` to // produce `memory_index` (see `invert_mapping`). let mut sized = true; - let mut offsets = vec![Size::ZERO; fields.len()]; + let mut offsets = IndexVec::from_elem(Size::ZERO, &fields); let mut offset = Size::ZERO; let mut largest_niche = None; let mut largest_niche_available = 0; @@ -146,7 +133,7 @@ pub trait LayoutCalculator { offset = prefix_size.align_to(prefix_align); } for &i in &inverse_memory_index { - let field = &fields[i as usize]; + let field = &fields[i]; if !sized { self.delay_bug(&format!( "univariant: field #{} comes after unsized field", @@ -168,7 +155,7 @@ pub trait LayoutCalculator { align = align.max(field_align); debug!("univariant offset: {:?} field: {:#?}", offset, field); - offsets[i as usize] = offset; + offsets[i] = offset; if let Some(mut niche) = field.largest_niche() { let available = niche.available(dl); @@ -192,14 +179,18 @@ pub trait LayoutCalculator { // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0. // Field 5 would be the first element, so memory_index is i: // Note: if we didn't optimize, it's already right. - let memory_index = - if optimize { invert_mapping(&inverse_memory_index) } else { inverse_memory_index }; + let memory_index = if optimize { + inverse_memory_index.invert_bijective_mapping() + } else { + debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices())); + inverse_memory_index.into_iter().map(FieldIdx::as_u32).collect() + }; let size = min_size.align_to(align.abi); let mut abi = Abi::Aggregate { sized }; // Unpack newtype ABIs and find scalar pairs. if sized && size.bytes() > 0 { // All other fields must be ZSTs. - let mut non_zst_fields = fields.iter().enumerate().filter(|&(_, f)| !f.0.is_zst()); + let mut non_zst_fields = fields.iter_enumerated().filter(|&(_, f)| !f.0.is_zst()); match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { // We have exactly one non-ZST field. @@ -238,13 +229,13 @@ pub trait LayoutCalculator { let pair = self.scalar_pair(a, b); let pair_offsets = match pair.fields { FieldsShape::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index, &[0, 1]); + assert_eq!(memory_index.raw, [0, 1]); offsets } _ => panic!(), }; - if offsets[i] == pair_offsets[0] - && offsets[j] == pair_offsets[1] + if offsets[i] == pair_offsets[FieldIdx::from_usize(0)] + && offsets[j] == pair_offsets[FieldIdx::from_usize(1)] && align == pair.align && size == pair.size { @@ -289,7 +280,7 @@ pub trait LayoutCalculator { fn layout_of_struct_or_enum( &self, repr: &ReprOptions, - variants: &IndexSlice>>, + variants: &IndexSlice>>, is_enum: bool, is_unsafe_cell: bool, scalar_valid_range: (Bound, Bound), @@ -312,7 +303,7 @@ pub trait LayoutCalculator { // but *not* an encoding of the discriminant (e.g., a tag value). // See issue #49298 for more details on the need to leave space // for non-ZST uninhabited data (mostly partial initialization). - let absent = |fields: &[Layout<'_>]| { + let absent = |fields: &IndexSlice>| { let uninhabited = fields.iter().any(|f| f.abi().is_uninhabited()); let is_zst = fields.iter().all(|f| f.0.is_zst()); uninhabited && is_zst @@ -510,7 +501,7 @@ pub trait LayoutCalculator { // It'll fit, but we need to make some adjustments. match layout.fields { FieldsShape::Arbitrary { ref mut offsets, .. } => { - for (j, offset) in offsets.iter_mut().enumerate() { + for (j, offset) in offsets.iter_enumerated_mut() { if !variants[i][j].0.is_zst() { *offset += this_offset; } @@ -577,8 +568,8 @@ pub trait LayoutCalculator { variants: IndexVec::new(), }, fields: FieldsShape::Arbitrary { - offsets: vec![niche_offset], - memory_index: vec![0], + offsets: [niche_offset].into(), + memory_index: [0].into(), }, abi, largest_niche, @@ -651,7 +642,8 @@ pub trait LayoutCalculator { st.variants = Variants::Single { index: i }; // Find the first field we can't move later // to make room for a larger discriminant. - for field in st.fields.index_by_increasing_offset().map(|j| &field_layouts[j]) { + for field_idx in st.fields.index_by_increasing_offset() { + let field = &field_layouts[FieldIdx::from_usize(field_idx)]; if !field.0.is_zst() || field.align().abi.bytes() != 1 { start_align = start_align.min(field.align().abi); break; @@ -802,13 +794,13 @@ pub trait LayoutCalculator { let pair = self.scalar_pair(tag, prim_scalar); let pair_offsets = match pair.fields { FieldsShape::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index, &[0, 1]); + assert_eq!(memory_index.raw, [0, 1]); offsets } _ => panic!(), }; - if pair_offsets[0] == Size::ZERO - && pair_offsets[1] == *offset + if pair_offsets[FieldIdx::from_u32(0)] == Size::ZERO + && pair_offsets[FieldIdx::from_u32(1)] == *offset && align == pair.align && size == pair.size { @@ -844,7 +836,10 @@ pub trait LayoutCalculator { tag_field: 0, variants: IndexVec::new(), }, - fields: FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0] }, + fields: FieldsShape::Arbitrary { + offsets: [Size::ZERO].into(), + memory_index: [0].into(), + }, largest_niche, abi, align, @@ -883,7 +878,7 @@ pub trait LayoutCalculator { fn layout_of_union( &self, repr: &ReprOptions, - variants: &IndexSlice>>, + variants: &IndexSlice>>, ) -> Option { let dl = self.current_data_layout(); let dl = dl.borrow(); diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 7b5732b488b4..b0c0ee942ea8 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1108,7 +1108,7 @@ pub enum FieldsShape { /// ordered to match the source definition order. /// This vector does not go in increasing order. // FIXME(eddyb) use small vector optimization for the common case. - offsets: Vec, + offsets: IndexVec, /// Maps source order field indices to memory order indices, /// depending on how the fields were reordered (if at all). @@ -1122,7 +1122,7 @@ pub enum FieldsShape { /// // FIXME(eddyb) build a better abstraction for permutations, if possible. // FIXME(camlorn) also consider small vector optimization here. - memory_index: Vec, + memory_index: IndexVec, }, } @@ -1157,7 +1157,7 @@ impl FieldsShape { assert!(i < count); stride * i } - FieldsShape::Arbitrary { ref offsets, .. } => offsets[i], + FieldsShape::Arbitrary { ref offsets, .. } => offsets[FieldIdx::from_usize(i)], } } @@ -1168,28 +1168,27 @@ impl FieldsShape { unreachable!("FieldsShape::memory_index: `Primitive`s have no fields") } FieldsShape::Union(_) | FieldsShape::Array { .. } => i, - FieldsShape::Arbitrary { ref memory_index, .. } => memory_index[i].try_into().unwrap(), + FieldsShape::Arbitrary { ref memory_index, .. } => { + memory_index[FieldIdx::from_usize(i)].try_into().unwrap() + } } } /// Gets source indices of the fields by increasing offsets. #[inline] - pub fn index_by_increasing_offset<'a>(&'a self) -> impl Iterator + 'a { + pub fn index_by_increasing_offset(&self) -> impl Iterator + '_ { let mut inverse_small = [0u8; 64]; - let mut inverse_big = vec![]; + let mut inverse_big = IndexVec::new(); let use_small = self.count() <= inverse_small.len(); // We have to write this logic twice in order to keep the array small. if let FieldsShape::Arbitrary { ref memory_index, .. } = *self { if use_small { - for i in 0..self.count() { - inverse_small[memory_index[i] as usize] = i as u8; + for (field_idx, &mem_idx) in memory_index.iter_enumerated() { + inverse_small[mem_idx as usize] = field_idx.as_u32() as u8; } } else { - inverse_big = vec![0; self.count()]; - for i in 0..self.count() { - inverse_big[memory_index[i] as usize] = i as u32; - } + inverse_big = memory_index.invert_bijective_mapping(); } } @@ -1199,7 +1198,7 @@ impl FieldsShape { if use_small { inverse_small[i] as usize } else { - inverse_big[i] as usize + inverse_big[i as u32].as_usize() } } }) @@ -1523,6 +1522,16 @@ impl<'a> Layout<'a> { pub fn size(self) -> Size { self.0.0.size } + + /// Whether the layout is from a type that implements [`std::marker::PointerLike`]. + /// + /// Currently, that means that the type is pointer-sized, pointer-aligned, + /// and has a scalar ABI. + pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool { + self.size() == data_layout.pointer_size + && self.align().abi == data_layout.pointer_align.abi + && matches!(self.abi(), Abi::Scalar(..)) + } } #[derive(Copy, Clone, PartialEq, Eq, Debug)] diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 4fae5ef845f7..345e058e1134 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -22,6 +22,7 @@ #![feature(strict_provenance)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine. use smallvec::SmallVec; @@ -568,7 +569,9 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { } pub trait ArenaAllocatable<'tcx, C = rustc_arena::IsNotCopy>: Sized { + #[allow(clippy::mut_from_ref)] fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self; + #[allow(clippy::mut_from_ref)] fn allocate_from_iter<'a>( arena: &'a Arena<'tcx>, iter: impl ::std::iter::IntoIterator, @@ -578,10 +581,12 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { // Any type that impls `Copy` can be arena-allocated in the `DroplessArena`. impl<'tcx, T: Copy> ArenaAllocatable<'tcx, rustc_arena::IsCopy> for T { #[inline] + #[allow(clippy::mut_from_ref)] fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { arena.dropless.alloc(self) } #[inline] + #[allow(clippy::mut_from_ref)] fn allocate_from_iter<'a>( arena: &'a Arena<'tcx>, iter: impl ::std::iter::IntoIterator, @@ -601,6 +606,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { } #[inline] + #[allow(clippy::mut_from_ref)] fn allocate_from_iter<'a>( arena: &'a Arena<'tcx>, iter: impl ::std::iter::IntoIterator, @@ -616,12 +622,14 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { impl<'tcx> Arena<'tcx> { #[inline] + #[allow(clippy::mut_from_ref)] pub fn alloc, C>(&self, value: T) -> &mut T { value.allocate_on(self) } // Any type that impls `Copy` can have slices be arena-allocated in the `DroplessArena`. #[inline] + #[allow(clippy::mut_from_ref)] pub fn alloc_slice(&self, value: &[T]) -> &mut [T] { if value.is_empty() { return &mut []; @@ -629,6 +637,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { self.dropless.alloc_slice(value) } + #[allow(clippy::mut_from_ref)] pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, C>, C>( &'a self, iter: impl ::std::iter::IntoIterator, diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 9b6bfaadef05..fb9d71b52a8a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2890,6 +2890,20 @@ pub struct Fn { pub body: Option>, } +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct StaticItem { + pub ty: P, + pub mutability: Mutability, + pub expr: Option>, +} + +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct ConstItem { + pub defaultness: Defaultness, + pub ty: P, + pub expr: Option>, +} + #[derive(Clone, Encodable, Decodable, Debug)] pub enum ItemKind { /// An `extern crate` item, with the optional *original* crate name if the crate was renamed. @@ -2903,11 +2917,11 @@ pub enum ItemKind { /// A static item (`static`). /// /// E.g., `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";`. - Static(P, Mutability, Option>), + Static(Box), /// A constant item (`const`). /// /// E.g., `const FOO: i32 = 42;`. - Const(Defaultness, P, Option>), + Const(Box), /// A function declaration (`fn`). /// /// E.g., `fn foo(bar: usize) -> usize { .. }`. @@ -3023,7 +3037,7 @@ pub type AssocItem = Item; pub enum AssocItemKind { /// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`. /// If `def` is parsed, then the constant is provided, and otherwise required. - Const(Defaultness, P, Option>), + Const(Box), /// An associated function. Fn(Box), /// An associated type. @@ -3035,7 +3049,7 @@ pub enum AssocItemKind { impl AssocItemKind { pub fn defaultness(&self) -> Defaultness { match *self { - Self::Const(defaultness, ..) + Self::Const(box ConstItem { defaultness, .. }) | Self::Fn(box Fn { defaultness, .. }) | Self::Type(box TyAlias { defaultness, .. }) => defaultness, Self::MacCall(..) => Defaultness::Final, @@ -3046,7 +3060,7 @@ impl AssocItemKind { impl From for ItemKind { fn from(assoc_item_kind: AssocItemKind) -> ItemKind { match assoc_item_kind { - AssocItemKind::Const(a, b, c) => ItemKind::Const(a, b, c), + AssocItemKind::Const(item) => ItemKind::Const(item), AssocItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind), AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind), AssocItemKind::MacCall(a) => ItemKind::MacCall(a), @@ -3059,7 +3073,7 @@ impl TryFrom for AssocItemKind { fn try_from(item_kind: ItemKind) -> Result { Ok(match item_kind { - ItemKind::Const(a, b, c) => AssocItemKind::Const(a, b, c), + ItemKind::Const(item) => AssocItemKind::Const(item), ItemKind::Fn(fn_kind) => AssocItemKind::Fn(fn_kind), ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind), ItemKind::MacCall(a) => AssocItemKind::MacCall(a), @@ -3084,7 +3098,9 @@ pub enum ForeignItemKind { impl From for ItemKind { fn from(foreign_item_kind: ForeignItemKind) -> ItemKind { match foreign_item_kind { - ForeignItemKind::Static(a, b, c) => ItemKind::Static(a, b, c), + ForeignItemKind::Static(a, b, c) => { + ItemKind::Static(StaticItem { ty: a, mutability: b, expr: c }.into()) + } ForeignItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind), ForeignItemKind::TyAlias(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind), ForeignItemKind::MacCall(a) => ItemKind::MacCall(a), @@ -3097,7 +3113,9 @@ impl TryFrom for ForeignItemKind { fn try_from(item_kind: ItemKind) -> Result { Ok(match item_kind { - ItemKind::Static(a, b, c) => ForeignItemKind::Static(a, b, c), + ItemKind::Static(box StaticItem { ty: a, mutability: b, expr: c }) => { + ForeignItemKind::Static(a, b, c) + } ItemKind::Fn(fn_kind) => ForeignItemKind::Fn(fn_kind), ItemKind::TyAlias(ty_alias_kind) => ForeignItemKind::TyAlias(ty_alias_kind), ItemKind::MacCall(a) => ForeignItemKind::MacCall(a), @@ -3114,8 +3132,8 @@ mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; // tidy-alphabetical-start - static_assert_size!(AssocItem, 104); - static_assert_size!(AssocItemKind, 32); + static_assert_size!(AssocItem, 88); + static_assert_size!(AssocItemKind, 16); static_assert_size!(Attribute, 32); static_assert_size!(Block, 32); static_assert_size!(Expr, 72); diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 514978f5569a..2424073ae53a 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -7,10 +7,10 @@ //! a `MutVisitor` renaming item names in a module will miss all of those //! that are created by the expansion of a macro. -use crate::ast::*; use crate::ptr::P; use crate::token::{self, Token}; use crate::tokenstream::*; +use crate::{ast::*, StaticItem}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::sync::Lrc; @@ -1030,14 +1030,12 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { match kind { ItemKind::ExternCrate(_orig_name) => {} ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(ty, _, expr) => { + ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { vis.visit_ty(ty); visit_opt(expr, |expr| vis.visit_expr(expr)); } - ItemKind::Const(defaultness, ty, expr) => { - visit_defaultness(defaultness, vis); - vis.visit_ty(ty); - visit_opt(expr, |expr| vis.visit_expr(expr)); + ItemKind::Const(item) => { + visit_const_item(item, vis); } ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { visit_defaultness(defaultness, vis); @@ -1120,10 +1118,8 @@ pub fn noop_flat_map_assoc_item( visitor.visit_vis(vis); visit_attrs(attrs, visitor); match kind { - AssocItemKind::Const(defaultness, ty, expr) => { - visit_defaultness(defaultness, visitor); - visitor.visit_ty(ty); - visit_opt(expr, |expr| visitor.visit_expr(expr)); + AssocItemKind::Const(item) => { + visit_const_item(item, visitor); } AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { visit_defaultness(defaultness, visitor); @@ -1153,6 +1149,15 @@ pub fn noop_flat_map_assoc_item( smallvec![item] } +fn visit_const_item( + ConstItem { defaultness, ty, expr }: &mut ConstItem, + visitor: &mut T, +) { + visit_defaultness(defaultness, visitor); + visitor.visit_ty(ty); + visit_opt(expr, |expr| visitor.visit_expr(expr)); +} + pub fn noop_visit_fn_header(header: &mut FnHeader, vis: &mut T) { let FnHeader { unsafety, asyncness, constness, ext: _ } = header; visit_constness(constness, vis); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e5a0ad1f1e48..3b08467fde2b 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -13,7 +13,7 @@ //! instance, a walker looking for item names in a module will miss all of //! those that are created by the expansion of a macro. -use crate::ast::*; +use crate::{ast::*, StaticItem}; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -305,8 +305,9 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { match &item.kind { ItemKind::ExternCrate(_) => {} ItemKind::Use(use_tree) => visitor.visit_use_tree(use_tree, item.id, false), - ItemKind::Static(typ, _, expr) | ItemKind::Const(_, typ, expr) => { - visitor.visit_ty(typ); + ItemKind::Static(box StaticItem { ty, mutability: _, expr }) + | ItemKind::Const(box ConstItem { ty, expr, .. }) => { + visitor.visit_ty(ty); walk_list!(visitor, visit_expr, expr); } ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { @@ -674,7 +675,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, visitor.visit_ident(ident); walk_list!(visitor, visit_attribute, attrs); match kind { - AssocItemKind::Const(_, ty, expr) => { + AssocItemKind::Const(box ConstItem { ty, expr, .. }) => { visitor.visit_ty(ty); walk_list!(visitor, visit_expr, expr); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 2efffbb6dc5e..f89e254a2f54 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -229,12 +229,12 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs) } - ItemKind::Static(t, m, e) => { + ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => { let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); hir::ItemKind::Static(ty, *m, body_id) } - ItemKind::Const(_, t, e) => { - let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); + ItemKind::Const(box ast::ConstItem { ty, expr, .. }) => { + let (ty, body_id) = self.lower_const_item(ty, span, expr.as_deref()); hir::ItemKind::Const(ty, body_id) } ItemKind::Fn(box Fn { @@ -708,10 +708,10 @@ impl<'hir> LoweringContext<'_, 'hir> { let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { - AssocItemKind::Const(_, ty, default) => { + AssocItemKind::Const(box ConstItem { ty, expr, .. }) => { let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x))); + let body = expr.as_ref().map(|x| self.lower_const_body(i.span, Some(x))); (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some()) } AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => { @@ -809,7 +809,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_attrs(hir_id, &i.attrs); let (generics, kind) = match &i.kind { - AssocItemKind::Const(_, ty, expr) => { + AssocItemKind::Const(box ConstItem { ty, expr, .. }) => { let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); ( diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 44b6c77fc419..1389acabfcbd 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -9,8 +9,8 @@ use itertools::{Either, Itertools}; use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; -use rustc_ast::walk_list; use rustc_ast::*; +use rustc_ast::{walk_list, StaticItem}; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxIndexMap; use rustc_macros::Subdiagnostic; @@ -691,7 +691,7 @@ fn validate_generic_param_order( GenericParamKind::Lifetime => (), GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => { ordered_params += " = "; - ordered_params += &pprust::expr_to_string(&*default.value); + ordered_params += &pprust::expr_to_string(&default.value); } GenericParamKind::Const { ty: _, kw_span: _, default: None } => (), } @@ -983,14 +983,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.err_handler().emit_err(errors::FieldlessUnion { span: item.span }); } } - ItemKind::Const(def, .., None) => { - self.check_defaultness(item.span, *def); + ItemKind::Const(box ConstItem { defaultness, expr: None, .. }) => { + self.check_defaultness(item.span, *defaultness); self.session.emit_err(errors::ConstWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), }); } - ItemKind::Static(.., None) => { + ItemKind::Static(box StaticItem { expr: None, .. }) => { self.session.emit_err(errors::StaticWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), @@ -1259,13 +1259,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if ctxt == AssocCtxt::Impl { match &item.kind { - AssocItemKind::Const(_, _, body) => { - if body.is_none() { - self.session.emit_err(errors::AssocConstWithoutBody { - span: item.span, - replace_span: self.ending_semi_or_hi(item.span), - }); - } + AssocItemKind::Const(box ConstItem { expr: None, .. }) => { + self.session.emit_err(errors::AssocConstWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); } AssocItemKind::Fn(box Fn { body, .. }) => { if body.is_none() { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index de94c1bc4779..007d64f681f7 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -404,11 +404,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } else { // And if it isn't, cancel the early-pass warning. - self.sess + if let Some(err) = self + .sess .parse_sess .span_diagnostic .steal_diagnostic(e.span, StashKey::EarlySyntaxWarning) - .map(|err| err.cancel()); + { + err.cancel() + } } } ast::ExprKind::TryBlock(_) => { @@ -485,17 +488,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if let Some(args) = constraint.gen_args.as_ref() && matches!( args, - ast::GenericArgs::ReturnTypeNotation(..) | ast::GenericArgs::Parenthesized(..) + ast::GenericArgs::ReturnTypeNotation(..) ) { - // RTN is gated elsewhere, and parenthesized args will turn into - // another error. - if matches!(args, ast::GenericArgs::Parenthesized(..)) { - self.sess.delay_span_bug( - constraint.span, - "should have emitted a parenthesized generics error", - ); - } + // RTN is gated below with a `gate_all`. } else { gate_feature_post!( &self, diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 80c451d67535..1f6838a02784 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -686,7 +686,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere fn bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, close_box: bool) { let has_comment = self.maybe_print_comment(span.hi()); if !empty || has_comment { - self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize)); + self.break_offset_if_not_bol(1, -INDENT_UNIT); } self.word("}"); if close_box { @@ -988,7 +988,9 @@ impl<'a> State<'a> { pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) { self.print_ident(constraint.ident); - constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false)); + if let Some(args) = constraint.gen_args.as_ref() { + self.print_generic_args(args, false) + } self.space(); match &constraint.kind { ast::AssocConstraintKind::Equality { term } => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index bf2c73a66a2c..c465f8c948a8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -2,6 +2,7 @@ use crate::pp::Breaks::Inconsistent; use crate::pprust::state::delimited::IterDelimited; use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; +use ast::StaticItem; use rustc_ast as ast; use rustc_ast::GenericBound; use rustc_ast::ModKind; @@ -156,7 +157,7 @@ impl<'a> State<'a> { self.print_use_tree(tree); self.word(";"); } - ast::ItemKind::Static(ty, mutbl, body) => { + ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => { let def = ast::Defaultness::Final; self.print_item_const( item.ident, @@ -167,8 +168,15 @@ impl<'a> State<'a> { def, ); } - ast::ItemKind::Const(def, ty, body) => { - self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, *def); + ast::ItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => { + self.print_item_const( + item.ident, + None, + ty, + expr.as_deref(), + &item.vis, + *defaultness, + ); } ast::ItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { self.print_fn_full( @@ -507,8 +515,8 @@ impl<'a> State<'a> { ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); } - ast::AssocItemKind::Const(def, ty, body) => { - self.print_item_const(ident, None, ty, body.as_deref(), vis, *def); + ast::AssocItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => { + self.print_item_const(ident, None, ty, expr.as_deref(), vis, *defaultness); } ast::AssocItemKind::Type(box ast::TyAlias { defaultness, diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 68205fa45587..84f75caa6928 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -181,8 +181,8 @@ trait TypeOpInfo<'tcx> { }; let placeholder_region = tcx.mk_re_placeholder(ty::Placeholder { - name: placeholder.name, universe: adjusted_universe.into(), + bound: placeholder.bound, }); let error_region = @@ -191,8 +191,8 @@ trait TypeOpInfo<'tcx> { error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); adjusted_universe.map(|adjusted| { tcx.mk_re_placeholder(ty::Placeholder { - name: error_placeholder.name, universe: adjusted.into(), + bound: error_placeholder.bound, }) }) } else { diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs index fd1fda2ee4bd..e2d04324f3b6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs @@ -11,7 +11,7 @@ use crate::{ }; use rustc_data_structures::fx::FxIndexSet; use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location}; +use rustc_middle::mir::{self, Body, Local, Location}; use rustc_middle::ty::{RegionVid, TyCtxt}; pub(crate) fn find<'tcx>( @@ -70,7 +70,10 @@ impl<'cx, 'tcx> UseFinder<'cx, 'tcx> { block_data .terminator() .successors() - .filter(|&bb| Some(&Some(bb)) != block_data.terminator().unwind()) + .filter(|&bb| { + Some(&mir::UnwindAction::Cleanup(bb)) + != block_data.terminator().unwind() + }) .map(|bb| Location { statement_index: 0, block: bb }), ); } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 7bd4331c5ed9..110354a20d83 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -467,9 +467,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let ty::Ref(region, ..) = ty.kind() { match **region { ty::ReLateBound(_, ty::BoundRegion { kind: br, .. }) - | ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { - printer.region_highlight_mode.highlighting_bound_region(br, counter) - } + | ty::RePlaceholder(ty::PlaceholderRegion { + bound: ty::BoundRegion { kind: br, .. }, + .. + }) => printer.region_highlight_mode.highlighting_bound_region(br, counter), _ => {} } } @@ -485,9 +486,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let region = if let ty::Ref(region, ..) = ty.kind() { match **region { ty::ReLateBound(_, ty::BoundRegion { kind: br, .. }) - | ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { - printer.region_highlight_mode.highlighting_bound_region(br, counter) - } + | ty::RePlaceholder(ty::PlaceholderRegion { + bound: ty::BoundRegion { kind: br, .. }, + .. + }) => printer.region_highlight_mode.highlighting_bound_region(br, counter), _ => {} } region diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index ffe82b46cfd6..9fcebeb0acdc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -207,7 +207,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .regioncx .placeholders_contained_in(lower_bound) .map(|placeholder| { - if let Some(id) = placeholder.name.get_id() + if let Some(id) = placeholder.bound.kind.get_id() && let Some(placeholder_id) = id.as_local() && let gat_hir_id = hir.local_def_id_to_hir_id(placeholder_id) && let Some(generics_impl) = hir.get_parent(gat_hir_id).generics() diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index a71c41632861..498d254da653 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -125,7 +125,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { args, destination, target: _, - cleanup: _, + unwind: _, from_hir_call: _, fn_span: _, } => { @@ -135,7 +135,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } self.mutate_place(location, *destination, Deep); } - TerminatorKind::Assert { cond, expected: _, msg, target: _, cleanup: _ } => { + TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { self.consume_operand(location, cond); use rustc_middle::mir::AssertKind; if let AssertKind::BoundsCheck { len, index } = msg { @@ -173,7 +173,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { options: _, line_spans: _, destination: _, - cleanup: _, + unwind: _, } => { for op in operands { match op { @@ -198,7 +198,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } } TerminatorKind::Goto { target: _ } - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Unreachable | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 1d4d1406239d..3d876155fc95 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -740,7 +740,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx args, destination, target: _, - cleanup: _, + unwind: _, from_hir_call: _, fn_span: _, } => { @@ -750,7 +750,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx } self.mutate_place(loc, (*destination, span), Deep, flow_state); } - TerminatorKind::Assert { cond, expected: _, msg, target: _, cleanup: _ } => { + TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { self.consume_operand(loc, (cond, span), flow_state); use rustc_middle::mir::AssertKind; if let AssertKind::BoundsCheck { len, index } = msg { @@ -770,7 +770,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx options: _, line_spans: _, destination: _, - cleanup: _, + unwind: _, } => { for op in operands { match op { @@ -801,7 +801,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx } TerminatorKind::Goto { target: _ } - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Unreachable | TerminatorKind::Resume | TerminatorKind::Return @@ -845,7 +845,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx } } - TerminatorKind::Abort + TerminatorKind::Terminate | TerminatorKind::Assert { .. } | TerminatorKind::Call { .. } | TerminatorKind::Drop { .. } diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs index 8023ef60d205..2c387edfef07 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs @@ -63,7 +63,7 @@ impl LocalUseMap { elements: &RegionValueElements, body: &Body<'_>, ) -> Self { - let nones = IndexVec::from_elem_n(None, body.local_decls.len()); + let nones = IndexVec::from_elem(None, &body.local_decls); let mut local_use_map = LocalUseMap { first_def_at: nones.clone(), first_use_at: nones.clone(), @@ -76,7 +76,7 @@ impl LocalUseMap { } let mut locals_with_use_data: IndexVec = - IndexVec::from_elem_n(false, body.local_decls.len()); + IndexVec::from_elem(false, &body.local_decls); live_locals.iter().for_each(|&local| locals_with_use_data[local] = true); LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 2fc4e32ecb24..624a4a00c319 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1300,7 +1300,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { match &term.kind { TerminatorKind::Goto { .. } | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable @@ -1342,9 +1342,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let region_ctxt_fn = || { let reg_info = match br.kind { - ty::BoundRegionKind::BrAnon(_, Some(span)) => { - BoundRegionInfo::Span(span) - } + ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span), ty::BoundRegionKind::BrAnon(..) => { BoundRegionInfo::Name(Symbol::intern("anon")) } @@ -1584,7 +1582,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { span_mirbug!(self, block_data, "resume on non-cleanup block!") } } - TerminatorKind::Abort => { + TerminatorKind::Terminate => { if !is_cleanup { span_mirbug!(self, block_data, "abort on non-cleanup block!") } @@ -1610,25 +1608,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } TerminatorKind::Unreachable => {} TerminatorKind::Drop { target, unwind, .. } - | TerminatorKind::Assert { target, cleanup: unwind, .. } => { + | TerminatorKind::Assert { target, unwind, .. } => { self.assert_iscleanup(body, block_data, target, is_cleanup); - if let Some(unwind) = unwind { - if is_cleanup { - span_mirbug!(self, block_data, "unwind on cleanup block") - } - self.assert_iscleanup(body, block_data, unwind, true); - } + self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); } - TerminatorKind::Call { ref target, cleanup, .. } => { + TerminatorKind::Call { ref target, unwind, .. } => { if let &Some(target) = target { self.assert_iscleanup(body, block_data, target, is_cleanup); } - if let Some(cleanup) = cleanup { - if is_cleanup { - span_mirbug!(self, block_data, "cleanup on cleanup block") - } - self.assert_iscleanup(body, block_data, cleanup, true); - } + self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); } TerminatorKind::FalseEdge { real_target, imaginary_target } => { self.assert_iscleanup(body, block_data, real_target, is_cleanup); @@ -1636,23 +1624,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } TerminatorKind::FalseUnwind { real_target, unwind } => { self.assert_iscleanup(body, block_data, real_target, is_cleanup); - if let Some(unwind) = unwind { - if is_cleanup { - span_mirbug!(self, block_data, "cleanup in cleanup block via false unwind"); - } - self.assert_iscleanup(body, block_data, unwind, true); - } + self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); } - TerminatorKind::InlineAsm { destination, cleanup, .. } => { + TerminatorKind::InlineAsm { destination, unwind, .. } => { if let Some(target) = destination { self.assert_iscleanup(body, block_data, target, is_cleanup); } - if let Some(cleanup) = cleanup { - if is_cleanup { - span_mirbug!(self, block_data, "cleanup on cleanup block") - } - self.assert_iscleanup(body, block_data, cleanup, true); - } + self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); } } } @@ -1669,6 +1647,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + fn assert_iscleanup_unwind( + &mut self, + body: &Body<'tcx>, + ctxt: &dyn fmt::Debug, + unwind: UnwindAction, + is_cleanup: bool, + ) { + match unwind { + UnwindAction::Cleanup(unwind) => { + if is_cleanup { + span_mirbug!(self, ctxt, "unwind on cleanup block") + } + self.assert_iscleanup(body, ctxt, unwind, true); + } + UnwindAction::Continue => { + if is_cleanup { + span_mirbug!(self, ctxt, "unwind on cleanup block") + } + } + UnwindAction::Unreachable | UnwindAction::Terminate => (), + } + } + fn check_local(&mut self, body: &Body<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) { match body.local_kind(local) { LocalKind::ReturnPointer | LocalKind::Arg => { diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 305e2c8fe8eb..83429f2ddef3 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -123,8 +123,8 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> .constraints .placeholder_region(self.type_checker.infcx, placeholder); - let reg_info = match placeholder.name { - ty::BoundRegionKind::BrAnon(_, Some(span)) => BoundRegionInfo::Span(span), + let reg_info = match placeholder.bound.kind { + ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span), ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(Symbol::intern("anon")), ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name), ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(Symbol::intern("env")), diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 41b51bae7364..866cc5adbf3b 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -25,12 +25,12 @@ pub fn expand( // FIXME - if we get deref patterns, use them to reduce duplication here let (item, is_stmt, ty_span) = if let Annotatable::Item(item) = &item - && let ItemKind::Static(ty, ..) = &item.kind + && let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind { (item, false, ecx.with_def_site_ctxt(ty.span)) } else if let Annotatable::Stmt(stmt) = &item && let StmtKind::Item(item) = &stmt.kind - && let ItemKind::Static(ty, ..) = &item.kind + && let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind { (item, true, ecx.with_def_site_ctxt(ty.span)) } else { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 71177b8789ba..7697b592e33a 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -7,7 +7,6 @@ #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] -#![feature(is_some_and)] #![feature(is_sorted)] #![feature(let_chains)] #![feature(proc_macro_internals)] diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 44b9c4718a75..a76ed4ee6cee 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -254,25 +254,27 @@ pub fn expand_test_or_bench( let location_info = get_location_info(cx, &item); - let mut test_const = cx.item( - sp, - Ident::new(item.ident.name, sp), - thin_vec![ - // #[cfg(test)] - cx.attr_nested_word(sym::cfg, sym::test, attr_sp), - // #[rustc_test_marker = "test_case_sort_key"] - cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp), - ], - // const $ident: test::TestDescAndFn = - ast::ItemKind::Const( - ast::Defaultness::Final, - cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), - // test::TestDescAndFn { - Some( - cx.expr_struct( - sp, - test_path("TestDescAndFn"), - thin_vec![ + let mut test_const = + cx.item( + sp, + Ident::new(item.ident.name, sp), + thin_vec![ + // #[cfg(test)] + cx.attr_nested_word(sym::cfg, sym::test, attr_sp), + // #[rustc_test_marker = "test_case_sort_key"] + cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp), + ], + // const $ident: test::TestDescAndFn = + ast::ItemKind::Const( + ast::ConstItem { + defaultness: ast::Defaultness::Final, + ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), + // test::TestDescAndFn { + expr: Some( + cx.expr_struct( + sp, + test_path("TestDescAndFn"), + thin_vec![ // desc: test::TestDesc { field( "desc", @@ -359,10 +361,12 @@ pub fn expand_test_or_bench( // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) field("testfn", test_fn), // } ], - ), // } + ), // } + ), + } + .into(), ), - ), - ); + ); test_const = test_const.map(|mut tc| { tc.vis.kind = ast::VisibilityKind::Public; tc diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 43ab6c044283..80f497333a63 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -53,7 +53,7 @@ pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn Resolve // even in non-test builds let test_runner = get_test_runner(span_diagnostic, &krate); - if sess.opts.test { + if sess.is_test_crate() { let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) { (PanicStrategy::Abort, true) => PanicStrategy::Abort, (PanicStrategy::Abort, false) => { diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 2630f02e6eb3..f5301f9f7f10 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -345,7 +345,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { TerminatorKind::Return => { crate::abi::codegen_return(fx); } - TerminatorKind::Assert { cond, expected, msg, target, cleanup: _ } => { + TerminatorKind::Assert { cond, expected, msg, target, unwind: _ } => { if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() { let target = fx.get_block(*target); fx.bcx.ins().jump(target, &[]); @@ -450,7 +450,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { destination, target, fn_span, - cleanup: _, + unwind: _, from_hir_call: _, } => { fx.tcx.prof.generic_activity("codegen call").run(|| { @@ -470,7 +470,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { options, destination, line_spans: _, - cleanup: _, + unwind: _, } => { if options.contains(InlineAsmOptions::MAY_UNWIND) { fx.tcx.sess.span_fatal( @@ -488,7 +488,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { *destination, ); } - TerminatorKind::Abort => { + TerminatorKind::Terminate => { codegen_panic_cannot_unwind(fx, source_info); } TerminatorKind::Resume => { diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index ebb4de33f990..e87f4e258911 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -549,7 +549,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index d9f8170a3cff..e7668341eb6e 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -381,7 +381,7 @@ impl<'tcx> AsmMethods<'tcx> for CodegenCx<'_, 'tcx> { } unsafe { - llvm::LLVMRustAppendModuleInlineAsm( + llvm::LLVMAppendModuleInlineAsm( self.llmod, template_str.as_ptr().cast(), template_str.len(), diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index fb563f70ed09..7136f750f39d 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -904,9 +904,9 @@ unsafe fn embed_bitcode( // We need custom section flags, so emit module-level inline assembly. let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); - llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); - llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 63e8a67db53e..6819a2af09da 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -2,7 +2,7 @@ use crate::abi::FnAbiLlvmExt; use crate::attributes; use crate::common::Funclet; use crate::context::CodegenCx; -use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock}; +use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, True}; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; @@ -841,7 +841,15 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn intcast(&mut self, val: &'ll Value, dest_ty: &'ll Type, is_signed: bool) -> &'ll Value { - unsafe { llvm::LLVMRustBuildIntCast(self.llbuilder, val, dest_ty, is_signed) } + unsafe { + llvm::LLVMBuildIntCast2( + self.llbuilder, + val, + dest_ty, + if is_signed { True } else { False }, + UNNAMED, + ) + } } fn pointercast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { @@ -1001,11 +1009,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn cleanup_pad(&mut self, parent: Option<&'ll Value>, args: &[&'ll Value]) -> Funclet<'ll> { let name = cstr!("cleanuppad"); let ret = unsafe { - llvm::LLVMRustBuildCleanupPad( + llvm::LLVMBuildCleanupPad( self.llbuilder, parent, - args.len() as c_uint, args.as_ptr(), + args.len() as c_uint, name.as_ptr(), ) }; @@ -1014,7 +1022,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn cleanup_ret(&mut self, funclet: &Funclet<'ll>, unwind: Option<&'ll BasicBlock>) { unsafe { - llvm::LLVMRustBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind) + llvm::LLVMBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind) .expect("LLVM does not have support for cleanupret"); } } @@ -1022,11 +1030,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn catch_pad(&mut self, parent: &'ll Value, args: &[&'ll Value]) -> Funclet<'ll> { let name = cstr!("catchpad"); let ret = unsafe { - llvm::LLVMRustBuildCatchPad( + llvm::LLVMBuildCatchPad( self.llbuilder, parent, - args.len() as c_uint, args.as_ptr(), + args.len() as c_uint, name.as_ptr(), ) }; @@ -1041,7 +1049,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { ) -> &'ll Value { let name = cstr!("catchswitch"); let ret = unsafe { - llvm::LLVMRustBuildCatchSwitch( + llvm::LLVMBuildCatchSwitch( self.llbuilder, parent, unwind, @@ -1052,7 +1060,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let ret = ret.expect("LLVM does not have support for catchswitch"); for handler in handlers { unsafe { - llvm::LLVMRustAddHandler(ret, handler); + llvm::LLVMAddHandler(ret, handler); } } ret @@ -1376,8 +1384,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } pub fn catch_ret(&mut self, funclet: &Funclet<'ll>, unwind: &'ll BasicBlock) -> &'ll Value { - let ret = - unsafe { llvm::LLVMRustBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) }; + let ret = unsafe { llvm::LLVMBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) }; ret.expect("LLVM does not have support for catchret") } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 9116e71beac8..940358acde9a 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -7,7 +7,6 @@ use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; use cstr::cstr; -use libc::c_uint; use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -486,10 +485,10 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { // go into custom sections of the wasm executable. if self.tcx.sess.target.is_like_wasm { if let Some(section) = attrs.link_section { - let section = llvm::LLVMMDStringInContext( + let section = llvm::LLVMMDStringInContext2( self.llcx, section.as_str().as_ptr().cast(), - section.as_str().len() as c_uint, + section.as_str().len(), ); assert!(alloc.provenance().ptrs().is_empty()); @@ -498,17 +497,15 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { // as part of the interpreter execution). let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); - let alloc = llvm::LLVMMDStringInContext( - self.llcx, - bytes.as_ptr().cast(), - bytes.len() as c_uint, - ); + let alloc = + llvm::LLVMMDStringInContext2(self.llcx, bytes.as_ptr().cast(), bytes.len()); let data = [section, alloc]; - let meta = llvm::LLVMMDNodeInContext(self.llcx, data.as_ptr(), 2); + let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()); + let val = llvm::LLVMMetadataAsValue(self.llcx, meta); llvm::LLVMAddNamedMetadataOperand( self.llmod, "wasm.custom_sections\0".as_ptr().cast(), - meta, + val, ); } } else { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index e2a592d851a8..21a0a60b012a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -830,24 +830,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( } .unwrap_or_default(); let split_name = split_name.to_str().unwrap(); - - // FIXME(#60020): - // - // This should actually be - // - // let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo); - // - // That is, we should set LLVM's emission kind to `LineTablesOnly` if - // we are compiling with "limited" debuginfo. However, some of the - // existing tools relied on slightly more debuginfo being generated than - // would be the case with `LineTablesOnly`, and we did not want to break - // these tools in a "drive-by fix", without a good idea or plan about - // what limited debuginfo should exactly look like. So for now we keep - // the emission kind as `FullDebug`. - // - // See https://github.com/rust-lang/rust/issues/60020 for details. - let kind = DebugEmissionKind::FullDebug; - assert!(tcx.sess.opts.debuginfo != DebugInfo::None); + let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo); unsafe { let compile_unit_file = llvm::LLVMRustDIBuilderCreateFile( @@ -881,8 +864,6 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( ); if tcx.sess.opts.unstable_opts.profile { - let cu_desc_metadata = - llvm::LLVMRustMetadataAsValue(debug_context.llcontext, unit_metadata); let default_gcda_path = &output_filenames.with_extension("gcda"); let gcda_path = tcx.sess.opts.unstable_opts.profile_emit.as_ref().unwrap_or(default_gcda_path); @@ -890,20 +871,17 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( let gcov_cu_info = [ path_to_mdstring(debug_context.llcontext, &output_filenames.with_extension("gcno")), path_to_mdstring(debug_context.llcontext, gcda_path), - cu_desc_metadata, + unit_metadata, ]; - let gcov_metadata = llvm::LLVMMDNodeInContext( + let gcov_metadata = llvm::LLVMMDNodeInContext2( debug_context.llcontext, gcov_cu_info.as_ptr(), - gcov_cu_info.len() as c_uint, + gcov_cu_info.len(), ); + let val = llvm::LLVMMetadataAsValue(debug_context.llcontext, gcov_metadata); let llvm_gcov_ident = cstr!("llvm.gcov"); - llvm::LLVMAddNamedMetadataOperand( - debug_context.llmod, - llvm_gcov_ident.as_ptr(), - gcov_metadata, - ); + llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, llvm_gcov_ident.as_ptr(), val); } // Insert `llvm.ident` metadata on the wasm targets since that will @@ -924,15 +902,9 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( return unit_metadata; }; - fn path_to_mdstring<'ll>(llcx: &'ll llvm::Context, path: &Path) -> &'ll Value { + fn path_to_mdstring<'ll>(llcx: &'ll llvm::Context, path: &Path) -> &'ll llvm::Metadata { let path_str = path_to_c_string(path); - unsafe { - llvm::LLVMMDStringInContext( - llcx, - path_str.as_ptr(), - path_str.as_bytes().len() as c_uint, - ) - } + unsafe { llvm::LLVMMDStringInContext2(llcx, path_str.as_ptr(), path_str.as_bytes().len()) } } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 5392534cfcb7..d56c414cf651 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -209,8 +209,7 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) { unsafe { - let dbg_loc_as_llval = llvm::LLVMRustMetadataAsValue(self.cx().llcx, dbg_loc); - llvm::LLVMSetCurrentDebugLocation(self.llbuilder, dbg_loc_as_llval); + llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc); } } @@ -402,7 +401,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { cx: &CodegenCx<'ll, 'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) -> &'ll DIArray { - if cx.sess().opts.debuginfo == DebugInfo::Limited { + if cx.sess().opts.debuginfo != DebugInfo::Full { return create_DIArray(DIB(cx), &[]); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 0d63e634ad88..09f3fe021650 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -946,15 +946,27 @@ pub mod debuginfo { NoDebug, FullDebug, LineTablesOnly, + DebugDirectivesOnly, } impl DebugEmissionKind { pub fn from_generic(kind: rustc_session::config::DebugInfo) -> Self { + // We should be setting LLVM's emission kind to `LineTablesOnly` if + // we are compiling with "limited" debuginfo. However, some of the + // existing tools relied on slightly more debuginfo being generated than + // would be the case with `LineTablesOnly`, and we did not want to break + // these tools in a "drive-by fix", without a good idea or plan about + // what limited debuginfo should exactly look like. So for now we are + // instead adding a new debuginfo option "line-tables-only" so as to + // not break anything and to allow users to have 'limited' debug info. + // + // See https://github.com/rust-lang/rust/issues/60020 for details. use rustc_session::config::DebugInfo; match kind { DebugInfo::None => DebugEmissionKind::NoDebug, - DebugInfo::Limited => DebugEmissionKind::LineTablesOnly, - DebugInfo::Full => DebugEmissionKind::FullDebug, + DebugInfo::LineDirectivesOnly => DebugEmissionKind::DebugDirectivesOnly, + DebugInfo::LineTablesOnly => DebugEmissionKind::LineTablesOnly, + DebugInfo::Limited | DebugInfo::Full => DebugEmissionKind::FullDebug, } } } @@ -1006,7 +1018,7 @@ extern "C" { pub fn LLVMSetDataLayout(M: &Module, Triple: *const c_char); /// See Module::setModuleInlineAsm. - pub fn LLVMRustAppendModuleInlineAsm(M: &Module, Asm: *const c_char, AsmLen: size_t); + pub fn LLVMAppendModuleInlineAsm(M: &Module, Asm: *const c_char, Len: size_t); /// See llvm::LLVMTypeKind::getTypeID. pub fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind; @@ -1053,7 +1065,7 @@ extern "C" { // Operations on other types pub fn LLVMVoidTypeInContext(C: &Context) -> &Type; - pub fn LLVMRustMetadataTypeInContext(C: &Context) -> &Type; + pub fn LLVMMetadataTypeInContext(C: &Context) -> &Type; // Operations on all values pub fn LLVMTypeOf(Val: &Value) -> &Type; @@ -1072,7 +1084,12 @@ extern "C" { pub fn LLVMGetPoison(Ty: &Type) -> &Value; // Operations on metadata + // FIXME: deprecated, replace with LLVMMDStringInContext2 pub fn LLVMMDStringInContext(C: &Context, Str: *const c_char, SLen: c_uint) -> &Value; + + pub fn LLVMMDStringInContext2(C: &Context, Str: *const c_char, SLen: size_t) -> &Metadata; + + // FIXME: deprecated, replace with LLVMMDNodeInContext2 pub fn LLVMMDNodeInContext<'a>( C: &'a Context, Vals: *const &'a Value, @@ -1111,6 +1128,8 @@ extern "C" { Packed: Bool, ) -> &'a Value; + // FIXME: replace with LLVMConstArray2 when bumped minimal version to llvm-17 + // https://github.com/llvm/llvm-project/commit/35276f16e5a2cae0dfb49c0fbf874d4d2f177acc pub fn LLVMConstArray<'a>( ElementTy: &'a Type, ConstantVals: *const &'a Value, @@ -1250,7 +1269,7 @@ extern "C" { pub fn LLVMDisposeBuilder<'a>(Builder: &'a mut Builder<'a>); // Metadata - pub fn LLVMSetCurrentDebugLocation<'a>(Builder: &Builder<'a>, L: &'a Value); + pub fn LLVMSetCurrentDebugLocation2<'a>(Builder: &Builder<'a>, Loc: &'a Metadata); // Terminators pub fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value; @@ -1290,38 +1309,38 @@ extern "C" { pub fn LLVMBuildResume<'a>(B: &Builder<'a>, Exn: &'a Value) -> &'a Value; pub fn LLVMBuildUnreachable<'a>(B: &Builder<'a>) -> &'a Value; - pub fn LLVMRustBuildCleanupPad<'a>( + pub fn LLVMBuildCleanupPad<'a>( B: &Builder<'a>, ParentPad: Option<&'a Value>, - ArgCnt: c_uint, Args: *const &'a Value, + NumArgs: c_uint, Name: *const c_char, ) -> Option<&'a Value>; - pub fn LLVMRustBuildCleanupRet<'a>( + pub fn LLVMBuildCleanupRet<'a>( B: &Builder<'a>, CleanupPad: &'a Value, - UnwindBB: Option<&'a BasicBlock>, + BB: Option<&'a BasicBlock>, ) -> Option<&'a Value>; - pub fn LLVMRustBuildCatchPad<'a>( + pub fn LLVMBuildCatchPad<'a>( B: &Builder<'a>, ParentPad: &'a Value, - ArgCnt: c_uint, Args: *const &'a Value, + NumArgs: c_uint, Name: *const c_char, ) -> Option<&'a Value>; - pub fn LLVMRustBuildCatchRet<'a>( + pub fn LLVMBuildCatchRet<'a>( B: &Builder<'a>, - Pad: &'a Value, + CatchPad: &'a Value, BB: &'a BasicBlock, ) -> Option<&'a Value>; - pub fn LLVMRustBuildCatchSwitch<'a>( + pub fn LLVMBuildCatchSwitch<'a>( Builder: &Builder<'a>, ParentPad: Option<&'a Value>, - BB: Option<&'a BasicBlock>, + UnwindBB: Option<&'a BasicBlock>, NumHandlers: c_uint, Name: *const c_char, ) -> Option<&'a Value>; - pub fn LLVMRustAddHandler<'a>(CatchSwitch: &'a Value, Handler: &'a BasicBlock); + pub fn LLVMAddHandler<'a>(CatchSwitch: &'a Value, Dest: &'a BasicBlock); pub fn LLVMSetPersonalityFn<'a>(Func: &'a Value, Pers: &'a Value); // Add a case to the switch instruction @@ -1615,11 +1634,12 @@ extern "C" { DestTy: &'a Type, Name: *const c_char, ) -> &'a Value; - pub fn LLVMRustBuildIntCast<'a>( + pub fn LLVMBuildIntCast2<'a>( B: &Builder<'a>, Val: &'a Value, DestTy: &'a Type, - IsSigned: bool, + IsSigned: Bool, + Name: *const c_char, ) -> &'a Value; // Comparisons @@ -1908,7 +1928,7 @@ extern "C" { ); pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool; - pub fn LLVMRustMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; + pub fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>; diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index ff111d96f840..bef4647f2078 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -53,7 +53,7 @@ impl<'ll> CodegenCx<'ll, '_> { } pub(crate) fn type_metadata(&self) -> &'ll Type { - unsafe { llvm::LLVMRustMetadataTypeInContext(self.llcx) } + unsafe { llvm::LLVMMetadataTypeInContext(self.llcx) } } ///x Creates an integer type with the given number of bits, e.g., i24 diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 6a0d0ca55c25..7a5fa5a370cb 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2301,7 +2301,7 @@ fn add_native_libs_from_crate( || (whole_archive == None && bundle && cnum == LOCAL_CRATE - && sess.opts.test); + && sess.is_test_crate()); if bundle && cnum != LOCAL_CRATE { if let Some(filename) = lib.filename { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 69bb00f804d3..65dfc325a118 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1121,9 +1121,12 @@ impl<'a> Linker for EmLinker<'a> { fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { // Preserve names or generate source maps depending on debug info + // For more information see https://emscripten.org/docs/tools_reference/emcc.html#emcc-g self.cmd.arg(match self.sess.opts.debuginfo { DebugInfo::None => "-g0", - DebugInfo::Limited => "--profiling-funcs", + DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => { + "--profiling-funcs" + } DebugInfo::Full => "-g", }); } diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 4ab56699922f..3e3fcc08bd64 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -13,8 +13,7 @@ use object::{ use snap::write::FrameEncoder; use rustc_data_structures::memmap::Mmap; -use rustc_data_structures::owning_ref::OwningRef; -use rustc_data_structures::rustc_erase_owner; +use rustc_data_structures::owned_slice::try_slice_owned; use rustc_data_structures::sync::MetadataRef; use rustc_metadata::fs::METADATA_FILENAME; use rustc_metadata::EncodedMetadata; @@ -42,10 +41,10 @@ fn load_metadata_with( ) -> Result { let file = File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?; - let data = unsafe { Mmap::map(file) } - .map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e))?; - let metadata = OwningRef::new(data).try_map(f)?; - return Ok(rustc_erase_owner!(metadata.map_owner_box())); + + unsafe { Mmap::map(file) } + .map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e)) + .and_then(|mmap| try_slice_owned(mmap, |mmap| f(mmap))) } impl MetadataLoader for DefaultMetadataLoader { diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index dcf533dc39c3..115a41050d2a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -284,7 +284,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec) -> IndexVec { /* nothing to do */ } - TerminatorKind::Call { cleanup: unwind, .. } - | TerminatorKind::InlineAsm { cleanup: unwind, .. } - | TerminatorKind::Assert { cleanup: unwind, .. } + TerminatorKind::Call { unwind, .. } + | TerminatorKind::InlineAsm { unwind, .. } + | TerminatorKind::Assert { unwind, .. } | TerminatorKind::Drop { unwind, .. } => { - if let Some(unwind) = unwind { + if let mir::UnwindAction::Cleanup(unwind) = unwind { debug!( "cleanup_kinds: {:?}/{:?} registering {:?} as funclet", bb, data, unwind diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index c086d1b7f5a3..dd86977817fb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -147,7 +147,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } /// Call `fn_ptr` of `fn_abi` with the arguments `llargs`, the optional - /// return destination `destination` and the cleanup function `cleanup`. + /// return destination `destination` and the unwind action `unwind`. fn do_call>( &self, fx: &mut FunctionCx<'a, 'tcx, Bx>, @@ -156,7 +156,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { fn_ptr: Bx::Value, llargs: &[Bx::Value], destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>, - cleanup: Option, + mut unwind: mir::UnwindAction, copied_constant_arguments: &[PlaceRef<'tcx, ::Value>], mergeable_succ: bool, ) -> MergingSucc { @@ -164,23 +164,23 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { // do an invoke, otherwise do a call. let fn_ty = bx.fn_decl_backend_type(&fn_abi); - let unwind_block = if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) { - Some(self.llbb_with_cleanup(fx, cleanup)) - } else if fx.mir[self.bb].is_cleanup - && fn_abi.can_unwind - && !base::wants_msvc_seh(fx.cx.tcx().sess) - { - // Exception must not propagate out of the execution of a cleanup (doing so - // can cause undefined behaviour). We insert a double unwind guard for - // functions that can potentially unwind to protect against this. - // - // This is not necessary for SEH which does not use successive unwinding - // like Itanium EH. EH frames in SEH are different from normal function - // frames and SEH will abort automatically if an exception tries to - // propagate out from cleanup. - Some(fx.double_unwind_guard()) - } else { - None + if !fn_abi.can_unwind { + unwind = mir::UnwindAction::Unreachable; + } + + let unwind_block = match unwind { + mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)), + mir::UnwindAction::Continue => None, + mir::UnwindAction::Unreachable => None, + mir::UnwindAction::Terminate => { + if fx.mir[self.bb].is_cleanup && base::wants_msvc_seh(fx.cx.tcx().sess) { + // SEH will abort automatically if an exception tries to + // propagate out from cleanup. + None + } else { + Some(fx.terminate_block()) + } + } }; if let Some(unwind_block) = unwind_block { @@ -234,7 +234,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } } - /// Generates inline assembly with optional `destination` and `cleanup`. + /// Generates inline assembly with optional `destination` and `unwind`. fn do_inlineasm>( &self, fx: &mut FunctionCx<'a, 'tcx, Bx>, @@ -244,11 +244,18 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { options: InlineAsmOptions, line_spans: &[Span], destination: Option, - cleanup: Option, + unwind: mir::UnwindAction, instance: Instance<'_>, mergeable_succ: bool, ) -> MergingSucc { - if let Some(cleanup) = cleanup { + let unwind_target = match unwind { + mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)), + mir::UnwindAction::Terminate => Some(fx.terminate_block()), + mir::UnwindAction::Continue => None, + mir::UnwindAction::Unreachable => None, + }; + + if let Some(cleanup) = unwind_target { let ret_llbb = if let Some(target) = destination { fx.llbb(target) } else { @@ -261,7 +268,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { options, line_spans, instance, - Some((ret_llbb, self.llbb_with_cleanup(fx, cleanup), self.funclet(fx))), + Some((ret_llbb, cleanup, self.funclet(fx))), ); MergingSucc::False } else { @@ -431,7 +438,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &mut Bx, location: mir::Place<'tcx>, target: mir::BasicBlock, - unwind: Option, + unwind: mir::UnwindAction, mergeable_succ: bool, ) -> MergingSucc { let ty = location.ty(self.mir, bx.tcx()).ty; @@ -552,7 +559,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { expected: bool, msg: &mir::AssertMessage<'tcx>, target: mir::BasicBlock, - cleanup: Option, + unwind: mir::UnwindAction, mergeable_succ: bool, ) -> MergingSucc { let span = terminator.source_info.span; @@ -618,12 +625,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (fn_abi, llfn) = common::build_langcall(bx, Some(span), lang_item); // Codegen the actual panic invoke/call. - let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &args, None, cleanup, &[], false); + let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], false); assert_eq!(merging_succ, MergingSucc::False); MergingSucc::False } - fn codegen_abort_terminator( + fn codegen_terminate_terminator( &mut self, helper: TerminatorCodegenHelper<'tcx>, bx: &mut Bx, @@ -636,7 +643,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicCannotUnwind); // Codegen the actual panic invoke/call. - let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &[], None, None, &[], false); + let merging_succ = helper.do_call( + self, + bx, + fn_abi, + llfn, + &[], + None, + mir::UnwindAction::Unreachable, + &[], + false, + ); assert_eq!(merging_succ, MergingSucc::False); } @@ -649,7 +666,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { instance: Option>, source_info: mir::SourceInfo, target: Option, - cleanup: Option, + unwind: mir::UnwindAction, mergeable_succ: bool, ) -> Option { // Emit a panic or a no-op for `assert_*` intrinsics. @@ -696,7 +713,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llfn, &[msg.0, msg.1], target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)), - cleanup, + unwind, &[], mergeable_succ, ) @@ -719,7 +736,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args: &[mir::Operand<'tcx>], destination: mir::Place<'tcx>, target: Option, - cleanup: Option, + unwind: mir::UnwindAction, fn_span: Span, mergeable_succ: bool, ) -> MergingSucc { @@ -783,7 +800,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { instance, source_info, target, - cleanup, + unwind, mergeable_succ, ) { return merging_succ; @@ -1064,7 +1081,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_ptr, &llargs, target.as_ref().map(|&target| (ret_dest, target)), - cleanup, + unwind, &copied_constant_arguments, false, ); @@ -1084,7 +1101,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_ptr, &llargs, target.as_ref().map(|&target| (ret_dest, target)), - cleanup, + unwind, &copied_constant_arguments, mergeable_succ, ) @@ -1100,7 +1117,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { options: ast::InlineAsmOptions, line_spans: &[Span], destination: Option, - cleanup: Option, + unwind: mir::UnwindAction, instance: Instance<'_>, mergeable_succ: bool, ) -> MergingSucc { @@ -1164,7 +1181,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { options, line_spans, destination, - cleanup, + unwind, instance, mergeable_succ, ) @@ -1246,8 +1263,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { MergingSucc::False } - mir::TerminatorKind::Abort => { - self.codegen_abort_terminator(helper, bx, terminator); + mir::TerminatorKind::Terminate => { + self.codegen_terminate_terminator(helper, bx, terminator); MergingSucc::False } @@ -1274,7 +1291,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ()) } - mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => self + mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, unwind } => self .codegen_assert_terminator( helper, bx, @@ -1283,7 +1300,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { expected, msg, target, - cleanup, + unwind, mergeable_succ(), ), @@ -1292,7 +1309,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ref args, destination, target, - cleanup, + unwind, from_hir_call: _, fn_span, } => self.codegen_call_terminator( @@ -1303,7 +1320,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args, destination, target, - cleanup, + unwind, fn_span, mergeable_succ(), ), @@ -1320,7 +1337,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { options, line_spans, destination, - cleanup, + unwind, } => self.codegen_asm_terminator( helper, bx, @@ -1330,7 +1347,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { options, line_spans, destination, - cleanup, + unwind, self.instance, mergeable_succ(), ), @@ -1536,62 +1553,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn landing_pad_for_uncached(&mut self, bb: mir::BasicBlock) -> Bx::BasicBlock { let llbb = self.llbb(bb); if base::wants_msvc_seh(self.cx.sess()) { - let funclet; - let ret_llbb; - match self.mir[bb].terminator.as_ref().map(|t| &t.kind) { - // This is a basic block that we're aborting the program for, - // notably in an `extern` function. These basic blocks are inserted - // so that we assert that `extern` functions do indeed not panic, - // and if they do we abort the process. - // - // On MSVC these are tricky though (where we're doing funclets). If - // we were to do a cleanuppad (like below) the normal functions like - // `longjmp` would trigger the abort logic, terminating the - // program. Instead we insert the equivalent of `catch(...)` for C++ - // which magically doesn't trigger when `longjmp` files over this - // frame. - // - // Lots more discussion can be found on #48251 but this codegen is - // modeled after clang's for: - // - // try { - // foo(); - // } catch (...) { - // bar(); - // } - Some(&mir::TerminatorKind::Abort) => { - let cs_llbb = - Bx::append_block(self.cx, self.llfn, &format!("cs_funclet{:?}", bb)); - let cp_llbb = - Bx::append_block(self.cx, self.llfn, &format!("cp_funclet{:?}", bb)); - ret_llbb = cs_llbb; - - let mut cs_bx = Bx::build(self.cx, cs_llbb); - let cs = cs_bx.catch_switch(None, None, &[cp_llbb]); - - // The "null" here is actually a RTTI type descriptor for the - // C++ personality function, but `catch (...)` has no type so - // it's null. The 64 here is actually a bitfield which - // represents that this is a catch-all block. - let mut cp_bx = Bx::build(self.cx, cp_llbb); - let null = cp_bx.const_null( - cp_bx.type_i8p_ext(cp_bx.cx().data_layout().instruction_address_space), - ); - let sixty_four = cp_bx.const_i32(64); - funclet = cp_bx.catch_pad(cs, &[null, sixty_four, null]); - cp_bx.br(llbb); - } - _ => { - let cleanup_llbb = - Bx::append_block(self.cx, self.llfn, &format!("funclet_{:?}", bb)); - ret_llbb = cleanup_llbb; - let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb); - funclet = cleanup_bx.cleanup_pad(None, &[]); - cleanup_bx.br(llbb); - } - } + let cleanup_bb = Bx::append_block(self.cx, self.llfn, &format!("funclet_{:?}", bb)); + let mut cleanup_bx = Bx::build(self.cx, cleanup_bb); + let funclet = cleanup_bx.cleanup_pad(None, &[]); + cleanup_bx.br(llbb); self.funclets[bb] = Some(funclet); - ret_llbb + cleanup_bb } else { let cleanup_llbb = Bx::append_block(self.cx, self.llfn, "cleanup"); let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb); @@ -1618,26 +1585,68 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) } - fn double_unwind_guard(&mut self) -> Bx::BasicBlock { - self.double_unwind_guard.unwrap_or_else(|| { - assert!(!base::wants_msvc_seh(self.cx.sess())); + fn terminate_block(&mut self) -> Bx::BasicBlock { + self.terminate_block.unwrap_or_else(|| { + let funclet; + let llbb; + let mut bx; + if base::wants_msvc_seh(self.cx.sess()) { + // This is a basic block that we're aborting the program for, + // notably in an `extern` function. These basic blocks are inserted + // so that we assert that `extern` functions do indeed not panic, + // and if they do we abort the process. + // + // On MSVC these are tricky though (where we're doing funclets). If + // we were to do a cleanuppad (like below) the normal functions like + // `longjmp` would trigger the abort logic, terminating the + // program. Instead we insert the equivalent of `catch(...)` for C++ + // which magically doesn't trigger when `longjmp` files over this + // frame. + // + // Lots more discussion can be found on #48251 but this codegen is + // modeled after clang's for: + // + // try { + // foo(); + // } catch (...) { + // bar(); + // } + llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate"); + let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate"); + + let mut cs_bx = Bx::build(self.cx, llbb); + let cs = cs_bx.catch_switch(None, None, &[cp_llbb]); + + // The "null" here is actually a RTTI type descriptor for the + // C++ personality function, but `catch (...)` has no type so + // it's null. The 64 here is actually a bitfield which + // represents that this is a catch-all block. + bx = Bx::build(self.cx, cp_llbb); + let null = + bx.const_null(bx.type_i8p_ext(bx.cx().data_layout().instruction_address_space)); + let sixty_four = bx.const_i32(64); + funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null])); + } else { + llbb = Bx::append_block(self.cx, self.llfn, "terminate"); + bx = Bx::build(self.cx, llbb); + + let llpersonality = self.cx.eh_personality(); + bx.cleanup_landing_pad(llpersonality); + + funclet = None; + } - let llbb = Bx::append_block(self.cx, self.llfn, "abort"); - let mut bx = Bx::build(self.cx, llbb); self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span)); - let llpersonality = self.cx.eh_personality(); - bx.cleanup_landing_pad(llpersonality); - let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicCannotUnwind); let fn_ty = bx.fn_decl_backend_type(&fn_abi); - let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &[], None); + let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &[], funclet.as_ref()); bx.do_not_inline(llret); bx.unreachable(); - self.double_unwind_guard = Some(llbb); + self.terminate_block = Some(llbb); llbb }) } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index ff25d1e38236..280f0207116f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -165,11 +165,15 @@ fn calculate_debuginfo_offset< mir::ProjectionElem::Downcast(_, variant) => { place = place.downcast(bx, variant); } - _ => span_bug!( - var.source_info.span, - "unsupported var debuginfo place `{:?}`", - mir::Place { local, projection: var.projection }, - ), + _ => { + // Sanity check for `can_use_in_debuginfo`. + debug_assert!(!elem.can_use_in_debuginfo()); + span_bug!( + var.source_info.span, + "unsupported var debuginfo place `{:?}`", + mir::Place { local, projection: var.projection }, + ) + } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 189549953d94..3dadb33c9691 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -73,8 +73,8 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// Cached unreachable block unreachable_block: Option, - /// Cached double unwind guarding block - double_unwind_guard: Option, + /// Cached terminate upon unwinding block + terminate_block: Option, /// The location where each MIR arg/var/tmp/ret is stored. This is /// usually an `PlaceRef` representing an alloca, but not always: @@ -166,7 +166,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let start_llbb = Bx::append_block(cx, llfn, "start"); let mut start_bx = Bx::build(cx, start_llbb); - if mir.basic_blocks.iter().any(|bb| bb.is_cleanup) { + if mir.basic_blocks.iter().any(|bb| { + bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate)) + }) { start_bx.set_personality_fn(cx.eh_personality()); } @@ -189,7 +191,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( personality_slot: None, cached_llbbs, unreachable_block: None, - double_unwind_guard: None, + terminate_block: None, cleanup_kinds, landing_pads: IndexVec::from_elem(None, &mir.basic_blocks), funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()), diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index b45e7c834e72..b37797fef4ce 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -23,10 +23,26 @@ pub enum OperandValue { /// to be valid for the operand's lifetime. /// The second value, if any, is the extra data (vtable or length) /// which indicates that it refers to an unsized rvalue. + /// + /// An `OperandValue` has this variant for types which are neither + /// `Immediate` nor `Pair`s. The backend value in this variant must be a + /// pointer to the *non*-immediate backend type. That pointee type is the + /// one returned by [`LayoutTypeMethods::backend_type`]. Ref(V, Option, Align), - /// A single LLVM value. + /// A single LLVM immediate value. + /// + /// An `OperandValue` *must* be this variant for any type for which + /// [`LayoutTypeMethods::is_backend_immediate`] returns `true`. + /// The backend value in this variant must be the *immediate* backend type, + /// as returned by [`LayoutTypeMethods::immediate_backend_type`]. Immediate(V), /// A pair of immediate LLVM values. Used by fat pointers too. + /// + /// An `OperandValue` *must* be this variant for any type for which + /// [`LayoutTypeMethods::is_backend_scalar_pair`] returns `true`. + /// The backend values in this variant must be the *immediate* backend types, + /// as returned by [`LayoutTypeMethods::scalar_pair_element_backend_type`] + /// with `immediate: true`. Pair(V, V), } @@ -243,6 +259,31 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } impl<'a, 'tcx, V: CodegenObject> OperandValue { + /// Returns an `OperandValue` that's generally UB to use in any way. + /// + /// Depending on the `layout`, returns an `Immediate` or `Pair` containing + /// poison value(s), or a `Ref` containing a poison pointer. + /// + /// Supports sized types only. + pub fn poison>( + bx: &mut Bx, + layout: TyAndLayout<'tcx>, + ) -> OperandValue { + assert!(layout.is_sized()); + if bx.cx().is_backend_immediate(layout) { + let ibty = bx.cx().immediate_backend_type(layout); + OperandValue::Immediate(bx.const_poison(ibty)) + } else if bx.cx().is_backend_scalar_pair(layout) { + let ibty0 = bx.cx().scalar_pair_element_backend_type(layout, 0, true); + let ibty1 = bx.cx().scalar_pair_element_backend_type(layout, 1, true); + OperandValue::Pair(bx.const_poison(ibty0), bx.const_poison(ibty1)) + } else { + let bty = bx.cx().backend_type(layout); + let ptr_bty = bx.cx().type_ptr_to(bty); + OperandValue::Ref(bx.const_poison(ptr_bty), None, layout.align.abi) + } + } + pub fn store>( self, bx: &mut Bx, diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index d49d23afe513..d88226f5db05 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -10,7 +10,7 @@ use crate::MemFlags; use rustc_middle::mir; use rustc_middle::mir::Operand; use rustc_middle::ty::cast::{CastTy, IntTy}; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_target::abi::{self, FIRST_VARIANT}; @@ -158,33 +158,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { debug_assert!(src.layout.is_sized()); debug_assert!(dst.layout.is_sized()); - if src.layout.size != dst.layout.size - || src.layout.abi == abi::Abi::Uninhabited - || dst.layout.abi == abi::Abi::Uninhabited - { - // In all of these cases it's UB to run this transmute, but that's - // known statically so might as well trap for it, rather than just - // making it unreachable. - bx.abort(); - return; - } - - let size_in_bytes = src.layout.size.bytes(); - if size_in_bytes == 0 { - // Nothing to write + if let Some(val) = self.codegen_transmute_operand(bx, src, dst.layout) { + val.store(bx, dst); return; } match src.val { - OperandValue::Ref(src_llval, meta, src_align) => { - debug_assert_eq!(meta, None); - // For a place-to-place transmute, call `memcpy` directly so that - // both arguments get the best-available alignment information. - let bytes = bx.cx().const_usize(size_in_bytes); - let flags = MemFlags::empty(); - bx.memcpy(dst.llval, dst.align, src_llval, src_align, bytes, flags); + OperandValue::Ref(..) => { + span_bug!( + self.mir.span, + "Operand path should have handled transmute \ + from `Ref` {src:?} to place {dst:?}" + ); } - OperandValue::Immediate(_) | OperandValue::Pair(_, _) => { + OperandValue::Immediate(..) | OperandValue::Pair(..) => { // When we have immediate(s), the alignment of the source is irrelevant, // so we can store them using the destination's alignment. let llty = bx.backend_type(src.layout); @@ -194,6 +181,123 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + /// Attempts to transmute an `OperandValue` to another `OperandValue`. + /// + /// Returns `None` for cases that can't work in that framework, such as for + /// `Immediate`->`Ref` that needs an `alloc` to get the location. + fn codegen_transmute_operand( + &mut self, + bx: &mut Bx, + operand: OperandRef<'tcx, Bx::Value>, + cast: TyAndLayout<'tcx>, + ) -> Option> { + // Check for transmutes that are always UB. + if operand.layout.size != cast.size + || operand.layout.abi.is_uninhabited() + || cast.abi.is_uninhabited() + { + if !operand.layout.abi.is_uninhabited() { + // Since this is known statically and the input could have existed + // without already having hit UB, might as well trap for it. + bx.abort(); + } + + // Because this transmute is UB, return something easy to generate, + // since it's fine that later uses of the value are probably UB. + return Some(OperandValue::poison(bx, cast)); + } + + let operand_kind = self.value_kind(operand.layout); + let cast_kind = self.value_kind(cast); + + match operand.val { + OperandValue::Ref(ptr, meta, align) => { + debug_assert_eq!(meta, None); + debug_assert!(matches!(operand_kind, OperandValueKind::Ref)); + let cast_bty = bx.backend_type(cast); + let cast_ptr = bx.pointercast(ptr, bx.type_ptr_to(cast_bty)); + let fake_place = PlaceRef::new_sized_aligned(cast_ptr, cast, align); + Some(bx.load_operand(fake_place).val) + } + OperandValue::Immediate(imm) => { + let OperandValueKind::Immediate(in_scalar) = operand_kind else { + bug!("Found {operand_kind:?} for operand {operand:?}"); + }; + if let OperandValueKind::Immediate(out_scalar) = cast_kind { + match (in_scalar, out_scalar) { + (ScalarOrZst::Zst, ScalarOrZst::Zst) => { + Some(OperandRef::new_zst(bx, cast).val) + } + (ScalarOrZst::Scalar(in_scalar), ScalarOrZst::Scalar(out_scalar)) + if in_scalar.size(self.cx) == out_scalar.size(self.cx) => + { + let cast_bty = bx.backend_type(cast); + Some(OperandValue::Immediate( + self.transmute_immediate(bx, imm, in_scalar, out_scalar, cast_bty), + )) + } + _ => None, + } + } else { + None + } + } + OperandValue::Pair(imm_a, imm_b) => { + let OperandValueKind::Pair(in_a, in_b) = operand_kind else { + bug!("Found {operand_kind:?} for operand {operand:?}"); + }; + if let OperandValueKind::Pair(out_a, out_b) = cast_kind + && in_a.size(self.cx) == out_a.size(self.cx) + && in_b.size(self.cx) == out_b.size(self.cx) + { + let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false); + let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false); + Some(OperandValue::Pair( + self.transmute_immediate(bx, imm_a, in_a, out_a, out_a_ibty), + self.transmute_immediate(bx, imm_b, in_b, out_b, out_b_ibty), + )) + } else { + None + } + } + } + } + + /// Transmutes one of the immediates from an [`OperandValue::Immediate`] + /// or an [`OperandValue::Pair`] to an immediate of the target type. + /// + /// `to_backend_ty` must be the *non*-immediate backend type (so it will be + /// `i8`, not `i1`, for `bool`-like types.) + fn transmute_immediate( + &self, + bx: &mut Bx, + mut imm: Bx::Value, + from_scalar: abi::Scalar, + to_scalar: abi::Scalar, + to_backend_ty: Bx::Type, + ) -> Bx::Value { + debug_assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx)); + + use abi::Primitive::*; + imm = bx.from_immediate(imm); + imm = match (from_scalar.primitive(), to_scalar.primitive()) { + (Int(..) | F32 | F64, Int(..) | F32 | F64) => bx.bitcast(imm, to_backend_ty), + (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), + (Int(..), Pointer(..)) => bx.inttoptr(imm, to_backend_ty), + (Pointer(..), Int(..)) => bx.ptrtoint(imm, to_backend_ty), + (F32 | F64, Pointer(..)) => { + let int_imm = bx.bitcast(imm, bx.cx().type_isize()); + bx.inttoptr(int_imm, to_backend_ty) + } + (Pointer(..), F32 | F64) => { + let int_imm = bx.ptrtoint(imm, bx.cx().type_isize()); + bx.bitcast(int_imm, to_backend_ty) + } + }; + imm = bx.to_immediate_scalar(imm, to_scalar); + imm + } + pub fn codegen_rvalue_unsized( &mut self, bx: &mut Bx, @@ -396,7 +500,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Immediate(newval) } mir::CastKind::Transmute => { - bug!("Transmute operand {:?} in `codegen_rvalue_operand`", operand); + self.codegen_transmute_operand(bx, operand, cast).unwrap_or_else(|| { + bug!("Unsupported transmute-as-operand of {operand:?} to {cast:?}"); + }) } }; OperandRef { val, layout: cast } @@ -739,10 +845,31 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool { match *rvalue { - mir::Rvalue::Cast(mir::CastKind::Transmute, ..) => - // FIXME: Now that transmute is an Rvalue, it would be nice if - // it could create `Immediate`s for scalars, where possible. - false, + mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, cast_ty) => { + let operand_ty = operand.ty(self.mir, self.cx.tcx()); + let cast_layout = self.cx.layout_of(self.monomorphize(cast_ty)); + let operand_layout = self.cx.layout_of(self.monomorphize(operand_ty)); + + match (self.value_kind(operand_layout), self.value_kind(cast_layout)) { + // Can always load from a pointer as needed + (OperandValueKind::Ref, _) => true, + + // Need to generate an `alloc` to get a pointer from an immediate + (OperandValueKind::Immediate(..) | OperandValueKind::Pair(..), OperandValueKind::Ref) => false, + + // When we have scalar immediates, we can only convert things + // where the sizes match, to avoid endianness questions. + (OperandValueKind::Immediate(a), OperandValueKind::Immediate(b)) => + a.size(self.cx) == b.size(self.cx), + (OperandValueKind::Pair(a0, a1), OperandValueKind::Pair(b0, b1)) => + a0.size(self.cx) == b0.size(self.cx) && a1.size(self.cx) == b1.size(self.cx), + + // Send mixings between scalars and pairs through the memory route + // FIXME: Maybe this could use insertvalue/extractvalue instead? + (OperandValueKind::Immediate(..), OperandValueKind::Pair(..)) | + (OperandValueKind::Pair(..), OperandValueKind::Immediate(..)) => false, + } + } mir::Rvalue::Ref(..) | mir::Rvalue::CopyForDeref(..) | mir::Rvalue::AddressOf(..) | @@ -767,4 +894,52 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // (*) this is only true if the type is suitable } + + /// Gets which variant of [`OperandValue`] is expected for a particular type. + fn value_kind(&self, layout: TyAndLayout<'tcx>) -> OperandValueKind { + if self.cx.is_backend_immediate(layout) { + debug_assert!(!self.cx.is_backend_scalar_pair(layout)); + OperandValueKind::Immediate(match layout.abi { + abi::Abi::Scalar(s) => ScalarOrZst::Scalar(s), + abi::Abi::Vector { element, .. } => ScalarOrZst::Scalar(element), + _ if layout.is_zst() => ScalarOrZst::Zst, + x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"), + }) + } else if self.cx.is_backend_scalar_pair(layout) { + let abi::Abi::ScalarPair(s1, s2) = layout.abi else { + span_bug!( + self.mir.span, + "Couldn't translate {:?} as backend scalar pair", + layout.abi, + ); + }; + OperandValueKind::Pair(s1, s2) + } else { + OperandValueKind::Ref + } + } +} + +/// The variants of this match [`OperandValue`], giving details about the +/// backend values that will be held in that other type. +#[derive(Debug, Copy, Clone)] +enum OperandValueKind { + Ref, + Immediate(ScalarOrZst), + Pair(abi::Scalar, abi::Scalar), +} + +#[derive(Debug, Copy, Clone)] +enum ScalarOrZst { + Zst, + Scalar(abi::Scalar), +} + +impl ScalarOrZst { + pub fn size(self, cx: &impl abi::HasDataLayout) -> abi::Size { + match self { + ScalarOrZst::Zst => abi::Size::ZERO, + ScalarOrZst::Scalar(s) => s.size(cx), + } + } } diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 109161ccc836..32905b079d36 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -100,11 +100,22 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { impl<'tcx, T> DerivedTypeMethods<'tcx> for T where Self: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {} pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { + /// The backend type used for a rust type when it's in memory, + /// such as when it's stack-allocated or when it's being loaded or stored. fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type; fn cast_backend_type(&self, ty: &CastTarget) -> Self::Type; fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type; fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type; fn reg_backend_type(&self, ty: &Reg) -> Self::Type; + /// The backend type used for a rust type when it's in an SSA register. + /// + /// For nearly all types this is the same as the [`Self::backend_type`], however + /// `bool` (and other `0`-or-`1` values) are kept as [`BaseTypeMethods::type_i1`] + /// in registers but as [`BaseTypeMethods::type_i8`] in memory. + /// + /// Converting values between the two different backend types is done using + /// [`from_immediate`](super::BuilderMethods::from_immediate) and + /// [`to_immediate_scalar`](super::BuilderMethods::to_immediate_scalar). fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type; fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool; fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool; diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index c87ea18af4f4..a5dfd1072f0a 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -23,7 +23,7 @@ use rustc_target::spec::abi::Abi as CallAbi; use crate::interpret::{ self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx, - InterpResult, OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind, + InterpResult, OpTy, PlaceTy, Pointer, Scalar, }; use super::error::*; @@ -271,7 +271,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { /* with_caller_location = */ false, dest, ret, - StackPopUnwind::NotAllowed, + mir::UnwindAction::Unreachable, )?; Ok(ControlFlow::Break(())) } else { @@ -401,7 +401,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, args: &[OpTy<'tcx>], dest: &PlaceTy<'tcx>, ret: Option, - _unwind: StackPopUnwind, // unwinding is not supported in consts + _unwind: mir::UnwindAction, // unwinding is not supported in consts ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { debug!("find_mir_or_eval_fn: {:?}", instance); @@ -450,7 +450,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, args: &[OpTy<'tcx>], dest: &PlaceTy<'tcx, Self::Provenance>, target: Option, - _unwind: StackPopUnwind, + _unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { // Shared intrinsics. if ecx.emulate_intrinsic(instance, args, dest, target)? { @@ -526,7 +526,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, fn assert_panic( ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: &AssertMessage<'tcx>, - _unwind: Option, + _unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { use rustc_middle::mir::AssertKind::*; // Convert `AssertKind` to `AssertKind`. diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 0918ffcd9821..3e58a58aef7d 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -139,17 +139,6 @@ pub struct FrameInfo<'tcx> { pub lint_root: Option, } -/// Unwind information. -#[derive(Clone, Copy, Eq, PartialEq, Debug)] -pub enum StackPopUnwind { - /// The cleanup block. - Cleanup(mir::BasicBlock), - /// No cleanup needs to be done. - Skip, - /// Unwinding is not allowed (UB). - NotAllowed, -} - #[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these pub enum StackPopCleanup { /// Jump to the next block in the caller, or cause UB if None (that's a function @@ -157,7 +146,7 @@ pub enum StackPopCleanup { /// we can validate it at that layout. /// `ret` stores the block we jump to on a normal return, while `unwind` /// stores the block used for cleanup during unwinding. - Goto { ret: Option, unwind: StackPopUnwind }, + Goto { ret: Option, unwind: mir::UnwindAction }, /// The root frame of the stack: nowhere else to jump to. /// `cleanup` says whether locals are deallocated. Static computation /// wants them leaked to intern what they need (and just throw away @@ -735,18 +724,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// *Unwind* to the given `target` basic block. /// Do *not* use for returning! Use `return_to_block` instead. /// - /// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup + /// If `target` is `UnwindAction::Continue`, that indicates the function does not need cleanup /// during unwinding, and we will just keep propagating that upwards. /// - /// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow + /// If `target` is `UnwindAction::Unreachable`, that indicates the function does not allow /// unwinding, and doing so is UB. - pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> { + pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tcx> { self.frame_mut().loc = match target { - StackPopUnwind::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }), - StackPopUnwind::Skip => Right(self.frame_mut().body.span), - StackPopUnwind::NotAllowed => { + mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }), + mir::UnwindAction::Continue => Right(self.frame_mut().body.span), + mir::UnwindAction::Unreachable => { throw_ub_format!("unwinding past a stack frame that does not allow unwinding") } + mir::UnwindAction::Terminate => { + self.frame_mut().loc = Right(self.frame_mut().body.span); + M::abort(self, "panic in a function that cannot unwind".to_owned())?; + } }; Ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index aca68dc454be..0291cca7378a 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -18,7 +18,7 @@ use crate::const_eval::CheckAlignment; use super::{ AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, - InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind, + InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, }; /// Data returned by Machine::stack_pop, @@ -185,7 +185,7 @@ pub trait Machine<'mir, 'tcx>: Sized { args: &[OpTy<'tcx, Self::Provenance>], destination: &PlaceTy<'tcx, Self::Provenance>, target: Option, - unwind: StackPopUnwind, + unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>; /// Execute `fn_val`. It is the hook's responsibility to advance the instruction @@ -197,7 +197,7 @@ pub trait Machine<'mir, 'tcx>: Sized { args: &[OpTy<'tcx, Self::Provenance>], destination: &PlaceTy<'tcx, Self::Provenance>, target: Option, - unwind: StackPopUnwind, + unwind: mir::UnwindAction, ) -> InterpResult<'tcx>; /// Directly process an intrinsic without pushing a stack frame. It is the hook's @@ -208,17 +208,17 @@ pub trait Machine<'mir, 'tcx>: Sized { args: &[OpTy<'tcx, Self::Provenance>], destination: &PlaceTy<'tcx, Self::Provenance>, target: Option, - unwind: StackPopUnwind, + unwind: mir::UnwindAction, ) -> InterpResult<'tcx>; /// Called to evaluate `Assert` MIR terminators that trigger a panic. fn assert_panic( ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: &mir::AssertMessage<'tcx>, - unwind: Option, + unwind: mir::UnwindAction, ) -> InterpResult<'tcx>; - /// Called to evaluate `Abort` MIR terminator. + /// Called to abort evaluation. fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> { throw_unsup_format!("aborting execution is not supported") } @@ -487,7 +487,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { _args: &[OpTy<$tcx>], _destination: &PlaceTy<$tcx, Self::Provenance>, _target: Option, - _unwind: StackPopUnwind, + _unwind: mir::UnwindAction, ) -> InterpResult<$tcx> { match fn_val {} } diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 86de4e4e32c2..898d62361ab2 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -20,9 +20,7 @@ mod visitor; pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here -pub use self::eval_context::{ - Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind, -}; +pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup}; pub use self::intern::{intern_const_alloc_recursive, InternKind}; pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump}; pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 8d5192bca67e..5310ef0bb3ed 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -612,14 +612,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { span: Option, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - // FIXME(const_prop): normalization needed b/c const prop lint in - // `mir_drops_elaborated_and_const_checked`, which happens before - // optimized MIR. Only after optimizing the MIR can we guarantee - // that the `RevealAll` pass has happened and that the body's consts - // are normalized, so any call to resolve before that needs to be - // manually normalized. - let val = self.tcx.normalize_erasing_regions(self.param_env, *val); - match val { + match *val { mir::ConstantKind::Ty(ct) => { let ty = ct.ty(); let valtree = self.eval_ty_constant(ct, span)?; diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 2d9fee9852cc..a07702f7d9bb 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -13,7 +13,7 @@ use rustc_target::spec::abi::Abi; use super::{ FnVal, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemoryKind, OpTy, Operand, - PlaceTy, Scalar, StackPopCleanup, StackPopUnwind, + PlaceTy, Scalar, StackPopCleanup, }; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { @@ -60,7 +60,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ref args, destination, target, - ref cleanup, + unwind, from_hir_call: _, fn_span: _, } => { @@ -106,11 +106,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { with_caller_location, &destination, target, - match (cleanup, fn_abi.can_unwind) { - (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup), - (None, true) => StackPopUnwind::Skip, - (_, false) => StackPopUnwind::NotAllowed, - }, + if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable }, )?; // Sanity-check that `eval_fn_call` either pushed a new frame or // did a jump to another block. @@ -137,19 +133,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.drop_in_place(&place, instance, target, unwind)?; } - Assert { ref cond, expected, ref msg, target, cleanup } => { + Assert { ref cond, expected, ref msg, target, unwind } => { let ignored = M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check(); let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?; if ignored || expected == cond_val { self.go_to_block(target); } else { - M::assert_panic(self, msg, cleanup)?; + M::assert_panic(self, msg, unwind)?; } } - Abort => { - M::abort(self, "the program aborted execution".to_owned())?; + Terminate => { + // FIXME: maybe should call `panic_no_unwind` lang item instead. + M::abort(self, "panic in a function that cannot unwind".to_owned())?; } // When we encounter Resume, we've finished unwinding @@ -351,7 +348,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { with_caller_location: bool, destination: &PlaceTy<'tcx, M::Provenance>, target: Option, - mut unwind: StackPopUnwind, + mut unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { trace!("eval_fn_call: {:#?}", fn_val); @@ -410,9 +407,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - if !matches!(unwind, StackPopUnwind::NotAllowed) && !callee_fn_abi.can_unwind { - // The callee cannot unwind. - unwind = StackPopUnwind::NotAllowed; + if !callee_fn_abi.can_unwind { + // The callee cannot unwind, so force the `Unreachable` unwind handling. + unwind = mir::UnwindAction::Unreachable; } self.push_stack_frame( @@ -676,7 +673,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { place: &PlaceTy<'tcx, M::Provenance>, instance: ty::Instance<'tcx>, target: mir::BasicBlock, - unwind: Option, + unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance); // We take the address of the object. This may well be unaligned, which is fine @@ -717,10 +714,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { false, &ret.into(), Some(target), - match unwind { - Some(cleanup) => StackPopUnwind::Cleanup(cleanup), - None => StackPopUnwind::Skip, - }, + unwind, ) } } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 16b83af91ac9..5ab389d04c7e 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -20,7 +20,6 @@ Rust MIR: a lowered representation of Rust. #![feature(try_blocks)] #![feature(yeet_expr)] #![feature(if_let_guard)] -#![feature(is_some_and)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index d6110a050f2d..9dad94790539 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -553,7 +553,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } Rvalue::Cast(CastKind::DynStar, _, _) => { - unimplemented!() + // `dyn*` coercion is implemented for CTFE. } Rvalue::Cast(_, _, _) => {} @@ -1031,9 +1031,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { self.check_op(ops::Generator(hir::GeneratorKind::Gen)) } - TerminatorKind::Abort => { + TerminatorKind::Terminate => { // Cleanup blocks are skipped for const checking (see `visit_basic_block_data`). - span_bug!(self.span, "`Abort` terminator outside of cleanup block") + span_bug!(self.span, "`Terminate` terminator outside of cleanup block") } TerminatorKind::Assert { .. } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs index f01ab4c5d611..1f1640fd80ae 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs @@ -104,7 +104,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> { } } - mir::TerminatorKind::Abort + mir::TerminatorKind::Terminate | mir::TerminatorKind::Call { .. } | mir::TerminatorKind::Assert { .. } | mir::TerminatorKind::FalseEdge { .. } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 6774e5a58376..7919aed097a4 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -807,7 +807,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { kind: TerminatorKind::Call { func, args, - cleanup: None, + unwind: UnwindAction::Continue, destination: Place::from(new_temp), target: Some(new_target), from_hir_call, diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 558253f727bc..0f56fda18f56 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -5,13 +5,12 @@ use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::traits::Reveal; use rustc_middle::mir::interpret::Scalar; -use rustc_middle::mir::visit::NonUseContext::VarDebugInfo; -use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{ traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location, MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator, - TerminatorKind, UnOp, START_BLOCK, + TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents, START_BLOCK, }; use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; use rustc_mir_dataflow::impls::MaybeStorageLive; @@ -233,6 +232,24 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + fn check_unwind_edge(&mut self, location: Location, unwind: UnwindAction) { + let is_cleanup = self.body.basic_blocks[location.block].is_cleanup; + match unwind { + UnwindAction::Cleanup(unwind) => { + if is_cleanup { + self.fail(location, "unwind on cleanup block"); + } + self.check_edge(location, unwind, EdgeKind::Unwind); + } + UnwindAction::Continue => { + if is_cleanup { + self.fail(location, "unwind on cleanup block"); + } + } + UnwindAction::Unreachable | UnwindAction::Terminate => (), + } + } + /// Check if src can be assigned into dest. /// This is not precise, it will accept some incorrect assignments. fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool { @@ -419,13 +436,49 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.super_projection_elem(local, proj_base, elem, context, location); } + fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) { + let check_place = |place: Place<'_>| { + if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) { + self.fail( + START_BLOCK.start_location(), + format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name), + ); + } + }; + match debuginfo.value { + VarDebugInfoContents::Const(_) => {} + VarDebugInfoContents::Place(place) => check_place(place), + VarDebugInfoContents::Composite { ty, ref fragments } => { + for f in fragments { + check_place(f.contents); + if ty.is_union() || ty.is_enum() { + self.fail( + START_BLOCK.start_location(), + format!("invalid type {:?} for composite debuginfo", ty), + ); + } + if f.projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) { + self.fail( + START_BLOCK.start_location(), + format!( + "illegal projection {:?} in debuginfo for {:?}", + f.projection, debuginfo.name + ), + ); + } + } + } + } + self.super_var_debug_info(debuginfo); + } + fn visit_place(&mut self, place: &Place<'tcx>, cntxt: PlaceContext, location: Location) { // Set off any `bug!`s in the type computation code let _ = place.ty(&self.body.local_decls, self.tcx); if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) && place.projection.len() > 1 - && cntxt != PlaceContext::NonUse(VarDebugInfo) + && cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo) && place.projection[1..].contains(&ProjectionElem::Deref) { self.fail(location, format!("{:?}, has deref at the wrong place", place)); @@ -867,11 +920,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } TerminatorKind::Drop { target, unwind, .. } => { self.check_edge(location, *target, EdgeKind::Normal); - if let Some(unwind) = unwind { - self.check_edge(location, *unwind, EdgeKind::Unwind); - } + self.check_unwind_edge(location, *unwind); } - TerminatorKind::Call { func, args, destination, target, cleanup, .. } => { + TerminatorKind::Call { func, args, destination, target, unwind, .. } => { let func_ty = func.ty(&self.body.local_decls, self.tcx); match func_ty.kind() { ty::FnPtr(..) | ty::FnDef(..) => {} @@ -883,9 +934,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if let Some(target) = target { self.check_edge(location, *target, EdgeKind::Normal); } - if let Some(cleanup) = cleanup { - self.check_edge(location, *cleanup, EdgeKind::Unwind); - } + self.check_unwind_edge(location, *unwind); // The call destination place and Operand::Move place used as an argument might be // passed by a reference to the callee. Consequently they must be non-overlapping. @@ -911,7 +960,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } - TerminatorKind::Assert { cond, target, cleanup, .. } => { + TerminatorKind::Assert { cond, target, unwind, .. } => { let cond_ty = cond.ty(&self.body.local_decls, self.tcx); if cond_ty != self.tcx.types.bool { self.fail( @@ -923,9 +972,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } self.check_edge(location, *target, EdgeKind::Normal); - if let Some(cleanup) = cleanup { - self.check_edge(location, *cleanup, EdgeKind::Unwind); - } + self.check_unwind_edge(location, *unwind); } TerminatorKind::Yield { resume, drop, .. } => { if self.body.generator.is_none() { @@ -957,17 +1004,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } self.check_edge(location, *real_target, EdgeKind::Normal); - if let Some(unwind) = unwind { - self.check_edge(location, *unwind, EdgeKind::Unwind); - } + self.check_unwind_edge(location, *unwind); } - TerminatorKind::InlineAsm { destination, cleanup, .. } => { + TerminatorKind::InlineAsm { destination, unwind, .. } => { if let Some(destination) = destination { self.check_edge(location, *destination, EdgeKind::Normal); } - if let Some(cleanup) = cleanup { - self.check_edge(location, *cleanup, EdgeKind::Unwind); - } + self.check_unwind_edge(location, *unwind); } TerminatorKind::GeneratorDrop => { if self.body.generator.is_none() { @@ -980,10 +1023,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } - TerminatorKind::Resume | TerminatorKind::Abort => { + TerminatorKind::Resume | TerminatorKind::Terminate => { let bb = location.block; if !self.body.basic_blocks[bb].is_cleanup { - self.fail(location, "Cannot `Resume` or `Abort` from non-cleanup basic block") + self.fail( + location, + "Cannot `Resume` or `Terminate` from non-cleanup basic block", + ) } } TerminatorKind::Return => { diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 0b2b03da2080..24b6b5cfb1f7 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -32,7 +32,7 @@ stacker = "0.1.15" tempfile = "3.2" thin-vec = "0.2.12" tracing = "0.1" -elsa = "1.8" +elsa = "=1.7.1" [dependencies.parking_lot] version = "0.11" diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs index 1aa7ac024d94..9ff401c3c7aa 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs +++ b/compiler/rustc_data_structures/src/graph/implementation/mod.rs @@ -206,17 +206,11 @@ impl Graph { AdjacentEdges { graph: self, direction, next: first_edge } } - pub fn successor_nodes<'a>( - &'a self, - source: NodeIndex, - ) -> impl Iterator + 'a { + pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator + '_ { self.outgoing_edges(source).targets() } - pub fn predecessor_nodes<'a>( - &'a self, - target: NodeIndex, - ) -> impl Iterator + 'a { + pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator + '_ { self.incoming_edges(target).sources() } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 9b52638e6124..e373bd18402a 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -1,5 +1,5 @@ //! Various data structures used by the Rust compiler. The intention -//! is that code in here should be not be *specific* to rustc, so that +//! is that code in here should not be *specific* to rustc, so that //! it can be easily unit tested and so forth. //! //! # Note @@ -27,6 +27,8 @@ #![feature(thread_id_value)] #![feature(vec_into_raw_parts)] #![feature(get_mut_unchecked)] +#![feature(lint_reasons)] +#![feature(unwrap_infallible)] #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] @@ -59,7 +61,6 @@ pub mod intern; pub mod jobserver; pub mod macros; pub mod obligation_forest; -pub mod owning_ref; pub mod sip128; pub mod small_c_str; pub mod small_str; @@ -82,6 +83,7 @@ pub mod vec_linked_list; pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; +pub mod owned_slice; pub mod sso; pub mod steal; pub mod tagged_ptr; diff --git a/compiler/rustc_data_structures/src/memmap.rs b/compiler/rustc_data_structures/src/memmap.rs index 3d44e17f31d1..ef37a606f313 100644 --- a/compiler/rustc_data_structures/src/memmap.rs +++ b/compiler/rustc_data_structures/src/memmap.rs @@ -2,9 +2,7 @@ use std::fs::File; use std::io; use std::ops::{Deref, DerefMut}; -use crate::owning_ref::StableAddress; - -/// A trivial wrapper for [`memmap2::Mmap`] that implements [`StableAddress`]. +/// A trivial wrapper for [`memmap2::Mmap`] (or `Vec` on WASM). #[cfg(not(target_arch = "wasm32"))] pub struct Mmap(memmap2::Mmap); @@ -42,16 +40,10 @@ impl Deref for Mmap { impl AsRef<[u8]> for Mmap { fn as_ref(&self) -> &[u8] { - &*self.0 + &self.0 } } -// SAFETY: On architectures other than WASM, mmap is used as backing storage. The address of this -// memory map is stable. On WASM, `Vec` is used as backing storage. The `Mmap` type doesn't -// export any function that can cause the `Vec` to be re-allocated. As such the address of the -// bytes inside this `Vec` is stable. -unsafe impl StableAddress for Mmap {} - #[cfg(not(target_arch = "wasm32"))] pub struct MmapMut(memmap2::MmapMut); diff --git a/compiler/rustc_data_structures/src/owned_slice.rs b/compiler/rustc_data_structures/src/owned_slice.rs new file mode 100644 index 000000000000..048401f66c27 --- /dev/null +++ b/compiler/rustc_data_structures/src/owned_slice.rs @@ -0,0 +1,118 @@ +use std::{borrow::Borrow, ops::Deref}; + +// Use our fake Send/Sync traits when on not parallel compiler, +// so that `OwnedSlice` only implements/requires Send/Sync +// for parallel compiler builds. +use crate::sync::{Send, Sync}; + +/// An owned slice. +/// +/// This is similar to `Box<[u8]>` but allows slicing and using anything as the +/// backing buffer. +/// +/// See [`slice_owned`] for `OwnedSlice` construction and examples. +/// +/// --------------------------------------------------------------------------- +/// +/// This is essentially a replacement for `owning_ref` which is a lot simpler +/// and even sound! 🌸 +pub struct OwnedSlice { + /// This is conceptually a `&'self.owner [u8]`. + bytes: *const [u8], + + // +---------------------------------------+ + // | We expect `dead_code` lint here, | + // | because we don't want to accidentally | + // | touch the owner — otherwise the owner | + // | could invalidate out `bytes` pointer | + // | | + // | so be quiet | + // +----+ +-------------------------------+ + // \/ + // ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770) + #[expect(dead_code)] + owner: Box, +} + +/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function. +/// +/// ## Examples +/// +/// ```rust +/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; +/// let vec = vec![1, 2, 3, 4]; +/// +/// // Identical to slicing via `&v[1..3]` but produces an owned slice +/// let slice: OwnedSlice = slice_owned(vec, |v| &v[1..3]); +/// assert_eq!(&*slice, [2, 3]); +/// ``` +/// +/// ```rust +/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; +/// # use std::ops::Deref; +/// let vec = vec![1, 2, 3, 4]; +/// +/// // Identical to slicing via `&v[..]` but produces an owned slice +/// let slice: OwnedSlice = slice_owned(vec, Deref::deref); +/// assert_eq!(&*slice, [1, 2, 3, 4]); +/// ``` +pub fn slice_owned(owner: O, slicer: F) -> OwnedSlice +where + O: Send + Sync + 'static, + F: FnOnce(&O) -> &[u8], +{ + try_slice_owned(owner, |x| Ok::<_, !>(slicer(x))).into_ok() +} + +/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function that can fail. +/// +/// See [`slice_owned`] for the infallible version. +pub fn try_slice_owned(owner: O, slicer: F) -> Result +where + O: Send + Sync + 'static, + F: FnOnce(&O) -> Result<&[u8], E>, +{ + // We box the owner of the bytes, so it doesn't move. + // + // Since the owner does not move and we don't access it in any way + // before drop, there is nothing that can invalidate the bytes pointer. + // + // Thus, "extending" the lifetime of the reference returned from `F` is fine. + // We pretend that we pass it a reference that lives as long as the returned slice. + // + // N.B. the HRTB on the `slicer` is important — without it the caller could provide + // a short lived slice, unrelated to the owner. + + let owner = Box::new(owner); + let bytes = slicer(&*owner)?; + + Ok(OwnedSlice { bytes, owner }) +} + +impl Deref for OwnedSlice { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + // Safety: + // `self.bytes` is valid per the construction in `slice_owned` + // (which is the only constructor) + unsafe { &*self.bytes } + } +} + +impl Borrow<[u8]> for OwnedSlice { + #[inline] + fn borrow(&self) -> &[u8] { + self + } +} + +// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box)`, which is `Send` +unsafe impl Send for OwnedSlice {} + +// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box)`, which is `Sync` +unsafe impl Sync for OwnedSlice {} + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_data_structures/src/owned_slice/tests.rs b/compiler/rustc_data_structures/src/owned_slice/tests.rs new file mode 100644 index 000000000000..e715fb55362d --- /dev/null +++ b/compiler/rustc_data_structures/src/owned_slice/tests.rs @@ -0,0 +1,74 @@ +use std::{ + ops::Deref, + sync::{ + atomic::{self, AtomicBool}, + Arc, + }, +}; + +use crate::{ + owned_slice::{slice_owned, try_slice_owned, OwnedSlice}, + OnDrop, +}; + +#[test] +fn smoke() { + let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice); + + assert_eq!(&*slice, [1, 2, 3, 4, 5, 6]); +} + +#[test] +fn static_storage() { + let slice = slice_owned(Box::new(String::from("what")), |_| b"bytes boo"); + + assert_eq!(&*slice, b"bytes boo"); +} + +#[test] +fn slice_the_slice() { + let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice); + let slice = slice_owned(slice, |s| &s[1..][..4]); + let slice = slice_owned(slice, |s| s); + let slice = slice_owned(slice, |s| &s[1..]); + + assert_eq!(&*slice, &[1, 2, 3, 4, 5, 6][1..][..4][1..]); +} + +#[test] +fn try_and_fail() { + let res = try_slice_owned(vec![0], |v| v.get(12..).ok_or(())); + + assert!(res.is_err()); +} + +#[test] +fn boxed() { + // It's important that we don't cause UB because of `Box`'es uniqueness + + let boxed: Box<[u8]> = vec![1, 1, 2, 3, 5, 8, 13, 21].into_boxed_slice(); + let slice = slice_owned(boxed, Deref::deref); + + assert_eq!(&*slice, [1, 1, 2, 3, 5, 8, 13, 21]); +} + +#[test] +fn drop_drops() { + let flag = Arc::new(AtomicBool::new(false)); + let flag_prime = Arc::clone(&flag); + let d = OnDrop(move || flag_prime.store(true, atomic::Ordering::Relaxed)); + + let slice = slice_owned(d, |_| &[]); + + assert_eq!(flag.load(atomic::Ordering::Relaxed), false); + + drop(slice); + + assert_eq!(flag.load(atomic::Ordering::Relaxed), true); +} + +#[test] +fn send_sync() { + crate::sync::assert_send::(); + crate::sync::assert_sync::(); +} diff --git a/compiler/rustc_data_structures/src/owning_ref/LICENSE b/compiler/rustc_data_structures/src/owning_ref/LICENSE deleted file mode 100644 index dff72d1e4325..000000000000 --- a/compiler/rustc_data_structures/src/owning_ref/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Marvin Löbel - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/compiler/rustc_data_structures/src/owning_ref/mod.rs b/compiler/rustc_data_structures/src/owning_ref/mod.rs deleted file mode 100644 index d1d92b905b82..000000000000 --- a/compiler/rustc_data_structures/src/owning_ref/mod.rs +++ /dev/null @@ -1,1211 +0,0 @@ -#![warn(missing_docs)] - -/*! -# An owning reference. - -This crate provides the _owning reference_ types `OwningRef` and `OwningRefMut` -that enables it to bundle a reference together with the owner of the data it points to. -This allows moving and dropping of an `OwningRef` without needing to recreate the reference. - -This can sometimes be useful because Rust borrowing rules normally prevent -moving a type that has been moved from. For example, this kind of code gets rejected: - -```compile_fail,E0515 -fn return_owned_and_referenced<'a>() -> (Vec, &'a [u8]) { - let v = vec![1, 2, 3, 4]; - let s = &v[1..3]; - (v, s) -} -``` - -Even though, from a memory-layout point of view, this can be entirely safe -if the new location of the vector still lives longer than the lifetime `'a` -of the reference because the backing allocation of the vector does not change. - -This library enables this safe usage by keeping the owner and the reference -bundled together in a wrapper type that ensure that lifetime constraint: - -``` -# use rustc_data_structures::owning_ref::OwningRef; -# fn main() { -fn return_owned_and_referenced() -> OwningRef, [u8]> { - let v = vec![1, 2, 3, 4]; - let or = OwningRef::new(v); - let or = or.map(|v| &v[1..3]); - or -} -# } -``` - -It works by requiring owner types to dereference to stable memory locations -and preventing mutable access to root containers, which in practice requires heap allocation -as provided by `Box`, `Rc`, etc. - -Also provided are typedefs for common owner type combinations, -which allow for less verbose type signatures. -For example, `BoxRef` instead of `OwningRef, T>`. - -The crate also provides the more advanced `OwningHandle` type, -which allows more freedom in bundling a dependent handle object -along with the data it depends on, at the cost of some unsafe needed in the API. -See the documentation around `OwningHandle` for more details. - -# Examples - -## Basics - -``` -use rustc_data_structures::owning_ref::BoxRef; - -fn main() { - // Create an array owned by a Box. - let arr = Box::new([1, 2, 3, 4]) as Box<[i32]>; - - // Transfer into a BoxRef. - let arr: BoxRef<[i32]> = BoxRef::new(arr); - assert_eq!(&*arr, &[1, 2, 3, 4]); - - // We can slice the array without losing ownership or changing type. - let arr: BoxRef<[i32]> = arr.map(|arr| &arr[1..3]); - assert_eq!(&*arr, &[2, 3]); - - // Also works for Arc, Rc, String and Vec! -} -``` - -## Caching a reference to a struct field - -``` -use rustc_data_structures::owning_ref::BoxRef; - -fn main() { - struct Foo { - tag: u32, - x: u16, - y: u16, - z: u16, - } - let foo = Foo { tag: 1, x: 100, y: 200, z: 300 }; - - let or = BoxRef::new(Box::new(foo)).map(|foo| { - match foo.tag { - 0 => &foo.x, - 1 => &foo.y, - 2 => &foo.z, - _ => panic!(), - } - }); - - assert_eq!(*or, 200); -} -``` - -## Caching a reference to an entry in a vector - -``` -use rustc_data_structures::owning_ref::VecRef; - -fn main() { - let v = VecRef::new(vec![1, 2, 3, 4, 5]).map(|v| &v[3]); - assert_eq!(*v, 4); -} -``` - -## Caching a subslice of a String - -``` -use rustc_data_structures::owning_ref::StringRef; - -fn main() { - let s = StringRef::new("hello world".to_owned()) - .map(|s| s.split(' ').nth(1).unwrap()); - - assert_eq!(&*s, "world"); -} -``` - -## Reference counted slices that share ownership of the backing storage - -``` -use rustc_data_structures::owning_ref::RcRef; -use std::rc::Rc; - -fn main() { - let rc: RcRef<[i32]> = RcRef::new(Rc::new([1, 2, 3, 4]) as Rc<[i32]>); - assert_eq!(&*rc, &[1, 2, 3, 4]); - - let rc_a: RcRef<[i32]> = rc.clone().map(|s| &s[0..2]); - let rc_b = rc.clone().map(|s| &s[1..3]); - let rc_c = rc.clone().map(|s| &s[2..4]); - assert_eq!(&*rc_a, &[1, 2]); - assert_eq!(&*rc_b, &[2, 3]); - assert_eq!(&*rc_c, &[3, 4]); - - let rc_c_a = rc_c.clone().map(|s| &s[1]); - assert_eq!(&*rc_c_a, &4); -} -``` - -## Atomic reference counted slices that share ownership of the backing storage - -``` -use rustc_data_structures::owning_ref::ArcRef; -use std::sync::Arc; - -fn main() { - use std::thread; - - fn par_sum(rc: ArcRef<[i32]>) -> i32 { - if rc.len() == 0 { - return 0; - } else if rc.len() == 1 { - return rc[0]; - } - let mid = rc.len() / 2; - let left = rc.clone().map(|s| &s[..mid]); - let right = rc.map(|s| &s[mid..]); - - let left = thread::spawn(move || par_sum(left)); - let right = thread::spawn(move || par_sum(right)); - - left.join().unwrap() + right.join().unwrap() - } - - let rc: Arc<[i32]> = Arc::new([1, 2, 3, 4]); - let rc: ArcRef<[i32]> = rc.into(); - - assert_eq!(par_sum(rc), 10); -} -``` - -## References into RAII locks - -``` -use rustc_data_structures::owning_ref::RefRef; -use std::cell::{RefCell, Ref}; - -fn main() { - let refcell = RefCell::new((1, 2, 3, 4)); - // Also works with Mutex and RwLock - - let refref = { - let refref = RefRef::new(refcell.borrow()).map(|x| &x.3); - assert_eq!(*refref, 4); - - // We move the RAII lock and the reference to one of - // the subfields in the data it guards here: - refref - }; - - assert_eq!(*refref, 4); - - drop(refref); - - assert_eq!(*refcell.borrow(), (1, 2, 3, 4)); -} -``` - -## Mutable reference - -When the owned container implements `DerefMut`, it is also possible to make -a _mutable owning reference_. (e.g., with `Box`, `RefMut`, `MutexGuard`) - -``` -use rustc_data_structures::owning_ref::RefMutRefMut; -use std::cell::{RefCell, RefMut}; - -fn main() { - let refcell = RefCell::new((1, 2, 3, 4)); - - let mut refmut_refmut = { - let mut refmut_refmut = RefMutRefMut::new(refcell.borrow_mut()).map_mut(|x| &mut x.3); - assert_eq!(*refmut_refmut, 4); - *refmut_refmut *= 2; - - refmut_refmut - }; - - assert_eq!(*refmut_refmut, 8); - *refmut_refmut *= 2; - - drop(refmut_refmut); - - assert_eq!(*refcell.borrow(), (1, 2, 3, 16)); -} -``` -*/ - -pub use stable_deref_trait::{ - CloneStableDeref as CloneStableAddress, StableDeref as StableAddress, -}; -use std::mem; - -/// An owning reference. -/// -/// This wraps an owner `O` and a reference `&T` pointing -/// at something reachable from `O::Target` while keeping -/// the ability to move `self` around. -/// -/// The owner is usually a pointer that points at some base type. -/// -/// For more details and examples, see the module and method docs. -pub struct OwningRef { - owner: O, - reference: *const T, -} - -/// An mutable owning reference. -/// -/// This wraps an owner `O` and a reference `&mut T` pointing -/// at something reachable from `O::Target` while keeping -/// the ability to move `self` around. -/// -/// The owner is usually a pointer that points at some base type. -/// -/// For more details and examples, see the module and method docs. -pub struct OwningRefMut { - owner: O, - reference: *mut T, -} - -/// Helper trait for an erased concrete type an owner dereferences to. -/// This is used in form of a trait object for keeping -/// something around to (virtually) call the destructor. -pub trait Erased {} -impl Erased for T {} - -/// Helper trait for erasing the concrete type of what an owner dereferences to, -/// for example `Box -> Box`. This would be unneeded with -/// higher kinded types support in the language. -#[allow(unused_lifetimes)] -pub unsafe trait IntoErased<'a> { - /// Owner with the dereference type substituted to `Erased`. - type Erased; - /// Performs the type erasure. - fn into_erased(self) -> Self::Erased; -} - -/// Helper trait for erasing the concrete type of what an owner dereferences to, -/// for example `Box -> Box`. This would be unneeded with -/// higher kinded types support in the language. -#[allow(unused_lifetimes)] -pub unsafe trait IntoErasedSend<'a> { - /// Owner with the dereference type substituted to `Erased + Send`. - type Erased: Send; - /// Performs the type erasure. - fn into_erased_send(self) -> Self::Erased; -} - -/// Helper trait for erasing the concrete type of what an owner dereferences to, -/// for example `Box -> Box`. This would be unneeded with -/// higher kinded types support in the language. -#[allow(unused_lifetimes)] -pub unsafe trait IntoErasedSendSync<'a> { - /// Owner with the dereference type substituted to `Erased + Send + Sync`. - type Erased: Send + Sync; - /// Performs the type erasure. - fn into_erased_send_sync(self) -> Self::Erased; -} - -///////////////////////////////////////////////////////////////////////////// -// OwningRef -///////////////////////////////////////////////////////////////////////////// - -impl OwningRef { - /// Creates a new owning reference from an owner - /// initialized to the direct dereference of it. - /// - /// # Example - /// ``` - /// use rustc_data_structures::owning_ref::OwningRef; - /// - /// fn main() { - /// let owning_ref = OwningRef::new(Box::new(42)); - /// assert_eq!(*owning_ref, 42); - /// } - /// ``` - pub fn new(o: O) -> Self - where - O: StableAddress, - O: Deref, - { - OwningRef { reference: &*o, owner: o } - } - - /// Like `new`, but doesn’t require `O` to implement the `StableAddress` trait. - /// Instead, the caller is responsible to make the same promises as implementing the trait. - /// - /// This is useful for cases where coherence rules prevents implementing the trait - /// without adding a dependency to this crate in a third-party library. - pub unsafe fn new_assert_stable_address(o: O) -> Self - where - O: Deref, - { - OwningRef { reference: &*o, owner: o } - } - - /// Converts `self` into a new owning reference that points at something reachable - /// from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// use rustc_data_structures::owning_ref::OwningRef; - /// - /// fn main() { - /// let owning_ref = OwningRef::new(Box::new([1, 2, 3, 4])); - /// - /// // create an owning reference that points at the - /// // third element of the array. - /// let owning_ref = owning_ref.map(|array| &array[2]); - /// assert_eq!(*owning_ref, 3); - /// } - /// ``` - pub fn map(self, f: F) -> OwningRef - where - O: StableAddress, - F: FnOnce(&T) -> &U, - { - OwningRef { reference: f(&self), owner: self.owner } - } - - /// Tries to convert `self` into a new owning reference that points - /// at something reachable from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// use rustc_data_structures::owning_ref::OwningRef; - /// - /// fn main() { - /// let owning_ref = OwningRef::new(Box::new([1, 2, 3, 4])); - /// - /// // create an owning reference that points at the - /// // third element of the array. - /// let owning_ref = owning_ref.try_map(|array| { - /// if array[2] == 3 { Ok(&array[2]) } else { Err(()) } - /// }); - /// assert_eq!(*owning_ref.unwrap(), 3); - /// } - /// ``` - pub fn try_map(self, f: F) -> Result, E> - where - O: StableAddress, - F: FnOnce(&T) -> Result<&U, E>, - { - Ok(OwningRef { reference: f(&self)?, owner: self.owner }) - } - - /// Converts `self` into a new owning reference with a different owner type. - /// - /// The new owner type needs to still contain the original owner in some way - /// so that the reference into it remains valid. This function is marked unsafe - /// because the user needs to manually uphold this guarantee. - pub unsafe fn map_owner(self, f: F) -> OwningRef - where - O: StableAddress, - P: StableAddress, - F: FnOnce(O) -> P, - { - OwningRef { reference: self.reference, owner: f(self.owner) } - } - - /// Converts `self` into a new owning reference where the owner is wrapped - /// in an additional `Box`. - /// - /// This can be used to safely erase the owner of any `OwningRef` - /// to an `OwningRef, T>`. - pub fn map_owner_box(self) -> OwningRef, T> { - OwningRef { reference: self.reference, owner: Box::new(self.owner) } - } - - /// Erases the concrete base type of the owner with a trait object. - /// - /// This allows mixing of owned references with different owner base types. - /// - /// # Example - /// ``` - /// use rustc_data_structures::owning_ref::{OwningRef, Erased}; - /// - /// fn main() { - /// // N.B., using the concrete types here for explicitness. - /// // For less verbose code type aliases like `BoxRef` are provided. - /// - /// let owning_ref_a: OwningRef, [i32; 4]> - /// = OwningRef::new(Box::new([1, 2, 3, 4])); - /// - /// let owning_ref_b: OwningRef>, Vec<(i32, bool)>> - /// = OwningRef::new(Box::new(vec![(0, false), (1, true)])); - /// - /// let owning_ref_a: OwningRef, i32> - /// = owning_ref_a.map(|a| &a[0]); - /// - /// let owning_ref_b: OwningRef>, i32> - /// = owning_ref_b.map(|a| &a[1].0); - /// - /// let owning_refs: [OwningRef, i32>; 2] - /// = [owning_ref_a.erase_owner(), owning_ref_b.erase_owner()]; - /// - /// assert_eq!(*owning_refs[0], 1); - /// assert_eq!(*owning_refs[1], 1); - /// } - /// ``` - pub fn erase_owner<'a>(self) -> OwningRef - where - O: IntoErased<'a>, - { - OwningRef { reference: self.reference, owner: self.owner.into_erased() } - } - - /// Erases the concrete base type of the owner with a trait object which implements `Send`. - /// - /// This allows mixing of owned references with different owner base types. - pub fn erase_send_owner<'a>(self) -> OwningRef - where - O: IntoErasedSend<'a>, - { - OwningRef { reference: self.reference, owner: self.owner.into_erased_send() } - } - - /// Erases the concrete base type of the owner with a trait object - /// which implements `Send` and `Sync`. - /// - /// This allows mixing of owned references with different owner base types. - pub fn erase_send_sync_owner<'a>(self) -> OwningRef - where - O: IntoErasedSendSync<'a>, - { - OwningRef { reference: self.reference, owner: self.owner.into_erased_send_sync() } - } - - // UNIMPLEMENTED: wrap_owner - - // FIXME: Naming convention? - /// A getter for the underlying owner. - pub fn owner(&self) -> &O { - &self.owner - } - - // FIXME: Naming convention? - /// Discards the reference and retrieves the owner. - pub fn into_inner(self) -> O { - self.owner - } -} - -impl OwningRefMut { - /// Creates a new owning reference from an owner - /// initialized to the direct dereference of it. - /// - /// # Example - /// ``` - /// use rustc_data_structures::owning_ref::OwningRefMut; - /// - /// fn main() { - /// let owning_ref_mut = OwningRefMut::new(Box::new(42)); - /// assert_eq!(*owning_ref_mut, 42); - /// } - /// ``` - pub fn new(mut o: O) -> Self - where - O: StableAddress, - O: DerefMut, - { - OwningRefMut { reference: &mut *o, owner: o } - } - - /// Like `new`, but doesn’t require `O` to implement the `StableAddress` trait. - /// Instead, the caller is responsible to make the same promises as implementing the trait. - /// - /// This is useful for cases where coherence rules prevents implementing the trait - /// without adding a dependency to this crate in a third-party library. - pub unsafe fn new_assert_stable_address(mut o: O) -> Self - where - O: DerefMut, - { - OwningRefMut { reference: &mut *o, owner: o } - } - - /// Converts `self` into a new _shared_ owning reference that points at - /// something reachable from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// use rustc_data_structures::owning_ref::OwningRefMut; - /// - /// fn main() { - /// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4])); - /// - /// // create an owning reference that points at the - /// // third element of the array. - /// let owning_ref = owning_ref_mut.map(|array| &array[2]); - /// assert_eq!(*owning_ref, 3); - /// } - /// ``` - pub fn map(mut self, f: F) -> OwningRef - where - O: StableAddress, - F: FnOnce(&mut T) -> &U, - { - OwningRef { reference: f(&mut self), owner: self.owner } - } - - /// Converts `self` into a new _mutable_ owning reference that points at - /// something reachable from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// use rustc_data_structures::owning_ref::OwningRefMut; - /// - /// fn main() { - /// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4])); - /// - /// // create an owning reference that points at the - /// // third element of the array. - /// let owning_ref_mut = owning_ref_mut.map_mut(|array| &mut array[2]); - /// assert_eq!(*owning_ref_mut, 3); - /// } - /// ``` - pub fn map_mut(mut self, f: F) -> OwningRefMut - where - O: StableAddress, - F: FnOnce(&mut T) -> &mut U, - { - OwningRefMut { reference: f(&mut self), owner: self.owner } - } - - /// Tries to convert `self` into a new _shared_ owning reference that points - /// at something reachable from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// use rustc_data_structures::owning_ref::OwningRefMut; - /// - /// fn main() { - /// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4])); - /// - /// // create an owning reference that points at the - /// // third element of the array. - /// let owning_ref = owning_ref_mut.try_map(|array| { - /// if array[2] == 3 { Ok(&array[2]) } else { Err(()) } - /// }); - /// assert_eq!(*owning_ref.unwrap(), 3); - /// } - /// ``` - pub fn try_map(mut self, f: F) -> Result, E> - where - O: StableAddress, - F: FnOnce(&mut T) -> Result<&U, E>, - { - Ok(OwningRef { reference: f(&mut self)?, owner: self.owner }) - } - - /// Tries to convert `self` into a new _mutable_ owning reference that points - /// at something reachable from the previous one. - /// - /// This can be a reference to a field of `U`, something reachable from a field of - /// `U`, or even something unrelated with a `'static` lifetime. - /// - /// # Example - /// ``` - /// use rustc_data_structures::owning_ref::OwningRefMut; - /// - /// fn main() { - /// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4])); - /// - /// // create an owning reference that points at the - /// // third element of the array. - /// let owning_ref_mut = owning_ref_mut.try_map_mut(|array| { - /// if array[2] == 3 { Ok(&mut array[2]) } else { Err(()) } - /// }); - /// assert_eq!(*owning_ref_mut.unwrap(), 3); - /// } - /// ``` - pub fn try_map_mut(mut self, f: F) -> Result, E> - where - O: StableAddress, - F: FnOnce(&mut T) -> Result<&mut U, E>, - { - Ok(OwningRefMut { reference: f(&mut self)?, owner: self.owner }) - } - - /// Converts `self` into a new owning reference with a different owner type. - /// - /// The new owner type needs to still contain the original owner in some way - /// so that the reference into it remains valid. This function is marked unsafe - /// because the user needs to manually uphold this guarantee. - pub unsafe fn map_owner(self, f: F) -> OwningRefMut - where - O: StableAddress, - P: StableAddress, - F: FnOnce(O) -> P, - { - OwningRefMut { reference: self.reference, owner: f(self.owner) } - } - - /// Converts `self` into a new owning reference where the owner is wrapped - /// in an additional `Box`. - /// - /// This can be used to safely erase the owner of any `OwningRefMut` - /// to an `OwningRefMut, T>`. - pub fn map_owner_box(self) -> OwningRefMut, T> { - OwningRefMut { reference: self.reference, owner: Box::new(self.owner) } - } - - /// Erases the concrete base type of the owner with a trait object. - /// - /// This allows mixing of owned references with different owner base types. - /// - /// # Example - /// ``` - /// use rustc_data_structures::owning_ref::{OwningRefMut, Erased}; - /// - /// fn main() { - /// // N.B., using the concrete types here for explicitness. - /// // For less verbose code type aliases like `BoxRef` are provided. - /// - /// let owning_ref_mut_a: OwningRefMut, [i32; 4]> - /// = OwningRefMut::new(Box::new([1, 2, 3, 4])); - /// - /// let owning_ref_mut_b: OwningRefMut>, Vec<(i32, bool)>> - /// = OwningRefMut::new(Box::new(vec![(0, false), (1, true)])); - /// - /// let owning_ref_mut_a: OwningRefMut, i32> - /// = owning_ref_mut_a.map_mut(|a| &mut a[0]); - /// - /// let owning_ref_mut_b: OwningRefMut>, i32> - /// = owning_ref_mut_b.map_mut(|a| &mut a[1].0); - /// - /// let owning_refs_mut: [OwningRefMut, i32>; 2] - /// = [owning_ref_mut_a.erase_owner(), owning_ref_mut_b.erase_owner()]; - /// - /// assert_eq!(*owning_refs_mut[0], 1); - /// assert_eq!(*owning_refs_mut[1], 1); - /// } - /// ``` - pub fn erase_owner<'a>(self) -> OwningRefMut - where - O: IntoErased<'a>, - { - OwningRefMut { reference: self.reference, owner: self.owner.into_erased() } - } - - // UNIMPLEMENTED: wrap_owner - - // FIXME: Naming convention? - /// A getter for the underlying owner. - pub fn owner(&self) -> &O { - &self.owner - } - - // FIXME: Naming convention? - /// Discards the reference and retrieves the owner. - pub fn into_inner(self) -> O { - self.owner - } -} - -///////////////////////////////////////////////////////////////////////////// -// OwningHandle -///////////////////////////////////////////////////////////////////////////// - -use std::ops::{Deref, DerefMut}; - -/// `OwningHandle` is a complement to `OwningRef`. Where `OwningRef` allows -/// consumers to pass around an owned object and a dependent reference, -/// `OwningHandle` contains an owned object and a dependent _object_. -/// -/// `OwningHandle` can encapsulate a `RefMut` along with its associated -/// `RefCell`, or an `RwLockReadGuard` along with its associated `RwLock`. -/// However, the API is completely generic and there are no restrictions on -/// what types of owning and dependent objects may be used. -/// -/// `OwningHandle` is created by passing an owner object (which dereferences -/// to a stable address) along with a callback which receives a pointer to -/// that stable location. The callback may then dereference the pointer and -/// mint a dependent object, with the guarantee that the returned object will -/// not outlive the referent of the pointer. -/// -/// Since the callback needs to dereference a raw pointer, it requires `unsafe` -/// code. To avoid forcing this unsafety on most callers, the `ToHandle` trait is -/// implemented for common data structures. Types that implement `ToHandle` can -/// be wrapped into an `OwningHandle` without passing a callback. -pub struct OwningHandle -where - O: StableAddress, - H: Deref, -{ - handle: H, - _owner: O, -} - -impl Deref for OwningHandle -where - O: StableAddress, - H: Deref, -{ - type Target = H::Target; - fn deref(&self) -> &H::Target { - self.handle.deref() - } -} - -unsafe impl StableAddress for OwningHandle -where - O: StableAddress, - H: StableAddress, -{ -} - -impl DerefMut for OwningHandle -where - O: StableAddress, - H: DerefMut, -{ - fn deref_mut(&mut self) -> &mut H::Target { - self.handle.deref_mut() - } -} - -/// Trait to implement the conversion of owner to handle for common types. -pub trait ToHandle { - /// The type of handle to be encapsulated by the OwningHandle. - type Handle: Deref; - - /// Given an appropriately-long-lived pointer to ourselves, create a - /// handle to be encapsulated by the `OwningHandle`. - unsafe fn to_handle(x: *const Self) -> Self::Handle; -} - -/// Trait to implement the conversion of owner to mutable handle for common types. -pub trait ToHandleMut { - /// The type of handle to be encapsulated by the OwningHandle. - type HandleMut: DerefMut; - - /// Given an appropriately-long-lived pointer to ourselves, create a - /// mutable handle to be encapsulated by the `OwningHandle`. - unsafe fn to_handle_mut(x: *const Self) -> Self::HandleMut; -} - -impl OwningHandle -where - O: StableAddress>, - H: Deref, -{ - /// Creates a new `OwningHandle` for a type that implements `ToHandle`. For types - /// that don't implement `ToHandle`, callers may invoke `new_with_fn`, which accepts - /// a callback to perform the conversion. - pub fn new(o: O) -> Self { - OwningHandle::new_with_fn(o, |x| unsafe { O::Target::to_handle(x) }) - } -} - -impl OwningHandle -where - O: StableAddress>, - H: DerefMut, -{ - /// Creates a new mutable `OwningHandle` for a type that implements `ToHandleMut`. - pub fn new_mut(o: O) -> Self { - OwningHandle::new_with_fn(o, |x| unsafe { O::Target::to_handle_mut(x) }) - } -} - -impl OwningHandle -where - O: StableAddress, - H: Deref, -{ - /// Creates a new OwningHandle. The provided callback will be invoked with - /// a pointer to the object owned by `o`, and the returned value is stored - /// as the object to which this `OwningHandle` will forward `Deref` and - /// `DerefMut`. - pub fn new_with_fn(o: O, f: F) -> Self - where - F: FnOnce(*const O::Target) -> H, - { - let h: H; - { - h = f(o.deref() as *const O::Target); - } - - OwningHandle { handle: h, _owner: o } - } - - /// Creates a new OwningHandle. The provided callback will be invoked with - /// a pointer to the object owned by `o`, and the returned value is stored - /// as the object to which this `OwningHandle` will forward `Deref` and - /// `DerefMut`. - pub fn try_new(o: O, f: F) -> Result - where - F: FnOnce(*const O::Target) -> Result, - { - let h: H; - { - h = f(o.deref() as *const O::Target)?; - } - - Ok(OwningHandle { handle: h, _owner: o }) - } -} - -///////////////////////////////////////////////////////////////////////////// -// std traits -///////////////////////////////////////////////////////////////////////////// - -use std::borrow::Borrow; -use std::cmp::Ordering; -use std::fmt::{self, Debug}; -use std::hash::{Hash, Hasher}; - -impl Deref for OwningRef { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.reference } - } -} - -impl Deref for OwningRefMut { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.reference } - } -} - -impl DerefMut for OwningRefMut { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.reference } - } -} - -unsafe impl StableAddress for OwningRef {} - -impl AsRef for OwningRef { - fn as_ref(&self) -> &T { - self - } -} - -impl AsRef for OwningRefMut { - fn as_ref(&self) -> &T { - self - } -} - -impl AsMut for OwningRefMut { - fn as_mut(&mut self) -> &mut T { - self - } -} - -impl Borrow for OwningRef { - fn borrow(&self) -> &T { - self - } -} - -impl From for OwningRef -where - O: StableAddress, - O: Deref, -{ - fn from(owner: O) -> Self { - OwningRef::new(owner) - } -} - -impl From for OwningRefMut -where - O: StableAddress, - O: DerefMut, -{ - fn from(owner: O) -> Self { - OwningRefMut::new(owner) - } -} - -impl From> for OwningRef -where - O: StableAddress, - O: DerefMut, -{ - fn from(other: OwningRefMut) -> Self { - OwningRef { owner: other.owner, reference: other.reference } - } -} - -// ^ FIXME: Is an Into impl for calling into_inner() possible as well? - -impl Debug for OwningRef -where - O: Debug, - T: Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "OwningRef {{ owner: {:?}, reference: {:?} }}", self.owner(), &**self) - } -} - -impl Debug for OwningRefMut -where - O: Debug, - T: Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "OwningRefMut {{ owner: {:?}, reference: {:?} }}", self.owner(), &**self) - } -} - -impl Clone for OwningRef -where - O: CloneStableAddress, -{ - fn clone(&self) -> Self { - OwningRef { owner: self.owner.clone(), reference: self.reference } - } -} - -unsafe impl CloneStableAddress for OwningRef where O: CloneStableAddress {} - -unsafe impl Send for OwningRef -where - O: Send, - for<'a> &'a T: Send, -{ -} -unsafe impl Sync for OwningRef -where - O: Sync, - for<'a> &'a T: Sync, -{ -} - -unsafe impl Send for OwningRefMut -where - O: Send, - for<'a> &'a mut T: Send, -{ -} -unsafe impl Sync for OwningRefMut -where - O: Sync, - for<'a> &'a mut T: Sync, -{ -} - -impl Debug for dyn Erased { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "",) - } -} - -impl PartialEq for OwningRef -where - T: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.deref().eq(other.deref()) - } -} - -impl Eq for OwningRef where T: Eq {} - -impl PartialOrd for OwningRef -where - T: PartialOrd, -{ - fn partial_cmp(&self, other: &Self) -> Option { - self.deref().partial_cmp(other.deref()) - } -} - -impl Ord for OwningRef -where - T: Ord, -{ - fn cmp(&self, other: &Self) -> Ordering { - self.deref().cmp(other.deref()) - } -} - -impl Hash for OwningRef -where - T: Hash, -{ - fn hash(&self, state: &mut H) { - self.deref().hash(state); - } -} - -impl PartialEq for OwningRefMut -where - T: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.deref().eq(other.deref()) - } -} - -impl Eq for OwningRefMut where T: Eq {} - -impl PartialOrd for OwningRefMut -where - T: PartialOrd, -{ - fn partial_cmp(&self, other: &Self) -> Option { - self.deref().partial_cmp(other.deref()) - } -} - -impl Ord for OwningRefMut -where - T: Ord, -{ - fn cmp(&self, other: &Self) -> Ordering { - self.deref().cmp(other.deref()) - } -} - -impl Hash for OwningRefMut -where - T: Hash, -{ - fn hash(&self, state: &mut H) { - self.deref().hash(state); - } -} - -///////////////////////////////////////////////////////////////////////////// -// std types integration and convenience type defs -///////////////////////////////////////////////////////////////////////////// - -use std::cell::{Ref, RefCell, RefMut}; -use std::rc::Rc; -use std::sync::Arc; -use std::sync::{MutexGuard, RwLockReadGuard, RwLockWriteGuard}; - -impl ToHandle for RefCell { - type Handle = Ref<'static, T>; - unsafe fn to_handle(x: *const Self) -> Self::Handle { - (*x).borrow() - } -} - -impl ToHandleMut for RefCell { - type HandleMut = RefMut<'static, T>; - unsafe fn to_handle_mut(x: *const Self) -> Self::HandleMut { - (*x).borrow_mut() - } -} - -// N.B., implementing ToHandle{,Mut} for Mutex and RwLock requires a decision -// about which handle creation to use (i.e., read() vs try_read()) as well as -// what to do with error results. - -/// Typedef of an owning reference that uses a `Box` as the owner. -pub type BoxRef = OwningRef, U>; -/// Typedef of an owning reference that uses a `Vec` as the owner. -pub type VecRef = OwningRef, U>; -/// Typedef of an owning reference that uses a `String` as the owner. -pub type StringRef = OwningRef; - -/// Typedef of an owning reference that uses an `Rc` as the owner. -pub type RcRef = OwningRef, U>; -/// Typedef of an owning reference that uses an `Arc` as the owner. -pub type ArcRef = OwningRef, U>; - -/// Typedef of an owning reference that uses a `Ref` as the owner. -pub type RefRef<'a, T, U = T> = OwningRef, U>; -/// Typedef of an owning reference that uses a `RefMut` as the owner. -pub type RefMutRef<'a, T, U = T> = OwningRef, U>; -/// Typedef of an owning reference that uses a `MutexGuard` as the owner. -pub type MutexGuardRef<'a, T, U = T> = OwningRef, U>; -/// Typedef of an owning reference that uses an `RwLockReadGuard` as the owner. -pub type RwLockReadGuardRef<'a, T, U = T> = OwningRef, U>; -/// Typedef of an owning reference that uses an `RwLockWriteGuard` as the owner. -pub type RwLockWriteGuardRef<'a, T, U = T> = OwningRef, U>; - -/// Typedef of a mutable owning reference that uses a `Box` as the owner. -pub type BoxRefMut = OwningRefMut, U>; -/// Typedef of a mutable owning reference that uses a `Vec` as the owner. -pub type VecRefMut = OwningRefMut, U>; -/// Typedef of a mutable owning reference that uses a `String` as the owner. -pub type StringRefMut = OwningRefMut; - -/// Typedef of a mutable owning reference that uses a `RefMut` as the owner. -pub type RefMutRefMut<'a, T, U = T> = OwningRefMut, U>; -/// Typedef of a mutable owning reference that uses a `MutexGuard` as the owner. -pub type MutexGuardRefMut<'a, T, U = T> = OwningRefMut, U>; -/// Typedef of a mutable owning reference that uses an `RwLockWriteGuard` as the owner. -pub type RwLockWriteGuardRefMut<'a, T, U = T> = OwningRef, U>; - -unsafe impl<'a, T: 'a> IntoErased<'a> for Box { - type Erased = Box; - fn into_erased(self) -> Self::Erased { - self - } -} -unsafe impl<'a, T: 'a> IntoErased<'a> for Rc { - type Erased = Rc; - fn into_erased(self) -> Self::Erased { - self - } -} -unsafe impl<'a, T: 'a> IntoErased<'a> for Arc { - type Erased = Arc; - fn into_erased(self) -> Self::Erased { - self - } -} - -unsafe impl<'a, T: Send + 'a> IntoErasedSend<'a> for Box { - type Erased = Box; - fn into_erased_send(self) -> Self::Erased { - self - } -} - -unsafe impl<'a, T: Send + 'a> IntoErasedSendSync<'a> for Box { - type Erased = Box; - fn into_erased_send_sync(self) -> Self::Erased { - let result: Box = self; - // This is safe since Erased can always implement Sync - // Only the destructor is available and it takes &mut self - unsafe { mem::transmute(result) } - } -} - -unsafe impl<'a, T: Send + Sync + 'a> IntoErasedSendSync<'a> for Arc { - type Erased = Arc; - fn into_erased_send_sync(self) -> Self::Erased { - self - } -} - -/// Typedef of an owning reference that uses an erased `Box` as the owner. -pub type ErasedBoxRef = OwningRef, U>; -/// Typedef of an owning reference that uses an erased `Rc` as the owner. -pub type ErasedRcRef = OwningRef, U>; -/// Typedef of an owning reference that uses an erased `Arc` as the owner. -pub type ErasedArcRef = OwningRef, U>; - -/// Typedef of a mutable owning reference that uses an erased `Box` as the owner. -pub type ErasedBoxRefMut = OwningRefMut, U>; - -#[cfg(test)] -mod tests; diff --git a/compiler/rustc_data_structures/src/owning_ref/tests.rs b/compiler/rustc_data_structures/src/owning_ref/tests.rs deleted file mode 100644 index a9b187c4ce0a..000000000000 --- a/compiler/rustc_data_structures/src/owning_ref/tests.rs +++ /dev/null @@ -1,711 +0,0 @@ -// FIXME: owning_ref is not sound under stacked borrows. Preferably, get rid of it. -#[cfg(not(miri))] -mod owning_ref { - use super::super::OwningRef; - use super::super::{BoxRef, Erased, ErasedBoxRef, RcRef}; - use std::cmp::Ordering; - use std::collections::hash_map::DefaultHasher; - use std::collections::HashMap; - use std::hash::{Hash, Hasher}; - use std::rc::Rc; - - #[derive(Debug, PartialEq)] - struct Example(u32, String, [u8; 3]); - fn example() -> Example { - Example(42, "hello world".to_string(), [1, 2, 3]) - } - - #[test] - fn new_deref() { - let or: OwningRef, ()> = OwningRef::new(Box::new(())); - assert_eq!(&*or, &()); - } - - #[test] - fn into() { - let or: OwningRef, ()> = Box::new(()).into(); - assert_eq!(&*or, &()); - } - - #[test] - fn map_offset_ref() { - let or: BoxRef = Box::new(example()).into(); - let or: BoxRef<_, u32> = or.map(|x| &x.0); - assert_eq!(&*or, &42); - - let or: BoxRef = Box::new(example()).into(); - let or: BoxRef<_, u8> = or.map(|x| &x.2[1]); - assert_eq!(&*or, &2); - } - - #[test] - fn map_heap_ref() { - let or: BoxRef = Box::new(example()).into(); - let or: BoxRef<_, str> = or.map(|x| &x.1[..5]); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_static_ref() { - let or: BoxRef<()> = Box::new(()).into(); - let or: BoxRef<_, str> = or.map(|_| "hello"); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_chained() { - let or: BoxRef = Box::new(example().1).into(); - let or: BoxRef<_, str> = or.map(|x| &x[1..5]); - let or: BoxRef<_, str> = or.map(|x| &x[..2]); - assert_eq!(&*or, "el"); - } - - #[test] - fn map_chained_inference() { - let or = BoxRef::new(Box::new(example().1)).map(|x| &x[..5]).map(|x| &x[1..3]); - assert_eq!(&*or, "el"); - } - - #[test] - fn owner() { - let or: BoxRef = Box::new(example().1).into(); - let or = or.map(|x| &x[..5]); - assert_eq!(&*or, "hello"); - assert_eq!(&**or.owner(), "hello world"); - } - - #[test] - fn into_inner() { - let or: BoxRef = Box::new(example().1).into(); - let or = or.map(|x| &x[..5]); - assert_eq!(&*or, "hello"); - let s = *or.into_inner(); - assert_eq!(&s, "hello world"); - } - - #[test] - fn fmt_debug() { - let or: BoxRef = Box::new(example().1).into(); - let or = or.map(|x| &x[..5]); - let s = format!("{:?}", or); - assert_eq!(&s, "OwningRef { owner: \"hello world\", reference: \"hello\" }"); - } - - #[test] - fn erased_owner() { - let o1: BoxRef = BoxRef::new(Box::new(example())).map(|x| &x.1[..]); - - let o2: BoxRef = BoxRef::new(Box::new(example().1)).map(|x| &x[..]); - - let os: Vec> = vec![o1.erase_owner(), o2.erase_owner()]; - assert!(os.iter().all(|e| &e[..] == "hello world")); - } - - #[test] - fn raii_locks() { - use super::super::{MutexGuardRef, RwLockReadGuardRef, RwLockWriteGuardRef}; - use super::super::{RefMutRef, RefRef}; - use std::cell::RefCell; - use std::sync::{Mutex, RwLock}; - - { - let a = RefCell::new(1); - let a = { - let a = RefRef::new(a.borrow()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = RefCell::new(1); - let a = { - let a = RefMutRef::new(a.borrow_mut()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = Mutex::new(1); - let a = { - let a = MutexGuardRef::new(a.lock().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = RwLock::new(1); - let a = { - let a = RwLockReadGuardRef::new(a.read().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = RwLock::new(1); - let a = { - let a = RwLockWriteGuardRef::new(a.write().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - } - - #[test] - fn eq() { - let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - assert_eq!(or1.eq(&or2), true); - } - - #[test] - fn cmp() { - let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice()); - assert_eq!(or1.cmp(&or2), Ordering::Less); - } - - #[test] - fn partial_cmp() { - let or1: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice()); - let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater)); - } - - #[test] - fn hash() { - let mut h1 = DefaultHasher::new(); - let mut h2 = DefaultHasher::new(); - - let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); - - or1.hash(&mut h1); - or2.hash(&mut h2); - - assert_eq!(h1.finish(), h2.finish()); - } - - #[test] - fn borrow() { - let mut hash = HashMap::new(); - let key = RcRef::::new(Rc::new("foo-bar".to_string())).map(|s| &s[..]); - - hash.insert(key.clone().map(|s| &s[..3]), 42); - hash.insert(key.clone().map(|s| &s[4..]), 23); - - assert_eq!(hash.get("foo"), Some(&42)); - assert_eq!(hash.get("bar"), Some(&23)); - } - - #[test] - fn total_erase() { - let a: OwningRef, [u8]> = OwningRef::new(vec![]).map(|x| &x[..]); - let b: OwningRef, [u8]> = - OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]); - - let c: OwningRef>, [u8]> = unsafe { a.map_owner(Rc::new) }; - let d: OwningRef>, [u8]> = unsafe { b.map_owner(Rc::new) }; - - let e: OwningRef, [u8]> = c.erase_owner(); - let f: OwningRef, [u8]> = d.erase_owner(); - - let _g = e.clone(); - let _h = f.clone(); - } - - #[test] - fn total_erase_box() { - let a: OwningRef, [u8]> = OwningRef::new(vec![]).map(|x| &x[..]); - let b: OwningRef, [u8]> = - OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]); - - let c: OwningRef>, [u8]> = a.map_owner_box(); - let d: OwningRef>, [u8]> = b.map_owner_box(); - - let _e: OwningRef, [u8]> = c.erase_owner(); - let _f: OwningRef, [u8]> = d.erase_owner(); - } - - #[test] - fn try_map1() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - assert!(OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_ok()); - } - - #[test] - fn try_map2() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - assert!(!OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_err()); - } -} - -mod owning_handle { - use super::super::OwningHandle; - use super::super::RcRef; - use std::cell::RefCell; - use std::rc::Rc; - use std::sync::Arc; - use std::sync::RwLock; - - #[test] - fn owning_handle() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let mut handle = - OwningHandle::new_with_fn(cell_ref, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); - assert_eq!(*handle, 2); - *handle = 3; - assert_eq!(*handle, 3); - } - - #[test] - fn try_owning_handle_ok() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let mut handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| { - Ok(unsafe { x.as_ref() }.unwrap().borrow_mut()) - }) - .unwrap(); - assert_eq!(*handle, 2); - *handle = 3; - assert_eq!(*handle, 3); - } - - #[test] - fn try_owning_handle_err() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| { - if false { - return Ok(unsafe { x.as_ref() }.unwrap().borrow_mut()); - } - Err(()) - }); - assert!(handle.is_err()); - } - - #[test] - fn nested() { - use std::cell::RefCell; - use std::sync::{Arc, RwLock}; - - let result = { - let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString")))); - let curr = RcRef::new(complex); - let curr = - OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); - let mut curr = OwningHandle::new_with_fn(curr, |x| { - unsafe { x.as_ref() }.unwrap().try_write().unwrap() - }); - assert_eq!(*curr, "someString"); - *curr = "someOtherString"; - curr - }; - assert_eq!(*result, "someOtherString"); - } - - #[test] - fn owning_handle_safe() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let handle = OwningHandle::new(cell_ref); - assert_eq!(*handle, 2); - } - - #[test] - fn owning_handle_mut_safe() { - use std::cell::RefCell; - let cell = Rc::new(RefCell::new(2)); - let cell_ref = RcRef::new(cell); - let mut handle = OwningHandle::new_mut(cell_ref); - assert_eq!(*handle, 2); - *handle = 3; - assert_eq!(*handle, 3); - } - - #[test] - fn owning_handle_safe_2() { - let result = { - let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString")))); - let curr = RcRef::new(complex); - let curr = - OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); - let mut curr = OwningHandle::new_with_fn(curr, |x| { - unsafe { x.as_ref() }.unwrap().try_write().unwrap() - }); - assert_eq!(*curr, "someString"); - *curr = "someOtherString"; - curr - }; - assert_eq!(*result, "someOtherString"); - } -} - -// FIXME: owning_ref is not sound under stacked borrows. Preferably, get rid of it. -#[cfg(not(miri))] -mod owning_ref_mut { - use super::super::BoxRef; - use super::super::{BoxRefMut, Erased, ErasedBoxRefMut, OwningRefMut}; - use std::cmp::Ordering; - use std::collections::hash_map::DefaultHasher; - use std::collections::HashMap; - use std::hash::{Hash, Hasher}; - - #[derive(Debug, PartialEq)] - struct Example(u32, String, [u8; 3]); - fn example() -> Example { - Example(42, "hello world".to_string(), [1, 2, 3]) - } - - #[test] - fn new_deref() { - let or: OwningRefMut, ()> = OwningRefMut::new(Box::new(())); - assert_eq!(&*or, &()); - } - - #[test] - fn new_deref_mut() { - let mut or: OwningRefMut, ()> = OwningRefMut::new(Box::new(())); - assert_eq!(&mut *or, &mut ()); - } - - #[test] - fn mutate() { - let mut or: OwningRefMut, usize> = OwningRefMut::new(Box::new(0)); - assert_eq!(&*or, &0); - *or = 1; - assert_eq!(&*or, &1); - } - - #[test] - fn into() { - let or: OwningRefMut, ()> = Box::new(()).into(); - assert_eq!(&*or, &()); - } - - #[test] - fn map_offset_ref() { - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRef<_, u32> = or.map(|x| &mut x.0); - assert_eq!(&*or, &42); - - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRef<_, u8> = or.map(|x| &mut x.2[1]); - assert_eq!(&*or, &2); - } - - #[test] - fn map_heap_ref() { - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRef<_, str> = or.map(|x| &mut x.1[..5]); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_static_ref() { - let or: BoxRefMut<()> = Box::new(()).into(); - let or: BoxRef<_, str> = or.map(|_| "hello"); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_mut_offset_ref() { - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRefMut<_, u32> = or.map_mut(|x| &mut x.0); - assert_eq!(&*or, &42); - - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRefMut<_, u8> = or.map_mut(|x| &mut x.2[1]); - assert_eq!(&*or, &2); - } - - #[test] - fn map_mut_heap_ref() { - let or: BoxRefMut = Box::new(example()).into(); - let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x.1[..5]); - assert_eq!(&*or, "hello"); - } - - #[test] - fn map_mut_static_ref() { - static mut MUT_S: [u8; 5] = *b"hello"; - - let mut_s: &'static mut [u8] = unsafe { &mut MUT_S }; - - let or: BoxRefMut<()> = Box::new(()).into(); - let or: BoxRefMut<_, [u8]> = or.map_mut(move |_| mut_s); - assert_eq!(&*or, b"hello"); - } - - #[test] - fn map_mut_chained() { - let or: BoxRefMut = Box::new(example().1).into(); - let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[1..5]); - let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[..2]); - assert_eq!(&*or, "el"); - } - - #[test] - fn map_chained_inference() { - let or = BoxRefMut::new(Box::new(example().1)) - .map_mut(|x| &mut x[..5]) - .map_mut(|x| &mut x[1..3]); - assert_eq!(&*or, "el"); - } - - #[test] - fn try_map_mut() { - let or: BoxRefMut = Box::new(example().1).into(); - let or: Result, ()> = or.try_map_mut(|x| Ok(&mut x[1..5])); - assert_eq!(&*or.unwrap(), "ello"); - - let or: BoxRefMut = Box::new(example().1).into(); - let or: Result, ()> = or.try_map_mut(|_| Err(())); - assert!(or.is_err()); - } - - #[test] - fn owner() { - let or: BoxRefMut = Box::new(example().1).into(); - let or = or.map_mut(|x| &mut x[..5]); - assert_eq!(&*or, "hello"); - assert_eq!(&**or.owner(), "hello world"); - } - - #[test] - fn into_inner() { - let or: BoxRefMut = Box::new(example().1).into(); - let or = or.map_mut(|x| &mut x[..5]); - assert_eq!(&*or, "hello"); - let s = *or.into_inner(); - assert_eq!(&s, "hello world"); - } - - #[test] - fn fmt_debug() { - let or: BoxRefMut = Box::new(example().1).into(); - let or = or.map_mut(|x| &mut x[..5]); - let s = format!("{:?}", or); - assert_eq!(&s, "OwningRefMut { owner: \"hello world\", reference: \"hello\" }"); - } - - #[test] - fn erased_owner() { - let o1: BoxRefMut = - BoxRefMut::new(Box::new(example())).map_mut(|x| &mut x.1[..]); - - let o2: BoxRefMut = - BoxRefMut::new(Box::new(example().1)).map_mut(|x| &mut x[..]); - - let os: Vec> = vec![o1.erase_owner(), o2.erase_owner()]; - assert!(os.iter().all(|e| &e[..] == "hello world")); - } - - #[test] - fn raii_locks() { - use super::super::RefMutRefMut; - use super::super::{MutexGuardRefMut, RwLockWriteGuardRefMut}; - use std::cell::RefCell; - use std::sync::{Mutex, RwLock}; - - { - let a = RefCell::new(1); - let a = { - let a = RefMutRefMut::new(a.borrow_mut()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = Mutex::new(1); - let a = { - let a = MutexGuardRefMut::new(a.lock().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - { - let a = RwLock::new(1); - let a = { - let a = RwLockWriteGuardRefMut::new(a.write().unwrap()); - assert_eq!(*a, 1); - a - }; - assert_eq!(*a, 1); - drop(a); - } - } - - #[test] - fn eq() { - let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - assert_eq!(or1.eq(&or2), true); - } - - #[test] - fn cmp() { - let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice()); - assert_eq!(or1.cmp(&or2), Ordering::Less); - } - - #[test] - fn partial_cmp() { - let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice()); - let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater)); - } - - #[test] - fn hash() { - let mut h1 = DefaultHasher::new(); - let mut h2 = DefaultHasher::new(); - - let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); - - or1.hash(&mut h1); - or2.hash(&mut h2); - - assert_eq!(h1.finish(), h2.finish()); - } - - #[test] - fn borrow() { - let mut hash = HashMap::new(); - let key1 = BoxRefMut::::new(Box::new("foo".to_string())).map(|s| &s[..]); - let key2 = BoxRefMut::::new(Box::new("bar".to_string())).map(|s| &s[..]); - - hash.insert(key1, 42); - hash.insert(key2, 23); - - assert_eq!(hash.get("foo"), Some(&42)); - assert_eq!(hash.get("bar"), Some(&23)); - } - - #[test] - fn total_erase() { - let a: OwningRefMut, [u8]> = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]); - let b: OwningRefMut, [u8]> = - OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]); - - let c: OwningRefMut>, [u8]> = unsafe { a.map_owner(Box::new) }; - let d: OwningRefMut>, [u8]> = unsafe { b.map_owner(Box::new) }; - - let _e: OwningRefMut, [u8]> = c.erase_owner(); - let _f: OwningRefMut, [u8]> = d.erase_owner(); - } - - #[test] - fn total_erase_box() { - let a: OwningRefMut, [u8]> = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]); - let b: OwningRefMut, [u8]> = - OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]); - - let c: OwningRefMut>, [u8]> = a.map_owner_box(); - let d: OwningRefMut>, [u8]> = b.map_owner_box(); - - let _e: OwningRefMut, [u8]> = c.erase_owner(); - let _f: OwningRefMut, [u8]> = d.erase_owner(); - } - - #[test] - fn try_map1() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - assert!(OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).is_ok()); - } - - #[test] - fn try_map2() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - assert!(!OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).is_err()); - } - - #[test] - fn try_map3() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - assert!(OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_ok()); - } - - #[test] - fn try_map4() { - use std::any::Any; - - let x = Box::new(123_i32); - let y: Box = x; - - assert!(!OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_err()); - } - - #[test] - fn into_owning_ref() { - use super::super::BoxRef; - - let or: BoxRefMut<()> = Box::new(()).into(); - let or: BoxRef<()> = or.into(); - assert_eq!(&*or, &()); - } - - struct Foo { - u: u32, - } - struct Bar { - f: Foo, - } - - #[test] - fn ref_mut() { - use std::cell::RefCell; - - let a = RefCell::new(Bar { f: Foo { u: 42 } }); - let mut b = OwningRefMut::new(a.borrow_mut()); - assert_eq!(b.f.u, 42); - b.f.u = 43; - let mut c = b.map_mut(|x| &mut x.f); - assert_eq!(c.u, 43); - c.u = 44; - let mut d = c.map_mut(|x| &mut x.u); - assert_eq!(*d, 44); - *d = 45; - assert_eq!(*d, 45); - } -} diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 58a0609e2965..1ed584eafad3 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -778,7 +778,7 @@ pub fn print_time_passes_entry( "rss_start": start_rss, "rss_end": end_rss, }); - eprintln!("time: {}", json.to_string()); + eprintln!("time: {json}"); return; } TimePassesFormat::Text => (), diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index f88c055a9b56..bd7a86f67800 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -140,6 +140,7 @@ pub fn make_hash(val: &K) -> u64 { /// `hash` can be computed with any hasher, so long as that hasher is used /// consistently for each `Sharded` instance. #[inline] +#[allow(clippy::modulo_one)] pub fn get_shard_index_by_hash(hash: u64) -> usize { let hash_len = mem::size_of::(); // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits. diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index 90793a97ed0d..d849fe0373f2 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -247,7 +247,7 @@ impl SipHasher128 { for i in 0..BUFFER_CAPACITY { let elem = self.buf.get_unchecked(i).assume_init().to_le(); self.state.v3 ^= elem; - Sip24Rounds::c_rounds(&mut self.state); + Sip13Rounds::c_rounds(&mut self.state); self.state.v0 ^= elem; } @@ -327,7 +327,7 @@ impl SipHasher128 { for i in 0..last { let elem = self.buf.get_unchecked(i).assume_init().to_le(); self.state.v3 ^= elem; - Sip24Rounds::c_rounds(&mut self.state); + Sip13Rounds::c_rounds(&mut self.state); self.state.v0 ^= elem; } @@ -340,7 +340,7 @@ impl SipHasher128 { for _ in 0..elems_left { let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le(); self.state.v3 ^= elem; - Sip24Rounds::c_rounds(&mut self.state); + Sip13Rounds::c_rounds(&mut self.state); self.state.v0 ^= elem; processed += ELEM_SIZE; } @@ -368,7 +368,7 @@ impl SipHasher128 { for i in 0..last { let elem = unsafe { self.buf.get_unchecked(i).assume_init().to_le() }; state.v3 ^= elem; - Sip24Rounds::c_rounds(&mut state); + Sip13Rounds::c_rounds(&mut state); state.v0 ^= elem; } @@ -392,15 +392,15 @@ impl SipHasher128 { let b: u64 = ((length as u64 & 0xff) << 56) | elem; state.v3 ^= b; - Sip24Rounds::c_rounds(&mut state); + Sip13Rounds::c_rounds(&mut state); state.v0 ^= b; state.v2 ^= 0xee; - Sip24Rounds::d_rounds(&mut state); + Sip13Rounds::d_rounds(&mut state); let _0 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3; state.v1 ^= 0xdd; - Sip24Rounds::d_rounds(&mut state); + Sip13Rounds::d_rounds(&mut state); let _1 = state.v0 ^ state.v1 ^ state.v2 ^ state.v3; (_0, _1) @@ -477,13 +477,12 @@ impl Hasher for SipHasher128 { } #[derive(Debug, Clone, Default)] -struct Sip24Rounds; +struct Sip13Rounds; -impl Sip24Rounds { +impl Sip13Rounds { #[inline] fn c_rounds(state: &mut State) { compress!(state); - compress!(state); } #[inline] @@ -491,6 +490,5 @@ impl Sip24Rounds { compress!(state); compress!(state); compress!(state); - compress!(state); } } diff --git a/compiler/rustc_data_structures/src/sip128/tests.rs b/compiler/rustc_data_structures/src/sip128/tests.rs index 5fe967c4158f..cc6d3b0f4715 100644 --- a/compiler/rustc_data_structures/src/sip128/tests.rs +++ b/compiler/rustc_data_structures/src/sip128/tests.rs @@ -22,269 +22,76 @@ fn hash_with(mut st: SipHasher128, x: &T) -> (u64, u64) { fn hash(x: &T) -> (u64, u64) { hash_with(SipHasher128::new_with_keys(0, 0), x) } - +#[rustfmt::skip] const TEST_VECTOR: [[u8; 16]; 64] = [ - [ - 0xa3, 0x81, 0x7f, 0x04, 0xba, 0x25, 0xa8, 0xe6, 0x6d, 0xf6, 0x72, 0x14, 0xc7, 0x55, 0x02, - 0x93, - ], - [ - 0xda, 0x87, 0xc1, 0xd8, 0x6b, 0x99, 0xaf, 0x44, 0x34, 0x76, 0x59, 0x11, 0x9b, 0x22, 0xfc, - 0x45, - ], - [ - 0x81, 0x77, 0x22, 0x8d, 0xa4, 0xa4, 0x5d, 0xc7, 0xfc, 0xa3, 0x8b, 0xde, 0xf6, 0x0a, 0xff, - 0xe4, - ], - [ - 0x9c, 0x70, 0xb6, 0x0c, 0x52, 0x67, 0xa9, 0x4e, 0x5f, 0x33, 0xb6, 0xb0, 0x29, 0x85, 0xed, - 0x51, - ], - [ - 0xf8, 0x81, 0x64, 0xc1, 0x2d, 0x9c, 0x8f, 0xaf, 0x7d, 0x0f, 0x6e, 0x7c, 0x7b, 0xcd, 0x55, - 0x79, - ], - [ - 0x13, 0x68, 0x87, 0x59, 0x80, 0x77, 0x6f, 0x88, 0x54, 0x52, 0x7a, 0x07, 0x69, 0x0e, 0x96, - 0x27, - ], - [ - 0x14, 0xee, 0xca, 0x33, 0x8b, 0x20, 0x86, 0x13, 0x48, 0x5e, 0xa0, 0x30, 0x8f, 0xd7, 0xa1, - 0x5e, - ], - [ - 0xa1, 0xf1, 0xeb, 0xbe, 0xd8, 0xdb, 0xc1, 0x53, 0xc0, 0xb8, 0x4a, 0xa6, 0x1f, 0xf0, 0x82, - 0x39, - ], - [ - 0x3b, 0x62, 0xa9, 0xba, 0x62, 0x58, 0xf5, 0x61, 0x0f, 0x83, 0xe2, 0x64, 0xf3, 0x14, 0x97, - 0xb4, - ], - [ - 0x26, 0x44, 0x99, 0x06, 0x0a, 0xd9, 0xba, 0xab, 0xc4, 0x7f, 0x8b, 0x02, 0xbb, 0x6d, 0x71, - 0xed, - ], - [ - 0x00, 0x11, 0x0d, 0xc3, 0x78, 0x14, 0x69, 0x56, 0xc9, 0x54, 0x47, 0xd3, 0xf3, 0xd0, 0xfb, - 0xba, - ], - [ - 0x01, 0x51, 0xc5, 0x68, 0x38, 0x6b, 0x66, 0x77, 0xa2, 0xb4, 0xdc, 0x6f, 0x81, 0xe5, 0xdc, - 0x18, - ], - [ - 0xd6, 0x26, 0xb2, 0x66, 0x90, 0x5e, 0xf3, 0x58, 0x82, 0x63, 0x4d, 0xf6, 0x85, 0x32, 0xc1, - 0x25, - ], - [ - 0x98, 0x69, 0xe2, 0x47, 0xe9, 0xc0, 0x8b, 0x10, 0xd0, 0x29, 0x93, 0x4f, 0xc4, 0xb9, 0x52, - 0xf7, - ], - [ - 0x31, 0xfc, 0xef, 0xac, 0x66, 0xd7, 0xde, 0x9c, 0x7e, 0xc7, 0x48, 0x5f, 0xe4, 0x49, 0x49, - 0x02, - ], - [ - 0x54, 0x93, 0xe9, 0x99, 0x33, 0xb0, 0xa8, 0x11, 0x7e, 0x08, 0xec, 0x0f, 0x97, 0xcf, 0xc3, - 0xd9, - ], - [ - 0x6e, 0xe2, 0xa4, 0xca, 0x67, 0xb0, 0x54, 0xbb, 0xfd, 0x33, 0x15, 0xbf, 0x85, 0x23, 0x05, - 0x77, - ], - [ - 0x47, 0x3d, 0x06, 0xe8, 0x73, 0x8d, 0xb8, 0x98, 0x54, 0xc0, 0x66, 0xc4, 0x7a, 0xe4, 0x77, - 0x40, - ], - [ - 0xa4, 0x26, 0xe5, 0xe4, 0x23, 0xbf, 0x48, 0x85, 0x29, 0x4d, 0xa4, 0x81, 0xfe, 0xae, 0xf7, - 0x23, - ], - [ - 0x78, 0x01, 0x77, 0x31, 0xcf, 0x65, 0xfa, 0xb0, 0x74, 0xd5, 0x20, 0x89, 0x52, 0x51, 0x2e, - 0xb1, - ], - [ - 0x9e, 0x25, 0xfc, 0x83, 0x3f, 0x22, 0x90, 0x73, 0x3e, 0x93, 0x44, 0xa5, 0xe8, 0x38, 0x39, - 0xeb, - ], - [ - 0x56, 0x8e, 0x49, 0x5a, 0xbe, 0x52, 0x5a, 0x21, 0x8a, 0x22, 0x14, 0xcd, 0x3e, 0x07, 0x1d, - 0x12, - ], - [ - 0x4a, 0x29, 0xb5, 0x45, 0x52, 0xd1, 0x6b, 0x9a, 0x46, 0x9c, 0x10, 0x52, 0x8e, 0xff, 0x0a, - 0xae, - ], - [ - 0xc9, 0xd1, 0x84, 0xdd, 0xd5, 0xa9, 0xf5, 0xe0, 0xcf, 0x8c, 0xe2, 0x9a, 0x9a, 0xbf, 0x69, - 0x1c, - ], - [ - 0x2d, 0xb4, 0x79, 0xae, 0x78, 0xbd, 0x50, 0xd8, 0x88, 0x2a, 0x8a, 0x17, 0x8a, 0x61, 0x32, - 0xad, - ], - [ - 0x8e, 0xce, 0x5f, 0x04, 0x2d, 0x5e, 0x44, 0x7b, 0x50, 0x51, 0xb9, 0xea, 0xcb, 0x8d, 0x8f, - 0x6f, - ], - [ - 0x9c, 0x0b, 0x53, 0xb4, 0xb3, 0xc3, 0x07, 0xe8, 0x7e, 0xae, 0xe0, 0x86, 0x78, 0x14, 0x1f, - 0x66, - ], - [ - 0xab, 0xf2, 0x48, 0xaf, 0x69, 0xa6, 0xea, 0xe4, 0xbf, 0xd3, 0xeb, 0x2f, 0x12, 0x9e, 0xeb, - 0x94, - ], - [ - 0x06, 0x64, 0xda, 0x16, 0x68, 0x57, 0x4b, 0x88, 0xb9, 0x35, 0xf3, 0x02, 0x73, 0x58, 0xae, - 0xf4, - ], - [ - 0xaa, 0x4b, 0x9d, 0xc4, 0xbf, 0x33, 0x7d, 0xe9, 0x0c, 0xd4, 0xfd, 0x3c, 0x46, 0x7c, 0x6a, - 0xb7, - ], - [ - 0xea, 0x5c, 0x7f, 0x47, 0x1f, 0xaf, 0x6b, 0xde, 0x2b, 0x1a, 0xd7, 0xd4, 0x68, 0x6d, 0x22, - 0x87, - ], - [ - 0x29, 0x39, 0xb0, 0x18, 0x32, 0x23, 0xfa, 0xfc, 0x17, 0x23, 0xde, 0x4f, 0x52, 0xc4, 0x3d, - 0x35, - ], - [ - 0x7c, 0x39, 0x56, 0xca, 0x5e, 0xea, 0xfc, 0x3e, 0x36, 0x3e, 0x9d, 0x55, 0x65, 0x46, 0xeb, - 0x68, - ], - [ - 0x77, 0xc6, 0x07, 0x71, 0x46, 0xf0, 0x1c, 0x32, 0xb6, 0xb6, 0x9d, 0x5f, 0x4e, 0xa9, 0xff, - 0xcf, - ], - [ - 0x37, 0xa6, 0x98, 0x6c, 0xb8, 0x84, 0x7e, 0xdf, 0x09, 0x25, 0xf0, 0xf1, 0x30, 0x9b, 0x54, - 0xde, - ], - [ - 0xa7, 0x05, 0xf0, 0xe6, 0x9d, 0xa9, 0xa8, 0xf9, 0x07, 0x24, 0x1a, 0x2e, 0x92, 0x3c, 0x8c, - 0xc8, - ], - [ - 0x3d, 0xc4, 0x7d, 0x1f, 0x29, 0xc4, 0x48, 0x46, 0x1e, 0x9e, 0x76, 0xed, 0x90, 0x4f, 0x67, - 0x11, - ], - [ - 0x0d, 0x62, 0xbf, 0x01, 0xe6, 0xfc, 0x0e, 0x1a, 0x0d, 0x3c, 0x47, 0x51, 0xc5, 0xd3, 0x69, - 0x2b, - ], - [ - 0x8c, 0x03, 0x46, 0x8b, 0xca, 0x7c, 0x66, 0x9e, 0xe4, 0xfd, 0x5e, 0x08, 0x4b, 0xbe, 0xe7, - 0xb5, - ], - [ - 0x52, 0x8a, 0x5b, 0xb9, 0x3b, 0xaf, 0x2c, 0x9c, 0x44, 0x73, 0xcc, 0xe5, 0xd0, 0xd2, 0x2b, - 0xd9, - ], - [ - 0xdf, 0x6a, 0x30, 0x1e, 0x95, 0xc9, 0x5d, 0xad, 0x97, 0xae, 0x0c, 0xc8, 0xc6, 0x91, 0x3b, - 0xd8, - ], - [ - 0x80, 0x11, 0x89, 0x90, 0x2c, 0x85, 0x7f, 0x39, 0xe7, 0x35, 0x91, 0x28, 0x5e, 0x70, 0xb6, - 0xdb, - ], - [ - 0xe6, 0x17, 0x34, 0x6a, 0xc9, 0xc2, 0x31, 0xbb, 0x36, 0x50, 0xae, 0x34, 0xcc, 0xca, 0x0c, - 0x5b, - ], - [ - 0x27, 0xd9, 0x34, 0x37, 0xef, 0xb7, 0x21, 0xaa, 0x40, 0x18, 0x21, 0xdc, 0xec, 0x5a, 0xdf, - 0x89, - ], - [ - 0x89, 0x23, 0x7d, 0x9d, 0xed, 0x9c, 0x5e, 0x78, 0xd8, 0xb1, 0xc9, 0xb1, 0x66, 0xcc, 0x73, - 0x42, - ], - [ - 0x4a, 0x6d, 0x80, 0x91, 0xbf, 0x5e, 0x7d, 0x65, 0x11, 0x89, 0xfa, 0x94, 0xa2, 0x50, 0xb1, - 0x4c, - ], - [ - 0x0e, 0x33, 0xf9, 0x60, 0x55, 0xe7, 0xae, 0x89, 0x3f, 0xfc, 0x0e, 0x3d, 0xcf, 0x49, 0x29, - 0x02, - ], - [ - 0xe6, 0x1c, 0x43, 0x2b, 0x72, 0x0b, 0x19, 0xd1, 0x8e, 0xc8, 0xd8, 0x4b, 0xdc, 0x63, 0x15, - 0x1b, - ], - [ - 0xf7, 0xe5, 0xae, 0xf5, 0x49, 0xf7, 0x82, 0xcf, 0x37, 0x90, 0x55, 0xa6, 0x08, 0x26, 0x9b, - 0x16, - ], - [ - 0x43, 0x8d, 0x03, 0x0f, 0xd0, 0xb7, 0xa5, 0x4f, 0xa8, 0x37, 0xf2, 0xad, 0x20, 0x1a, 0x64, - 0x03, - ], - [ - 0xa5, 0x90, 0xd3, 0xee, 0x4f, 0xbf, 0x04, 0xe3, 0x24, 0x7e, 0x0d, 0x27, 0xf2, 0x86, 0x42, - 0x3f, - ], - [ - 0x5f, 0xe2, 0xc1, 0xa1, 0x72, 0xfe, 0x93, 0xc4, 0xb1, 0x5c, 0xd3, 0x7c, 0xae, 0xf9, 0xf5, - 0x38, - ], - [ - 0x2c, 0x97, 0x32, 0x5c, 0xbd, 0x06, 0xb3, 0x6e, 0xb2, 0x13, 0x3d, 0xd0, 0x8b, 0x3a, 0x01, - 0x7c, - ], - [ - 0x92, 0xc8, 0x14, 0x22, 0x7a, 0x6b, 0xca, 0x94, 0x9f, 0xf0, 0x65, 0x9f, 0x00, 0x2a, 0xd3, - 0x9e, - ], - [ - 0xdc, 0xe8, 0x50, 0x11, 0x0b, 0xd8, 0x32, 0x8c, 0xfb, 0xd5, 0x08, 0x41, 0xd6, 0x91, 0x1d, - 0x87, - ], - [ - 0x67, 0xf1, 0x49, 0x84, 0xc7, 0xda, 0x79, 0x12, 0x48, 0xe3, 0x2b, 0xb5, 0x92, 0x25, 0x83, - 0xda, - ], - [ - 0x19, 0x38, 0xf2, 0xcf, 0x72, 0xd5, 0x4e, 0xe9, 0x7e, 0x94, 0x16, 0x6f, 0xa9, 0x1d, 0x2a, - 0x36, - ], - [ - 0x74, 0x48, 0x1e, 0x96, 0x46, 0xed, 0x49, 0xfe, 0x0f, 0x62, 0x24, 0x30, 0x16, 0x04, 0x69, - 0x8e, - ], - [ - 0x57, 0xfc, 0xa5, 0xde, 0x98, 0xa9, 0xd6, 0xd8, 0x00, 0x64, 0x38, 0xd0, 0x58, 0x3d, 0x8a, - 0x1d, - ], - [ - 0x9f, 0xec, 0xde, 0x1c, 0xef, 0xdc, 0x1c, 0xbe, 0xd4, 0x76, 0x36, 0x74, 0xd9, 0x57, 0x53, - 0x59, - ], - [ - 0xe3, 0x04, 0x0c, 0x00, 0xeb, 0x28, 0xf1, 0x53, 0x66, 0xca, 0x73, 0xcb, 0xd8, 0x72, 0xe7, - 0x40, - ], - [ - 0x76, 0x97, 0x00, 0x9a, 0x6a, 0x83, 0x1d, 0xfe, 0xcc, 0xa9, 0x1c, 0x59, 0x93, 0x67, 0x0f, - 0x7a, - ], - [ - 0x58, 0x53, 0x54, 0x23, 0x21, 0xf5, 0x67, 0xa0, 0x05, 0xd5, 0x47, 0xa4, 0xf0, 0x47, 0x59, - 0xbd, - ], - [ - 0x51, 0x50, 0xd1, 0x77, 0x2f, 0x50, 0x83, 0x4a, 0x50, 0x3e, 0x06, 0x9a, 0x97, 0x3f, 0xbd, - 0x7c, - ], + [0xe7, 0x7e, 0xbc, 0xb2, 0x27, 0x88, 0xa5, 0xbe, 0xfd, 0x62, 0xdb, 0x6a, 0xdd, 0x30, 0x30, 0x01], + [0xfc, 0x6f, 0x37, 0x04, 0x60, 0xd3, 0xed, 0xa8, 0x5e, 0x05, 0x73, 0xcc, 0x2b, 0x2f, 0xf0, 0x63], + [0x75, 0x78, 0x7f, 0x09, 0x05, 0x69, 0x83, 0x9b, 0x85, 0x5b, 0xc9, 0x54, 0x8c, 0x6a, 0xea, 0x95], + [0x6b, 0xc5, 0xcc, 0xfa, 0x1e, 0xdc, 0xf7, 0x9f, 0x48, 0x23, 0x18, 0x77, 0x12, 0xeb, 0xd7, 0x43], + [0x0c, 0x78, 0x4e, 0x71, 0xac, 0x2b, 0x28, 0x5a, 0x9f, 0x8e, 0x92, 0xe7, 0x8f, 0xbf, 0x2c, 0x25], + [0xf3, 0x28, 0xdb, 0x89, 0x34, 0x5b, 0x62, 0x0c, 0x79, 0x52, 0x29, 0xa4, 0x26, 0x95, 0x84, 0x3e], + [0xdc, 0xd0, 0x3d, 0x29, 0xf7, 0x43, 0xe7, 0x10, 0x09, 0x51, 0xb0, 0xe8, 0x39, 0x85, 0xa6, 0xf8], + [0x10, 0x84, 0xb9, 0x23, 0xf2, 0xaa, 0xe0, 0xc3, 0xa6, 0x2f, 0x2e, 0xc8, 0x08, 0x48, 0xab, 0x77], + [0xaa, 0x12, 0xfe, 0xe1, 0xd5, 0xe3, 0xda, 0xb4, 0x72, 0x4f, 0x16, 0xab, 0x35, 0xf9, 0xc7, 0x99], + [0x81, 0xdd, 0xb8, 0x04, 0x2c, 0xf3, 0x39, 0x94, 0xf4, 0x72, 0x0e, 0x00, 0x94, 0x13, 0x7c, 0x42], + [0x4f, 0xaa, 0x54, 0x1d, 0x5d, 0x49, 0x8e, 0x89, 0xba, 0x0e, 0xa4, 0xc3, 0x87, 0xb2, 0x2f, 0xb4], + [0x72, 0x3b, 0x9a, 0xf3, 0x55, 0x44, 0x91, 0xdb, 0xb1, 0xd6, 0x63, 0x3d, 0xfc, 0x6e, 0x0c, 0x4e], + [0xe5, 0x3f, 0x92, 0x85, 0x9e, 0x48, 0x19, 0xa8, 0xdc, 0x06, 0x95, 0x73, 0x9f, 0xea, 0x8c, 0x65], + [0xb2, 0xf8, 0x58, 0xc7, 0xc9, 0xea, 0x80, 0x1d, 0x53, 0xd6, 0x03, 0x59, 0x6d, 0x65, 0x78, 0x44], + [0x87, 0xe7, 0x62, 0x68, 0xdb, 0xc9, 0x22, 0x72, 0x26, 0xb0, 0xca, 0x66, 0x5f, 0x64, 0xe3, 0x78], + [0xc1, 0x7e, 0x55, 0x05, 0xb2, 0xbd, 0x52, 0x6c, 0x29, 0x21, 0xcd, 0xec, 0x1e, 0x7e, 0x01, 0x09], + [0xd0, 0xa8, 0xd9, 0x57, 0x15, 0x51, 0x8e, 0xeb, 0xb5, 0x13, 0xb0, 0xf8, 0x3d, 0x9e, 0x17, 0x93], + [0x23, 0x41, 0x26, 0xf9, 0x3f, 0xbb, 0x66, 0x8d, 0x97, 0x51, 0x12, 0xe8, 0xfe, 0xbd, 0xf7, 0xec], + [0xef, 0x42, 0xf0, 0x3d, 0xb7, 0x8f, 0x70, 0x4d, 0x02, 0x3c, 0x44, 0x9f, 0x16, 0xb7, 0x09, 0x2b], + [0xab, 0xf7, 0x62, 0x38, 0xc2, 0x0a, 0xf1, 0x61, 0xb2, 0x31, 0x4b, 0x4d, 0x55, 0x26, 0xbc, 0xe9], + [0x3c, 0x2c, 0x2f, 0x11, 0xbb, 0x90, 0xcf, 0x0b, 0xe3, 0x35, 0xca, 0x9b, 0x2e, 0x91, 0xe9, 0xb7], + [0x2a, 0x7a, 0x68, 0x0f, 0x22, 0xa0, 0x2a, 0x92, 0xf4, 0x51, 0x49, 0xd2, 0x0f, 0xec, 0xe0, 0xef], + [0xc9, 0xa8, 0xd1, 0x30, 0x23, 0x1d, 0xd4, 0x3e, 0x42, 0xe6, 0x45, 0x69, 0x57, 0xf8, 0x37, 0x79], + [0x1d, 0x12, 0x7b, 0x84, 0x40, 0x5c, 0xea, 0xb9, 0x9f, 0xd8, 0x77, 0x5a, 0x9b, 0xe6, 0xc5, 0x59], + [0x9e, 0x4b, 0xf8, 0x37, 0xbc, 0xfd, 0x92, 0xca, 0xce, 0x09, 0xd2, 0x06, 0x1a, 0x84, 0xd0, 0x4a], + [0x39, 0x03, 0x1a, 0x96, 0x5d, 0x73, 0xb4, 0xaf, 0x5a, 0x27, 0x4d, 0x18, 0xf9, 0x73, 0xb1, 0xd2], + [0x7f, 0x4d, 0x0a, 0x12, 0x09, 0xd6, 0x7e, 0x4e, 0xd0, 0x6f, 0x75, 0x38, 0xe1, 0xcf, 0xad, 0x64], + [0xe6, 0x1e, 0xe2, 0x40, 0xfb, 0xdc, 0xce, 0x38, 0x96, 0x9f, 0x4c, 0xd2, 0x49, 0x27, 0xdd, 0x93], + [0x4c, 0x3b, 0xa2, 0xb3, 0x7b, 0x0f, 0xdd, 0x8c, 0xfa, 0x5e, 0x95, 0xc1, 0x89, 0xb2, 0x94, 0x14], + [0xe0, 0x6f, 0xd4, 0xca, 0x06, 0x6f, 0xec, 0xdd, 0x54, 0x06, 0x8a, 0x5a, 0xd8, 0x89, 0x6f, 0x86], + [0x5c, 0xa8, 0x4c, 0x34, 0x13, 0x9c, 0x65, 0x80, 0xa8, 0x8a, 0xf2, 0x49, 0x90, 0x72, 0x07, 0x06], + [0x42, 0xea, 0x96, 0x1c, 0x5b, 0x3c, 0x85, 0x8b, 0x17, 0xc3, 0xe5, 0x50, 0xdf, 0xa7, 0x90, 0x10], + [0x40, 0x6c, 0x44, 0xde, 0xe6, 0x78, 0x57, 0xb2, 0x94, 0x31, 0x60, 0xf3, 0x0c, 0x74, 0x17, 0xd3], + [0xc5, 0xf5, 0x7b, 0xae, 0x13, 0x20, 0xfc, 0xf4, 0xb4, 0xe8, 0x68, 0xe7, 0x1d, 0x56, 0xc6, 0x6b], + [0x04, 0xbf, 0x73, 0x7a, 0x5b, 0x67, 0x6b, 0xe7, 0xc3, 0xde, 0x05, 0x01, 0x7d, 0xf4, 0xbf, 0xf9], + [0x51, 0x63, 0xc9, 0xc0, 0x3f, 0x19, 0x07, 0xea, 0x10, 0x44, 0xed, 0x5c, 0x30, 0x72, 0x7b, 0x4f], + [0x37, 0xa1, 0x10, 0xf0, 0x02, 0x71, 0x8e, 0xda, 0xd2, 0x4b, 0x3f, 0x9e, 0xe4, 0x53, 0xf1, 0x40], + [0xb9, 0x87, 0x7e, 0x38, 0x1a, 0xed, 0xd3, 0xda, 0x08, 0xc3, 0x3e, 0x75, 0xff, 0x23, 0xac, 0x10], + [0x7c, 0x50, 0x04, 0x00, 0x5e, 0xc5, 0xda, 0x4c, 0x5a, 0xc9, 0x44, 0x0e, 0x5c, 0x72, 0x31, 0x93], + [0x81, 0xb8, 0x24, 0x37, 0x83, 0xdb, 0xc6, 0x46, 0xca, 0x9d, 0x0c, 0xd8, 0x2a, 0xbd, 0xb4, 0x6c], + [0x50, 0x57, 0x20, 0x54, 0x3e, 0xb9, 0xb4, 0x13, 0xd5, 0x0b, 0x3c, 0xfa, 0xd9, 0xee, 0xf9, 0x38], + [0x94, 0x5f, 0x59, 0x4d, 0xe7, 0x24, 0x11, 0xe4, 0xd3, 0x35, 0xbe, 0x87, 0x44, 0x56, 0xd8, 0xf3], + [0x37, 0x92, 0x3b, 0x3e, 0x37, 0x17, 0x77, 0xb2, 0x11, 0x70, 0xbf, 0x9d, 0x7e, 0x62, 0xf6, 0x02], + [0x3a, 0xd4, 0xe7, 0xc8, 0x57, 0x64, 0x96, 0x46, 0x11, 0xeb, 0x0a, 0x6c, 0x4d, 0x62, 0xde, 0x56], + [0xcd, 0x91, 0x39, 0x6c, 0x44, 0xaf, 0x4f, 0x51, 0x85, 0x57, 0x8d, 0x9d, 0xd9, 0x80, 0x3f, 0x0a], + [0xfe, 0x28, 0x15, 0x8e, 0x72, 0x7b, 0x86, 0x8f, 0x39, 0x03, 0xc9, 0xac, 0xda, 0x64, 0xa2, 0x58], + [0x40, 0xcc, 0x10, 0xb8, 0x28, 0x8c, 0xe5, 0xf0, 0xbc, 0x3a, 0xc0, 0xb6, 0x8a, 0x0e, 0xeb, 0xc8], + [0x6f, 0x14, 0x90, 0xf5, 0x40, 0x69, 0x9a, 0x3c, 0xd4, 0x97, 0x44, 0x20, 0xec, 0xc9, 0x27, 0x37], + [0xd5, 0x05, 0xf1, 0xb7, 0x5e, 0x1a, 0x84, 0xa6, 0x03, 0xc4, 0x35, 0x83, 0xb2, 0xed, 0x03, 0x08], + [0x49, 0x15, 0x73, 0xcf, 0xd7, 0x2b, 0xb4, 0x68, 0x2b, 0x7c, 0xa5, 0x88, 0x0e, 0x1c, 0x8d, 0x6f], + [0x3e, 0xd6, 0x9c, 0xfe, 0x45, 0xab, 0x40, 0x3f, 0x2f, 0xd2, 0xad, 0x95, 0x9b, 0xa2, 0x76, 0x66], + [0x8b, 0xe8, 0x39, 0xef, 0x1b, 0x20, 0xb5, 0x7c, 0x83, 0xba, 0x7e, 0xb6, 0xa8, 0xc2, 0x2b, 0x6a], + [0x14, 0x09, 0x18, 0x6a, 0xb4, 0x22, 0x31, 0xfe, 0xde, 0xe1, 0x81, 0x62, 0xcf, 0x1c, 0xb4, 0xca], + [0x2b, 0xf3, 0xcc, 0xc2, 0x4a, 0xb6, 0x72, 0xcf, 0x15, 0x1f, 0xb8, 0xd2, 0xf3, 0xf3, 0x06, 0x9b], + [0xb9, 0xb9, 0x3a, 0x28, 0x82, 0xd6, 0x02, 0x5c, 0xdb, 0x8c, 0x56, 0xfa, 0x13, 0xf7, 0x53, 0x7b], + [0xd9, 0x7c, 0xca, 0x36, 0x94, 0xfb, 0x20, 0x6d, 0xb8, 0xbd, 0x1f, 0x36, 0x50, 0xc3, 0x33, 0x22], + [0x94, 0xec, 0x2e, 0x19, 0xa4, 0x0b, 0xe4, 0x1a, 0xf3, 0x94, 0x0d, 0x6b, 0x30, 0xc4, 0x93, 0x84], + [0x4b, 0x41, 0x60, 0x3f, 0x20, 0x9a, 0x04, 0x5b, 0xe1, 0x40, 0xa3, 0x41, 0xa3, 0xdf, 0xfe, 0x10], + [0x23, 0xfb, 0xcb, 0x30, 0x9f, 0x1c, 0xf0, 0x94, 0x89, 0x07, 0x55, 0xab, 0x1b, 0x42, 0x65, 0x69], + [0xe7, 0xd9, 0xb6, 0x56, 0x90, 0x91, 0x8a, 0x2b, 0x23, 0x2f, 0x2f, 0x5c, 0x12, 0xc8, 0x30, 0x0e], + [0xad, 0xe8, 0x3c, 0xf7, 0xe7, 0xf3, 0x84, 0x7b, 0x36, 0xfa, 0x4b, 0x54, 0xb0, 0x0d, 0xce, 0x61], + [0x06, 0x10, 0xc5, 0xf2, 0xee, 0x57, 0x1c, 0x8a, 0xc8, 0x0c, 0xbf, 0xe5, 0x38, 0xbd, 0xf1, 0xc7], + [0x27, 0x1d, 0x5d, 0x00, 0xfb, 0xdb, 0x5d, 0x15, 0x5d, 0x9d, 0xce, 0xa9, 0x7c, 0xb4, 0x02, 0x18], + [0x4c, 0x58, 0x00, 0xe3, 0x4e, 0xfe, 0x42, 0x6f, 0x07, 0x9f, 0x6b, 0x0a, 0xa7, 0x52, 0x60, 0xad], ]; -// Test vector from reference implementation #[test] -fn test_siphash_2_4_test_vector() { +fn test_siphash_1_3_test_vector() { let k0 = 0x_07_06_05_04_03_02_01_00; let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index de9842156d61..3ed1de1bc3ca 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -312,14 +312,14 @@ impl HashStable for ::std::num::NonZeroUsize { impl HashStable for f32 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let val: u32 = unsafe { ::std::mem::transmute(*self) }; + let val: u32 = self.to_bits(); val.hash_stable(ctx, hasher); } } impl HashStable for f64 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let val: u64 = unsafe { ::std::mem::transmute(*self) }; + let val: u64 = self.to_bits(); val.hash_stable(ctx, hasher); } } diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs index 724be5888ddb..a98b1bc36261 100644 --- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs +++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs @@ -39,7 +39,7 @@ fn test_hash_integers() { test_isize.hash(&mut h); // This depends on the hashing algorithm. See note at top of file. - let expected = (1784307454142909076, 11471672289340283879); + let expected = (13997337031081104755, 6178945012502239489); assert_eq!(h.finalize(), expected); } @@ -53,7 +53,7 @@ fn test_hash_usize() { test_usize.hash(&mut h); // This depends on the hashing algorithm. See note at top of file. - let expected = (5798740672699530587, 11186240177685111648); + let expected = (12037165114281468837, 3094087741167521712); assert_eq!(h.finalize(), expected); } @@ -67,7 +67,7 @@ fn test_hash_isize() { test_isize.hash(&mut h); // This depends on the hashing algorithm. See note at top of file. - let expected = (2789913510339652884, 674280939192711005); + let expected = (3979067582695659080, 2322428596355037273); assert_eq!(h.finalize(), expected); } diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs index 3bdd67512321..7ff1339c5ab3 100644 --- a/compiler/rustc_data_structures/src/stack.rs +++ b/compiler/rustc_data_structures/src/stack.rs @@ -5,7 +5,7 @@ const RED_ZONE: usize = 100 * 1024; // 100k // Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then // on. This flag has performance relevant characteristics. Don't set it too high. -const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB +const STACK_PER_RECURSION: usize = 1024 * 1024; // 1MB /// Grows the stack on demand to prevent stack overflow. Call this in strategic locations /// to "break up" recursive calls. E.g. almost any call to `visit_expr` or equivalent can benefit diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 4e2126fff7be..ef1da85198fd 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -7,9 +7,6 @@ //! while the serial versions degenerate straightforwardly to serial execution. //! The operations include `join`, `parallel`, `par_iter`, and `par_for_each`. //! -//! `rustc_erase_owner!` erases an `OwningRef` owner into `Erased` for the -//! serial version and `Erased + Send + Sync` for the parallel version. -//! //! Types //! ----- //! The parallel versions of types provide various kinds of synchronization, @@ -42,7 +39,7 @@ //! //! [^2] `MTLockRef` is a typedef. -use crate::owning_ref::{Erased, OwningRef}; +use crate::owned_slice::OwnedSlice; use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; use std::ops::{Deref, DerefMut}; @@ -51,24 +48,17 @@ use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; pub use std::sync::atomic::Ordering; pub use std::sync::atomic::Ordering::SeqCst; -pub use vec::AppendOnlyVec; +pub use vec::{AppendOnlyIndexVec, AppendOnlyVec}; mod vec; cfg_if! { if #[cfg(not(parallel_compiler))] { - pub auto trait Send {} - pub auto trait Sync {} + pub unsafe auto trait Send {} + pub unsafe auto trait Sync {} - impl Send for T {} - impl Sync for T {} - - #[macro_export] - macro_rules! rustc_erase_owner { - ($v:expr) => { - $v.erase_owner() - } - } + unsafe impl Send for T {} + unsafe impl Sync for T {} use std::ops::Add; @@ -107,6 +97,14 @@ cfg_if! { } } + impl Atomic { + pub fn fetch_or(&self, val: bool, _: Ordering) -> bool { + let result = self.0.get() | val; + self.0.set(val); + result + } + } + impl Atomic { #[inline] pub fn compare_exchange(&self, @@ -189,7 +187,7 @@ cfg_if! { } } - pub type MetadataRef = OwningRef, [u8]>; + pub type MetadataRef = OwnedSlice; pub use std::rc::Rc as Lrc; pub use std::rc::Weak as Weak; @@ -372,20 +370,11 @@ cfg_if! { }); } - pub type MetadataRef = OwningRef, [u8]>; + pub type MetadataRef = OwnedSlice; /// This makes locks panic if they are already held. /// It is only useful when you are running in a single thread const ERROR_CHECKING: bool = false; - - #[macro_export] - macro_rules! rustc_erase_owner { - ($v:expr) => {{ - let v = $v; - ::rustc_data_structures::sync::assert_send_val(&v); - v.erase_send_sync_owner() - }} - } } } @@ -481,14 +470,6 @@ impl Default for Lock { } } -// FIXME: Probably a bad idea -impl Clone for Lock { - #[inline] - fn clone(&self) -> Self { - Lock::new(self.borrow().clone()) - } -} - #[derive(Debug, Default)] pub struct RwLock(InnerRwLock); diff --git a/compiler/rustc_data_structures/src/sync/vec.rs b/compiler/rustc_data_structures/src/sync/vec.rs index cbea4f059992..1783b4b35725 100644 --- a/compiler/rustc_data_structures/src/sync/vec.rs +++ b/compiler/rustc_data_structures/src/sync/vec.rs @@ -2,7 +2,8 @@ use std::marker::PhantomData; use rustc_index::vec::Idx; -pub struct AppendOnlyVec { +#[derive(Default)] +pub struct AppendOnlyIndexVec { #[cfg(not(parallel_compiler))] vec: elsa::vec::FrozenVec, #[cfg(parallel_compiler)] @@ -10,7 +11,7 @@ pub struct AppendOnlyVec { _marker: PhantomData, } -impl AppendOnlyVec { +impl AppendOnlyIndexVec { pub fn new() -> Self { Self { #[cfg(not(parallel_compiler))] @@ -39,3 +40,66 @@ impl AppendOnlyVec { return self.vec.get(i); } } + +#[derive(Default)] +pub struct AppendOnlyVec { + #[cfg(not(parallel_compiler))] + vec: elsa::vec::FrozenVec, + #[cfg(parallel_compiler)] + vec: elsa::sync::LockFreeFrozenVec, +} + +impl AppendOnlyVec { + pub fn new() -> Self { + Self { + #[cfg(not(parallel_compiler))] + vec: elsa::vec::FrozenVec::new(), + #[cfg(parallel_compiler)] + vec: elsa::sync::LockFreeFrozenVec::new(), + } + } + + pub fn push(&self, val: T) -> usize { + #[cfg(not(parallel_compiler))] + let i = self.vec.len(); + #[cfg(not(parallel_compiler))] + self.vec.push(val); + #[cfg(parallel_compiler)] + let i = self.vec.push(val); + i + } + + pub fn get(&self, i: usize) -> Option { + #[cfg(not(parallel_compiler))] + return self.vec.get_copy(i); + #[cfg(parallel_compiler)] + return self.vec.get(i); + } + + pub fn iter_enumerated(&self) -> impl Iterator + '_ { + (0..) + .map(|i| (i, self.get(i))) + .take_while(|(_, o)| o.is_some()) + .filter_map(|(i, o)| Some((i, o?))) + } + + pub fn iter(&self) -> impl Iterator + '_ { + (0..).map(|i| self.get(i)).take_while(|o| o.is_some()).flatten() + } +} + +impl AppendOnlyVec { + pub fn contains(&self, val: T) -> bool { + self.iter_enumerated().any(|(_, v)| v == val) + } +} + +impl FromIterator for AppendOnlyVec { + fn from_iter>(iter: T) -> Self { + let this = Self::new(); + for val in iter { + this.push(val); + } + this + } +} diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 5c2435a0122e..6c8d54146315 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -224,7 +224,7 @@ impl UnordSet { } #[inline] - pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator> { + pub fn items(&self) -> UnordItems<&V, impl Iterator> { UnordItems(self.inner.iter()) } @@ -415,7 +415,7 @@ impl UnordMap { } #[inline] - pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator> { + pub fn items(&self) -> UnordItems<(&K, &V), impl Iterator> { UnordItems(self.inner.iter()) } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b96b356f5517..730d41ab962f 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -44,8 +44,10 @@ use rustc_session::{early_error, early_error_no_abort, early_warn}; use rustc_span::source_map::{FileLoader, FileName}; use rustc_span::symbol::sym; use rustc_target::json::ToJson; +use rustc_target::spec::{Target, TargetTriple}; use std::cmp::max; +use std::collections::BTreeMap; use std::env; use std::ffi::OsString; use std::fs; @@ -648,6 +650,15 @@ fn print_crate_info( TargetSpec => { println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); } + AllTargetSpecs => { + let mut targets = BTreeMap::new(); + for name in rustc_target::spec::TARGETS { + let triple = TargetTriple::from_triple(name); + let target = Target::expect_builtin(&triple); + targets.insert(name, target.to_json()); + } + println!("{}", serde_json::to_string_pretty(&targets).unwrap()); + } FileNames | CrateName => { let Some(attrs) = attrs.as_ref() else { // no crate attributes, print out an error and exit diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 9ed8ab67431c..e09ef34b93db 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -956,7 +956,7 @@ impl Diagnostic { // Exact iteration order of diagnostic arguments shouldn't make a difference to output because // they're only used in interpolation. #[allow(rustc::potential_query_instability)] - pub fn args<'a>(&'a self) -> impl Iterator> { + pub fn args(&self) -> impl Iterator> { self.args.iter() } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 4b1ff0e1df94..81e8bcbf7cd5 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1407,7 +1407,7 @@ impl EmitterWriter { // Account for newlines to align output to its label. for (line, text) in normalize_whitespace(&text).lines().enumerate() { buffer.append( - 0 + line, + line, &format!( "{}{}", if line == 0 { String::new() } else { " ".repeat(label_width) }, @@ -1918,7 +1918,7 @@ impl EmitterWriter { let last_line = unhighlighted_lines.pop(); let first_line = unhighlighted_lines.drain(..).next(); - first_line.map(|(p, l)| { + if let Some((p, l)) = first_line { self.draw_code_line( &mut buffer, &mut row_num, @@ -1930,12 +1930,12 @@ impl EmitterWriter { &file_lines, is_multiline, ) - }); + } buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber); row_num += 1; - last_line.map(|(p, l)| { + if let Some((p, l)) = last_line { self.draw_code_line( &mut buffer, &mut row_num, @@ -1947,7 +1947,7 @@ impl EmitterWriter { &file_lines, is_multiline, ) - }); + } } } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 8a16143311b8..264f30fb10a1 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -620,10 +620,15 @@ impl<'a> ExtCtxt<'a> { span: Span, name: Ident, ty: P, - mutbl: ast::Mutability, + mutability: ast::Mutability, expr: P, ) -> P { - self.item(span, name, AttrVec::new(), ast::ItemKind::Static(ty, mutbl, Some(expr))) + self.item( + span, + name, + AttrVec::new(), + ast::ItemKind::Static(ast::StaticItem { ty, mutability, expr: Some(expr) }.into()), + ) } pub fn item_const( @@ -633,8 +638,13 @@ impl<'a> ExtCtxt<'a> { ty: P, expr: P, ) -> P { - let def = ast::Defaultness::Final; - self.item(span, name, AttrVec::new(), ast::ItemKind::Const(def, ty, Some(expr))) + let defaultness = ast::Defaultness::Final; + self.item( + span, + name, + AttrVec::new(), + ast::ItemKind::Const(ast::ConstItem { defaultness, ty, expr: Some(expr) }.into()), + ) } // Builds `#[name]`. diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index a78dc0678d5d..4ff8e409d88e 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -466,7 +466,7 @@ impl<'a> StripUnconfigured<'a> { // // N.B., this is intentionally not part of the visit_expr() function // in order for filter_map_expr() to be able to avoid this check - if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(*a)) { + if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { self.sess.emit_err(RemoveExprNotSupported { span: attr.span }); } diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index de34df0114a7..fb3a00d86d4f 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -41,7 +41,7 @@ impl MetaVarExpr { }; check_trailing_token(&mut tts, sess)?; let mut iter = args.trees(); - let rslt = match &*ident.as_str() { + let rslt = match ident.as_str() { "count" => parse_count(&mut iter, sess, ident.span)?, "ignore" => MetaVarExpr::Ignore(parse_ident(&mut iter, sess, ident.span)?), "index" => MetaVarExpr::Index(parse_depth(&mut iter, sess, ident.span)?), diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 84114b27f415..426c6727adca 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -518,6 +518,8 @@ declare_features! ( /// Allows dyn upcasting trait objects via supertraits. /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`. (active, trait_upcasting, "1.56.0", Some(65991), None), + /// Allows for transmuting between arrays with sizes that contain generic consts. + (active, transmute_generic_consts, "CURRENT_RUSTC_VERSION", Some(109929), None), /// Allows #[repr(transparent)] on unions (RFC 2645). (active, transparent_unions, "1.37.0", Some(60405), None), /// Allows inconsistent bounds in where clauses. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index eac8fd294293..8f91a96f964a 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -49,7 +49,7 @@ impl LanguageItems { self.get(it).ok_or_else(|| LangItemError(it)) } - pub fn iter<'a>(&'a self) -> impl Iterator + 'a { + pub fn iter(&self) -> impl Iterator + '_ { self.items .iter() .enumerate() diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index e870aa543d0b..838c123f83c8 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -2,7 +2,6 @@ use crate::def::{CtorOf, DefKind, Res}; use crate::def_id::DefId; use crate::hir::{self, BindingAnnotation, ByRef, HirId, PatKind}; use rustc_data_structures::fx::FxHashSet; -use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -136,14 +135,4 @@ impl hir::Pat<'_> { }); result } - - /// If the pattern is `Some()` from a desugared for loop, returns the inner pattern - pub fn for_loop_some(&self) -> Option<&Self> { - if self.span.desugaring_kind() == Some(DesugaringKind::ForLoop) { - if let hir::PatKind::Struct(_, [pat_field], _) = self.kind { - return Some(pat_field.pat); - } - } - None - } } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index a57f39878491..1d7965ff5f66 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -189,3 +189,39 @@ hir_analysis_return_type_notation_equality_bound = hir_analysis_return_type_notation_missing_method = cannot find associated function `{$assoc_name}` in trait `{$trait_name}` + +hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind} + .label = not allowed in type signatures + +hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters + .suggestion = use a fully qualified path with inferred lifetimes + +hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes + +hir_analysis_enum_discriminant_overflowed = enum discriminant overflowed + .label = overflowed on value after {$discr} + .note = explicitly set `{$item_name} = {$wrapped_discr}` if that is desired outcome + +hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation + .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it + +hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args + +hir_analysis_must_be_name_of_associated_function = must be a name of an associated function + +hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation + .note = required by this annotation + +hir_analysis_must_implement_not_function = not a function + +hir_analysis_must_implement_not_function_span_note = required by this annotation + +hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names + +hir_analysis_function_not_found_in_trait = function not found in this trait + +hir_analysis_functions_names_duplicated = functions names are duplicated + .note = all `#[rustc_must_implement_one_of]` arguments must be unique + +hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is highly experimental and may result in invalid code + .help = add `#![feature(simd_ffi)]` to the crate attributes to enable diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index e25b07d93922..acca3fa26418 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -33,9 +33,9 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; -use rustc_middle::ty::DynKind; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{DynKind, ToPredicate}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; @@ -1526,8 +1526,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { for (base_trait_ref, span, constness) in regular_traits_refs_spans { assert_eq!(constness, ty::BoundConstness::NotConst); - - for pred in traits::elaborate_trait_ref(tcx, base_trait_ref) { + let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx); + for pred in traits::elaborate(tcx, [base_pred]) { debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred); let bound_predicate = pred.kind(); @@ -2336,10 +2336,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { FnMutDelegate { regions: &mut |_| tcx.lifetimes.re_erased, types: &mut |bv| { - tcx.mk_placeholder(ty::PlaceholderType { universe, name: bv.kind }) + tcx.mk_placeholder(ty::PlaceholderType { universe, bound: bv }) }, consts: &mut |bv, ty| { - tcx.mk_const(ty::PlaceholderConst { universe, name: bv }, ty) + tcx.mk_const(ty::PlaceholderConst { universe, bound: bv }, ty) }, }, ); @@ -2525,11 +2525,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { regions: &mut |_| tcx.lifetimes.re_erased, types: &mut |bv| tcx.mk_placeholder(ty::PlaceholderType { universe, - name: bv.kind, + bound: bv, }), consts: &mut |bv, ty| tcx.mk_const(ty::PlaceholderConst { universe, - name: bv + bound: bv, }, ty), }) ) 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 2d509a114ad2..f6c2004c4a67 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2034,7 +2034,7 @@ pub(super) fn check_type_bounds<'tcx>( ObligationCause::new(impl_ty_span, impl_ty_def_id, code) }; - let obligations = tcx + let obligations: Vec<_> = tcx .bound_explicit_item_bounds(trait_ty.def_id) .subst_iter_copied(tcx, rebased_substs) .map(|(concrete_ty_bound, span)| { @@ -2044,7 +2044,7 @@ pub(super) fn check_type_bounds<'tcx>( .collect(); debug!("check_type_bounds: item_bounds={:?}", obligations); - for mut obligation in util::elaborate_obligations(tcx, obligations) { + for mut obligation in util::elaborate(tcx, obligations) { let normalized_predicate = ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate); debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 2bb724138f58..111bf5e54555 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -253,10 +253,6 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> { self.tcx } - fn intercrate(&self) -> bool { - false - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } @@ -269,10 +265,6 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> { true } - fn mark_ambiguous(&mut self) { - bug!() - } - fn relate_with_variance>( &mut self, _: ty::Variance, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 1b7475486dce..854974d1605a 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -139,14 +139,14 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let name_str = intrinsic_name.as_str(); let bound_vars = tcx.mk_bound_variable_kinds(&[ - ty::BoundVariableKind::Region(ty::BrAnon(0, None)), + ty::BoundVariableKind::Region(ty::BrAnon(None)), ty::BoundVariableKind::Region(ty::BrEnv), ]); let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { let region = tcx.mk_re_late_bound( ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) }, + ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }, ); let env_region = tcx.mk_re_late_bound( ty::INNERMOST, @@ -387,8 +387,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ); let discriminant_def_id = assoc_items[0]; - let br = - ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) }; + let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; ( 1, vec![tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0))], @@ -440,8 +439,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), sym::raw_eq => { - let br = - ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) }; + let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; let param_ty = tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0)); (1, vec![param_ty; 2], tcx.types.bool) } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 24cc58ee3449..c03621fcfb22 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1908,7 +1908,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { let predicates_with_span = tcx.predicates_of(self.body_def_id).predicates.iter().copied(); // Check elaborated bounds. - let implied_obligations = traits::elaborate_predicates_with_span(tcx, predicates_with_span); + let implied_obligations = traits::elaborate(tcx, predicates_with_span); for (pred, obligation_span) in implied_obligations { // We lower empty bounds like `Vec:` as diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index 7bca4edcc8c9..ad76e2bed202 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -302,7 +302,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { .iter() .flatten() .map(|r| r.impl_blocks.len() as isize - avg as isize) - .map(|v| v.abs() as usize) + .map(|v| v.unsigned_abs()) .sum::(); s / connected_regions.len() }, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index c41e96290df1..50862e342623 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -20,7 +20,7 @@ use crate::errors; use hir::def::DefKind; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; @@ -333,17 +333,7 @@ fn bad_placeholder<'tcx>( let kind = if kind.ends_with('s') { format!("{}es", kind) } else { format!("{}s", kind) }; spans.sort(); - let mut err = struct_span_err!( - tcx.sess, - spans.clone(), - E0121, - "the placeholder `_` is not allowed within types on item signatures for {}", - kind - ); - for span in spans { - err.span_label(span, "not allowed in type signatures"); - } - err + tcx.sess.create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind }) } impl<'tcx> ItemCtxt<'tcx> { @@ -419,13 +409,8 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { self.tcx().mk_projection(item_def_id, item_substs) } else { // There are no late-bound regions; we can just ignore the binder. - let mut err = struct_span_err!( - self.tcx().sess, - span, - E0212, - "cannot use the associated type of a trait \ - with uninferred generic parameters" - ); + let (mut mpart_sugg, mut inferred_sugg) = (None, None); + let mut bound = String::new(); match self.node() { hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => { @@ -444,31 +429,25 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { (bound.span.shrink_to_lo(), format!("{}, ", lt_name)) } }; - let suggestions = vec![ - (lt_sp, sugg), - ( - span.with_hi(item_segment.ident.span.lo()), - format!( - "{}::", - // Replace the existing lifetimes with a new named lifetime. - self.tcx.replace_late_bound_regions_uncached( - poly_trait_ref, - |_| { - self.tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: item_def_id, - index: 0, - name: Symbol::intern(<_name), - }) - } - ), + mpart_sugg = Some(errors::AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion { + fspan: lt_sp, + first: sugg, + sspan: span.with_hi(item_segment.ident.span.lo()), + second: format!( + "{}::", + // Replace the existing lifetimes with a new named lifetime. + self.tcx.replace_late_bound_regions_uncached( + poly_trait_ref, + |_| { + self.tcx.mk_re_early_bound(ty::EarlyBoundRegion { + def_id: item_def_id, + index: 0, + name: Symbol::intern(<_name), + }) + } ), ), - ]; - err.multipart_suggestion( - "use a fully qualified path with explicit lifetimes", - suggestions, - Applicability::MaybeIncorrect, - ); + }); } _ => {} } @@ -482,20 +461,23 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { | hir::Node::ForeignItem(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => { - err.span_suggestion_verbose( - span.with_hi(item_segment.ident.span.lo()), - "use a fully qualified path with inferred lifetimes", - format!( - "{}::", - // Erase named lt, we want `::C`, not `::C`. - self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(), - ), - Applicability::MaybeIncorrect, + inferred_sugg = Some(span.with_hi(item_segment.ident.span.lo())); + bound = format!( + "{}::", + // Erase named lt, we want `::C`, not `::C`. + self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(), ); } _ => {} } - self.tcx().ty_error(err.emit()) + self.tcx().ty_error(self.tcx().sess.emit_err( + errors::AssociatedTypeTraitUninferredGenericParams { + span, + inferred_sugg, + bound, + mpart_sugg, + }, + )) } } @@ -763,14 +745,12 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { Some(discr) } else { let span = tcx.def_span(variant.def_id); - struct_span_err!(tcx.sess, span, E0370, "enum discriminant overflowed") - .span_label(span, format!("overflowed on value after {}", prev_discr.unwrap())) - .note(&format!( - "explicitly set `{} = {}` if that is desired outcome", - tcx.item_name(variant.def_id), - wrapped_discr - )) - .emit(); + tcx.sess.emit_err(errors::EnumDiscriminantOverflowed { + span, + discr: prev_discr.unwrap().to_string(), + item_name: tcx.item_name(variant.def_id), + wrapped_discr: wrapped_discr.to_string(), + }); None } .unwrap_or(wrapped_discr), @@ -915,14 +895,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar); if paren_sugar && !tcx.features().unboxed_closures { - tcx.sess - .struct_span_err( - item.span, - "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ - which traits can use parenthetical notation", - ) - .help("add `#![feature(unboxed_closures)]` to the crate attributes to use it") - .emit(); + tcx.sess.emit_err(errors::ParenSugarAttribute { span: item.span }); } let is_marker = tcx.has_attr(def_id, sym::marker); @@ -942,13 +915,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { // and that they are all identifiers .and_then(|attr| match attr.meta_item_list() { Some(items) if items.len() < 2 => { - tcx.sess - .struct_span_err( - attr.span, - "the `#[rustc_must_implement_one_of]` attribute must be \ - used with at least 2 args", - ) - .emit(); + tcx.sess.emit_err(errors::MustImplementOneOfAttribute { span: attr.span }); None } @@ -957,9 +924,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { .map(|item| item.ident().ok_or(item.span())) .collect::, _>>() .map_err(|span| { - tcx.sess - .struct_span_err(span, "must be a name of an associated function") - .emit(); + tcx.sess.emit_err(errors::MustBeNameOfAssociatedFunction { span }); }) .ok() .zip(Some(attr.span)), @@ -975,13 +940,10 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { match item { Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => { if !tcx.impl_defaultness(item.id.owner_id).has_value() { - tcx.sess - .struct_span_err( - item.span, - "function doesn't have a default implementation", - ) - .span_note(attr_span, "required by this annotation") - .emit(); + tcx.sess.emit_err(errors::FunctionNotHaveDefaultImplementation { + span: item.span, + note_span: attr_span, + }); return Some(()); } @@ -989,19 +951,14 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { return None; } Some(item) => { - tcx.sess - .struct_span_err(item.span, "not a function") - .span_note(attr_span, "required by this annotation") - .note( - "all `#[rustc_must_implement_one_of]` arguments must be associated \ - function names", - ) - .emit(); + tcx.sess.emit_err(errors::MustImplementNotFunction { + span: item.span, + span_note: errors::MustImplementNotFunctionSpanNote { span: attr_span }, + note: errors::MustImplementNotFunctionNote {}, + }); } None => { - tcx.sess - .struct_span_err(ident.span, "function not found in this trait") - .emit(); + tcx.sess.emit_err(errors::FunctionNotFoundInTrait { span: ident.span }); } } @@ -1018,9 +975,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { for ident in &*list { if let Some(dup) = set.insert(ident.name, ident.span) { tcx.sess - .struct_span_err(vec![dup, ident.span], "functions names are duplicated") - .note("all `#[rustc_must_implement_one_of]` arguments must be unique") - .emit(); + .emit_err(errors::FunctionNamesDuplicated { spans: vec![dup, ident.span] }); no_dups = false; } @@ -1485,17 +1440,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( .source_map() .span_to_snippet(ast_ty.span) .map_or_else(|_| String::new(), |s| format!(" `{}`", s)); - tcx.sess - .struct_span_err( - ast_ty.span, - &format!( - "use of SIMD type{} in FFI is highly experimental and \ - may result in invalid code", - snip - ), - ) - .help("add `#![feature(simd_ffi)]` to the crate attributes to enable") - .emit(); + tcx.sess.emit_err(errors::SIMDFFIHighlyExperimental { span: ast_ty.span, snip }); } }; for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) { diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index d2e45c28658b..2e56d24638cd 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -130,7 +130,7 @@ pub(super) fn item_bounds( tcx: TyCtxt<'_>, def_id: DefId, ) -> ty::EarlyBinder<&'_ ty::List>> { - let bounds = tcx.mk_predicates_from_iter(util::elaborate_predicates( + let bounds = tcx.mk_predicates_from_iter(util::elaborate( tcx, tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound), )); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index c71ce9a0bc7c..2a3a683489dd 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -507,3 +507,127 @@ pub(crate) struct ReturnTypeNotationMissingMethod { pub trait_name: Symbol, pub assoc_name: Symbol, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = "E0121")] +pub(crate) struct PlaceholderNotAllowedItemSignatures { + #[primary_span] + #[label] + pub spans: Vec, + pub kind: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_associated_type_trait_uninferred_generic_params, code = "E0212")] +pub(crate) struct AssociatedTypeTraitUninferredGenericParams { + #[primary_span] + pub span: Span, + #[suggestion(style = "verbose", applicability = "maybe-incorrect", code = "{bound}")] + pub inferred_sugg: Option, + pub bound: String, + #[subdiagnostic] + pub mpart_sugg: Option, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion, + applicability = "maybe-incorrect" +)] +pub(crate) struct AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion { + #[suggestion_part(code = "{first}")] + pub fspan: Span, + pub first: String, + #[suggestion_part(code = "{second}")] + pub sspan: Span, + pub second: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_enum_discriminant_overflowed, code = "E0370")] +#[note] +pub(crate) struct EnumDiscriminantOverflowed { + #[primary_span] + #[label] + pub span: Span, + pub discr: String, + pub item_name: Symbol, + pub wrapped_discr: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_paren_sugar_attribute)] +#[help] +pub(crate) struct ParenSugarAttribute { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_must_implement_one_of_attribute)] +pub(crate) struct MustImplementOneOfAttribute { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_must_be_name_of_associated_function)] +pub(crate) struct MustBeNameOfAssociatedFunction { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_function_not_have_default_implementation)] +pub(crate) struct FunctionNotHaveDefaultImplementation { + #[primary_span] + pub span: Span, + #[note] + pub note_span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_must_implement_not_function)] +pub(crate) struct MustImplementNotFunction { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub span_note: MustImplementNotFunctionSpanNote, + #[subdiagnostic] + pub note: MustImplementNotFunctionNote, +} + +#[derive(Subdiagnostic)] +#[note(hir_analysis_must_implement_not_function_span_note)] +pub(crate) struct MustImplementNotFunctionSpanNote { + #[primary_span] + pub span: Span, +} + +#[derive(Subdiagnostic)] +#[note(hir_analysis_must_implement_not_function_note)] +pub(crate) struct MustImplementNotFunctionNote {} + +#[derive(Diagnostic)] +#[diag(hir_analysis_function_not_found_in_trait)] +pub(crate) struct FunctionNotFoundInTrait { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_functions_names_duplicated)] +#[note] +pub(crate) struct FunctionNamesDuplicated { + #[primary_span] + pub spans: Vec, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_simd_ffi_highly_experimental)] +#[help] +pub(crate) struct SIMDFFIHighlyExperimental { + #[primary_span] + pub span: Span, + pub snip: String, +} diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index b5bae5788f6b..35785e81ff49 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -318,15 +318,14 @@ fn check_predicates<'tcx>( span: Span, ) { let instantiated = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs); - let impl1_predicates: Vec<_> = - traits::elaborate_predicates_with_span(tcx, instantiated.into_iter()).collect(); + let impl1_predicates: Vec<_> = traits::elaborate(tcx, instantiated.into_iter()).collect(); let mut impl2_predicates = if impl2_node.is_from_trait() { // Always applicable traits have to be always applicable without any // assumptions. Vec::new() } else { - traits::elaborate_predicates( + traits::elaborate( tcx, tcx.predicates_of(impl2_node.def_id()) .instantiate(tcx, impl2_substs) @@ -371,11 +370,10 @@ fn check_predicates<'tcx>( .unwrap(); assert!(!obligations.needs_infer()); - impl2_predicates.extend( - traits::elaborate_obligations(tcx, obligations).map(|obligation| obligation.predicate), - ) + impl2_predicates + .extend(traits::elaborate(tcx, obligations).map(|obligation| obligation.predicate)) } - impl2_predicates.extend(traits::elaborate_predicates(tcx, always_applicable_traits)); + impl2_predicates.extend(traits::elaborate(tcx, always_applicable_traits)); for (predicate, span) in impl1_predicates { if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(tcx, predicate, *pred2, span)) { diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 2a9025d60aba..27e56180349e 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -70,7 +70,6 @@ This API is completely unstable and subject to change. #![feature(lazy_cell)] #![feature(slice_partition_dedup)] #![feature(try_blocks)] -#![feature(is_some_and)] #![feature(type_alias_impl_trait)] #![recursion_limit = "256"] diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 4f27c01fad2c..74f5b359021d 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -242,7 +242,7 @@ pub fn enum_def_to_string( impl<'a> State<'a> { pub fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) { self.maybe_print_comment(span.hi()); - self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize)); + self.break_offset_if_not_bol(1, -INDENT_UNIT); self.word("}"); if close_box { self.end(); // close the outer-box diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 035ccf30b246..6c2ce62722a5 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -538,8 +538,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(rpitit): This will need to be fixed when we move to associated types assert!(matches!( *trait_pred.trait_ref.self_ty().kind(), - ty::Alias(_, ty::AliasTy { def_id, substs, .. }) - if def_id == rpit_def_id && substs == substs + ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) + if def_id == rpit_def_id && substs == alias_substs )); ty::PredicateKind::Clause(ty::Clause::Trait( trait_pred.with_self_ty(self.tcx, ty), @@ -548,8 +548,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => { assert!(matches!( *proj_pred.projection_ty.self_ty().kind(), - ty::Alias(_, ty::AliasTy { def_id, substs, .. }) - if def_id == rpit_def_id && substs == substs + ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) + if def_id == rpit_def_id && substs == alias_substs )); proj_pred = proj_pred.with_self_ty(self.tcx, ty); ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred)) diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 47a8b0801664..15eec42d7864 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -204,7 +204,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut expected_sig = None; let mut expected_kind = None; - for (pred, span) in traits::elaborate_predicates_with_span( + for (pred, span) in traits::elaborate( self.tcx, // Reverse the obligations here, since `elaborate_*` uses a stack, // and we want to keep inference generally in the same order of diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index c17aae22ba54..68e096e3bd02 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2810,23 +2810,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "cannot index into a value of type `{base_t}`", ); // Try to give some advice about indexing tuples. - if let ty::Tuple(..) = base_t.kind() { + if let ty::Tuple(types) = base_t.kind() { let mut needs_note = true; // If the index is an integer, we can show the actual // fixed expression: - if let ExprKind::Lit(ref lit) = idx.kind { - if let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node { - let snip = self.tcx.sess.source_map().span_to_snippet(base.span); - if let Ok(snip) = snip { - err.span_suggestion( - expr.span, - "to access tuple elements, use", - format!("{snip}.{i}"), - Applicability::MachineApplicable, - ); - needs_note = false; - } + if let ExprKind::Lit(ref lit) = idx.kind + && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node + && i < types.len().try_into().expect("expected tuple index to be < usize length") + { + let snip = self.tcx.sess.source_map().span_to_snippet(base.span); + if let Ok(snip) = snip { + err.span_suggestion( + expr.span, + "to access tuple elements, use", + format!("{snip}.{i}"), + Applicability::MachineApplicable, + ); + needs_note = false; } + } else if let ExprKind::Path(..) = idx.peel_borrows().kind { + err.span_label(idx.span, "cannot access tuple elements at a variable index"); } if needs_note { err.help( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 7534e432f119..3e0c2bf2a553 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -242,8 +242,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(arg) = segment .args() .args - .iter() - .nth(index) else { return false; }; + .get(index) else { return false; }; error.obligation.cause.span = arg .span() .find_ancestor_in_same_ctxt(error.obligation.cause.span) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 61338ac613ae..b02eae19fce1 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -31,7 +31,7 @@ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, IsSuggestable, Ty}; use rustc_session::Session; use rustc_span::symbol::{kw, Ident}; -use rustc_span::{self, sym, Span}; +use rustc_span::{self, sym, BytePos, Span}; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::iter; @@ -894,8 +894,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut errors = errors.into_iter().peekable(); + let mut only_extras_so_far = errors + .peek() + .map_or(false, |first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0)); let mut suggestions = vec![]; while let Some(error) = errors.next() { + only_extras_so_far &= matches!(error, Error::Extra(_)); + match error { Error::Invalid(provided_idx, expected_idx, compatibility) => { let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; @@ -941,10 +946,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if arg_idx.index() > 0 && let Some((_, prev)) = provided_arg_tys .get(ProvidedIdx::from_usize(arg_idx.index() - 1) - ) { - // Include previous comma - span = prev.shrink_to_hi().to(span); - } + ) { + // Include previous comma + span = prev.shrink_to_hi().to(span); + } + + // Is last argument for deletion in a row starting from the 0-th argument? + // Then delete the next comma, so we are not left with `f(, ...)` + // + // fn f() {} + // - f(0, 1,) + // + f() + if only_extras_so_far + && errors + .peek() + .map_or(true, |next_error| !matches!(next_error, Error::Extra(_))) + { + let next = provided_arg_tys + .get(arg_idx + 1) + .map(|&(_, sp)| sp) + .unwrap_or_else(|| { + // Subtract one to move before `)` + call_expr.span.with_lo(call_expr.span.hi() - BytePos(1)) + }); + + // Include next comma + span = span.until(next); + } + suggestions.push((span, String::new())); suggestion_text = match suggestion_text { diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs index 1eeb7d984ee0..3e9a9ce1b311 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs @@ -526,8 +526,9 @@ impl DropRangesBuilder { let mut next = <_>::from(0u32); for value in tracked_values { for_each_consumable(hir, value, |value| { - if !tracked_value_map.contains_key(&value) { - tracked_value_map.insert(value, next); + if let std::collections::hash_map::Entry::Vacant(e) = tracked_value_map.entry(value) + { + e.insert(next); next = next + 1; } }); diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 9ecc870a70db..5faa6ab13dd7 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -240,7 +240,7 @@ pub fn resolve_interior<'a, 'tcx>( let mut counter = 0; let mut mk_bound_region = |span| { - let kind = ty::BrAnon(counter, span); + let kind = ty::BrAnon(span); let var = ty::BoundVar::from_u32(counter); counter += 1; ty::BoundRegion { var, kind } @@ -263,7 +263,7 @@ pub fn resolve_interior<'a, 'tcx>( } ty::ReLateBound(_, ty::BoundRegion { kind, .. }) | ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind { - ty::BoundRegionKind::BrAnon(_, span) => mk_bound_region(span), + ty::BoundRegionKind::BrAnon(span) => mk_bound_region(span), ty::BoundRegionKind::BrNamed(def_id, _) => { mk_bound_region(Some(fcx.tcx.def_span(def_id))) } @@ -294,7 +294,7 @@ pub fn resolve_interior<'a, 'tcx>( FnMutDelegate { regions: &mut |br| { let kind = match br.kind { - ty::BrAnon(_, span) => ty::BrAnon(counter, span), + ty::BrAnon(span) => ty::BrAnon(span), _ => br.kind, }; let var = ty::BoundVar::from_usize(bound_vars.len()); @@ -313,8 +313,7 @@ pub fn resolve_interior<'a, 'tcx>( // Extract type components to build the witness type. let type_list = fcx.tcx.mk_type_list_from_iter(type_causes.iter().map(|cause| cause.ty)); let bound_vars = fcx.tcx.mk_bound_variable_kinds(&bound_vars); - let witness = - fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone())); + let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars)); drop(typeck_results); // Store the generator types and spans into the typeck results for this generator. diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 901acffe1c8c..106f5bcd7558 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -84,6 +84,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let skeleton_string = |ty: Ty<'tcx>, sk| match sk { Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()), Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"), + Ok(SizeSkeleton::Generic(size)) => { + if let Some(size) = size.try_eval_target_usize(tcx, self.param_env) { + format!("{size} bytes") + } else { + format!("generic size {size}") + } + } Err(LayoutError::Unknown(bad)) => { if bad == ty { "this type does not have a fixed size".to_owned() diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 2762e778591e..9155a3d8daa1 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -574,7 +574,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ) -> Option { let sized_def_id = self.tcx.lang_items().sized_trait()?; - traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied()) + traits::elaborate(self.tcx, predicates.predicates.iter().copied()) // We don't care about regions here. .filter_map(|pred| match pred.kind().skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index dab709e17f05..08cd6085d7f3 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -793,6 +793,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // a `&self` method will wind up with an argument type like `&dyn Trait`. let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { + if new_trait_ref.has_non_region_late_bound() { + this.tcx.sess.delay_span_bug( + this.span, + "tried to select method from HRTB with non-lifetime bound vars", + ); + return; + } + let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); let (xform_self_ty, xform_ret_ty) = @@ -843,18 +851,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { - let trait_ref = this.erase_late_bound_regions(poly_trait_ref); + let trait_ref = this.instantiate_binder_with_fresh_vars( + this.span, + infer::LateBoundRegionConversionTime::FnCall, + poly_trait_ref, + ); let (xform_self_ty, xform_ret_ty) = this.xform_self_ty(item, trait_ref.self_ty(), trait_ref.substs); - // Because this trait derives from a where-clause, it - // should not contain any inference variables or other - // artifacts. This means it is safe to put into the - // `WhereClauseCandidate` and (eventually) into the - // `WhereClausePick`. - assert!(!trait_ref.substs.needs_infer()); - this.push_candidate( Candidate { xform_self_ty, @@ -964,7 +969,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { bound_trait_ref.def_id(), )); } else { - let new_trait_ref = self.erase_late_bound_regions(bound_trait_ref); + let new_trait_ref = self.instantiate_binder_with_fresh_vars( + self.span, + infer::LateBoundRegionConversionTime::FnCall, + bound_trait_ref, + ); let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.substs); @@ -1555,8 +1564,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; let parent_o = o.clone(); - let implied_obligations = - traits::elaborate_obligations(self.tcx, vec![o]); + let implied_obligations = traits::elaborate(self.tcx, vec![o]); for o in implied_obligations { let parent = if o == parent_o { None @@ -1756,7 +1764,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn probe_for_similar_candidate(&mut self) -> Result, MethodError<'tcx>> { debug!("probing for method names similar to {:?}", self.method_name); - let steps = self.steps.clone(); self.probe(|_| { let mut pcx = ProbeContext::new( self.fcx, @@ -1764,8 +1771,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.mode, self.method_name, self.return_type, - &self.orig_steps_var_values, - steps, + self.orig_steps_var_values, + self.steps, self.scope_expr_id, ); pcx.allow_similar_names = true; diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 241535b29c5f..af0bd26dec5f 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -37,6 +37,10 @@ pointers. If you encounter this error you should try to avoid dereferencing the You can read more about trait objects in the Trait Objects section of the Reference: \ https://doc.rust-lang.org/reference/types.html#trait-objects"; +fn is_number(text: &str) -> bool { + text.chars().all(|c: char| c.is_digit(10)) +} + /// Information about the expected type at the top level of type checking a pattern. /// /// **NOTE:** This is only for use by diagnostics. Do NOT use for type checking logic! @@ -1673,7 +1677,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::PatField<'tcx>], variant: &ty::VariantDef, ) -> Option> { - if let (Some(CtorKind::Fn), PatKind::Struct(qpath, ..)) = (variant.ctor_kind(), &pat.kind) { + if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) = + (variant.ctor_kind(), &pat.kind) + { + let is_tuple_struct_match = !pattern_fields.is_empty() + && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number); + if is_tuple_struct_match { + return None; + } + let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { s.print_qpath(qpath, false) }); @@ -1895,7 +1907,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prefix, unmentioned_fields .iter() - .map(|(_, name)| name.to_string()) + .map(|(_, name)| { + let field_name = name.to_string(); + if is_number(&field_name) { + format!("{}: _", field_name) + } else { + field_name + } + }) .collect::>() .join(", "), if have_inaccessible_fields { ", .." } else { "" }, diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index eba5b3ed882a..271ab830694b 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1850,7 +1850,7 @@ impl SparseBitMatrix { /// Iterates through all the columns set to true in a given row of /// the matrix. - pub fn iter<'a>(&'a self, row: R) -> impl Iterator + 'a { + pub fn iter(&self, row: R) -> impl Iterator + '_ { self.row(row).into_iter().flat_map(|r| r.iter()) } diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 5945de2302a5..ae2f52c513e9 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -24,6 +24,7 @@ pub trait Idx: Copy + 'static + Eq + PartialEq + Debug + Hash { } #[inline] + #[must_use = "Use `increment_by` if you wanted to update the index in-place"] fn plus(self, amount: usize) -> Self { Self::new(self.index() + amount) } @@ -129,6 +130,17 @@ impl IndexVec { IndexVec { raw: Vec::with_capacity(capacity), _marker: PhantomData } } + /// Creates a new vector with a copy of `elem` for each index in `universe`. + /// + /// Thus `IndexVec::from_elem(elem, &universe)` is equivalent to + /// `IndexVec::::from_elem_n(elem, universe.len())`. That can help + /// type inference as it ensures that the resulting vector uses the same + /// index type as `universe`, rather than something potentially surprising. + /// + /// For example, if you want to store data for each local in a MIR body, + /// using `let mut uses = IndexVec::from_elem(vec![], &body.local_decls);` + /// ensures that `uses` is an `IndexVec`, and thus can give + /// better error messages later if one accidentally mismatches indices. #[inline] pub fn from_elem(elem: T, universe: &IndexSlice) -> Self where @@ -189,18 +201,15 @@ impl IndexVec { } #[inline] - pub fn drain<'a, R: RangeBounds>( - &'a mut self, - range: R, - ) -> impl Iterator + 'a { + pub fn drain>(&mut self, range: R) -> impl Iterator + '_ { self.raw.drain(range) } #[inline] - pub fn drain_enumerated<'a, R: RangeBounds>( - &'a mut self, + pub fn drain_enumerated>( + &mut self, range: R, - ) -> impl Iterator + 'a { + ) -> impl Iterator + '_ { let begin = match range.start_bound() { std::ops::Bound::Included(i) => *i, std::ops::Bound::Excluded(i) => i.checked_add(1).unwrap(), @@ -283,6 +292,11 @@ impl ToOwned for IndexSlice { } impl IndexSlice { + #[inline] + pub fn empty() -> &'static Self { + Default::default() + } + #[inline] pub fn from_raw(raw: &[T]) -> &Self { let ptr: *const [T] = raw; @@ -398,6 +412,36 @@ impl IndexSlice { } } +impl IndexSlice { + /// Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`, + /// assuming the values in `self` are a permutation of `0..self.len()`. + /// + /// This is used to go between `memory_index` (source field order to memory order) + /// and `inverse_memory_index` (memory order to source field order). + /// See also `FieldsShape::Arbitrary::memory_index` for more details. + // FIXME(eddyb) build a better abstraction for permutations, if possible. + pub fn invert_bijective_mapping(&self) -> IndexVec { + debug_assert_eq!( + self.iter().map(|x| x.index() as u128).sum::(), + (0..self.len() as u128).sum::(), + "The values aren't 0..N in input {self:?}", + ); + + let mut inverse = IndexVec::from_elem_n(Idx::new(0), self.len()); + for (i1, &i2) in self.iter_enumerated() { + inverse[i2] = i1; + } + + debug_assert_eq!( + inverse.iter().map(|x| x.index() as u128).sum::(), + (0..inverse.len() as u128).sum::(), + "The values aren't 0..N in result {self:?}", + ); + + inverse + } +} + /// `IndexVec` is often used as a map, so it provides some map-like APIs. impl IndexVec> { #[inline] @@ -502,6 +546,13 @@ impl FromIterator for IndexVec { } } +impl From<[T; N]> for IndexVec { + #[inline] + fn from(array: [T; N]) -> Self { + IndexVec::from_raw(array.into()) + } +} + impl IntoIterator for IndexVec { type Item = T; type IntoIter = vec::IntoIter; diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 15780898dc6a..1e43644be89a 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -30,8 +30,8 @@ infer_source_kind_subdiag_let = {$kind -> }{$x_kind -> [has_name] , where the {$prefix_kind -> *[type] type for {$prefix} - [const_with_param] the value of const parameter - [const] the value of the constant + [const_with_param] value of const parameter + [const] value of the constant } `{$arg_name}` is specified [underscore] , where the placeholders `_` are specified *[empty] {""} diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index ef543b1fb935..30f6af74b83e 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -90,9 +90,8 @@ impl<'a> DescriptionCtx<'a> { }; me.span = Some(sp); } - ty::BrAnon(idx, span) => { - me.kind = "anon_num_here"; - me.num_arg = idx+1; + ty::BrAnon(span) => { + me.kind = "defined_here"; me.span = match span { Some(_) => span, None => Some(tcx.def_span(scope)), diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 3bbd01f82736..e808911a38b1 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -772,7 +772,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { let var = self.canonical_var(info, r.into()); - let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32(), None) }; + let br = ty::BoundRegion { var, kind: ty::BrAnon(None) }; self.interner().mk_re_late_bound(self.binder_index, br) } diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index ce230afdab3c..fbb2257bf67c 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -125,9 +125,9 @@ impl<'tcx> InferCtxt<'tcx> { ty.into() } - CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, name }) => { + CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound }) => { let universe_mapped = universe_map(universe); - let placeholder_mapped = ty::PlaceholderType { universe: universe_mapped, name }; + let placeholder_mapped = ty::PlaceholderType { universe: universe_mapped, bound }; self.tcx.mk_placeholder(placeholder_mapped).into() } @@ -138,9 +138,9 @@ impl<'tcx> InferCtxt<'tcx> { ) .into(), - CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, name }) => { + CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, bound }) => { let universe_mapped = universe_map(universe); - let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, name }; + let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, bound }; self.tcx.mk_re_placeholder(placeholder_mapped).into() } @@ -152,9 +152,9 @@ impl<'tcx> InferCtxt<'tcx> { ) .into(), - CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, name }, ty) => { + CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }, ty) => { let universe_mapped = universe_map(universe); - let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name }; + let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound }; self.tcx.mk_const(placeholder_mapped, ty).into() } } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 88a28e26005d..fe45b5ebe61b 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -137,6 +137,18 @@ impl<'tcx> InferCtxt<'tcx> { Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b))) } + // During coherence, opaque types should be treated as *possibly* + // equal to each other, even if their generic params differ, as + // they could resolve to the same hidden type, even for different + // generic params. + ( + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), + ) if self.intercrate && a_def_id == b_def_id => { + relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]); + Ok(a) + } + _ => ty::relate::super_relate_tys(relation, a, b), } } @@ -505,10 +517,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, to_pred) })) } - - pub fn mark_ambiguous(&mut self) { - self.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]); - } } struct Generalizer<'cx, 'tcx> { @@ -581,10 +589,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { self.infcx.tcx } - fn intercrate(&self) -> bool { - self.infcx.intercrate - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } @@ -597,10 +601,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { true } - fn mark_ambiguous(&mut self) { - span_bug!(self.cause.span, "opaque types are handled in `tys`"); - } - fn binders( &mut self, a: ty::Binder<'tcx, T>, diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 38002357cde3..fe4a2dd38007 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -35,10 +35,6 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { self.fields.tcx() } - fn intercrate(&self) -> bool { - self.fields.infcx.intercrate - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } @@ -47,10 +43,6 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { self.a_is_expected } - fn mark_ambiguous(&mut self) { - self.fields.mark_ambiguous(); - } - fn relate_item_substs( &mut self, _item_def_id: DefId, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index d53e64830ff3..86fca9797d02 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -170,15 +170,15 @@ fn msg_span_from_named_region<'tcx>( } ty::ReStatic => ("the static lifetime".to_owned(), alt_span), ty::RePlaceholder(ty::PlaceholderRegion { - name: ty::BoundRegionKind::BrNamed(def_id, name), + bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, name), .. }, .. }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))), ty::RePlaceholder(ty::PlaceholderRegion { - name: ty::BoundRegionKind::BrAnon(_, Some(span)), + bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon(Some(span)), .. }, .. }) => (format!("the anonymous lifetime defined here"), Some(span)), ty::RePlaceholder(ty::PlaceholderRegion { - name: ty::BoundRegionKind::BrAnon(_, None), + bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon(None), .. }, .. }) => (format!("an anonymous lifetime"), None), _ => bug!("{:?}", region), @@ -226,8 +226,8 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>( }; (text, sp) } - ty::BrAnon(idx, span) => ( - format!("the anonymous lifetime #{} defined here", idx + 1), + ty::BrAnon(span) => ( + "the anonymous lifetime as defined here".to_string(), match span { Some(span) => span, None => tcx.def_span(scope) @@ -2697,11 +2697,6 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { self.0.tcx } - fn intercrate(&self) -> bool { - assert!(!self.0.intercrate); - false - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { // Unused, only for consts which we treat as always equal ty::ParamEnv::empty() @@ -2715,10 +2710,6 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { true } - fn mark_ambiguous(&mut self) { - bug!() - } - fn relate_with_variance>( &mut self, _variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index bde16fad8216..d7b900ca02d3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1191,11 +1191,14 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { have_turbofish, } = args; let generics = tcx.generics_of(generics_def_id); - if let Some(argument_index) = generics + if let Some(mut argument_index) = generics .own_substs(substs) .iter() .position(|&arg| self.generic_arg_contains_target(arg)) { + if generics.parent.is_none() && generics.has_self { + argument_index += 1; + } let substs = self.infcx.resolve_vars_if_possible(substs); let generic_args = &generics.own_substs_no_defaults(tcx, substs) [generics.own_counts().lifetimes..]; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs index e8d94f0c04ea..8a78a1956c99 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs @@ -16,22 +16,34 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { match &self.error { Some(RegionResolutionError::ConcreteFailure( SubregionOrigin::RelateRegionParamBound(span), - Region(Interned(RePlaceholder(ty::Placeholder { name: sub_name, .. }), _)), - Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)), + Region(Interned( + RePlaceholder(ty::Placeholder { + bound: ty::BoundRegion { kind: sub_name, .. }, + .. + }), + _, + )), + Region(Interned( + RePlaceholder(ty::Placeholder { + bound: ty::BoundRegion { kind: sup_name, .. }, + .. + }), + _, + )), )) => { let span = *span; let (sub_span, sub_symbol) = match sub_name { ty::BrNamed(def_id, symbol) => { (Some(self.tcx().def_span(def_id)), Some(symbol)) } - ty::BrAnon(_, span) => (*span, None), + ty::BrAnon(span) => (*span, None), ty::BrEnv => (None, None), }; let (sup_span, sup_symbol) = match sup_name { ty::BrNamed(def_id, symbol) => { (Some(self.tcx().def_span(def_id)), Some(symbol)) } - ty::BrAnon(_, span) => (*span, None), + ty::BrAnon(span) => (*span, None), ty::BrEnv => (None, None), }; let diag = match (sub_span, sup_span, sub_symbol, sup_symbol) { diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 6395c4d4b207..2f659d9a6652 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -29,11 +29,6 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { "Glb" } - fn intercrate(&self) -> bool { - assert!(!self.fields.infcx.intercrate); - false - } - fn tcx(&self) -> TyCtxt<'tcx> { self.fields.tcx() } @@ -46,10 +41,6 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { self.a_is_expected } - fn mark_ambiguous(&mut self) { - bug!("mark_ambiguous used outside of coherence"); - } - fn relate_with_variance>( &mut self, variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index d1897cf24b4a..a63cfbc919c6 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -82,20 +82,20 @@ impl<'tcx> InferCtxt<'tcx> { let delegate = FnMutDelegate { regions: &mut |br: ty::BoundRegion| { - self.tcx.mk_re_placeholder(ty::PlaceholderRegion { - universe: next_universe, - name: br.kind, - }) + self.tcx + .mk_re_placeholder(ty::PlaceholderRegion { universe: next_universe, bound: br }) }, types: &mut |bound_ty: ty::BoundTy| { self.tcx.mk_placeholder(ty::PlaceholderType { universe: next_universe, - name: bound_ty.kind, + bound: bound_ty, }) }, consts: &mut |bound_var: ty::BoundVar, ty| { - self.tcx - .mk_const(ty::PlaceholderConst { universe: next_universe, name: bound_var }, ty) + self.tcx.mk_const( + ty::PlaceholderConst { universe: next_universe, bound: bound_var }, + ty, + ) }, }; diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 9e2bdb7f510b..f298b95ca35b 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -203,7 +203,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // Tracks the `VarSubVar` constraints generated for each region vid. We // later use this to expand across vids. - let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len()); + let mut constraints = IndexVec::from_elem(Vec::new(), &var_values.values); // Tracks the changed region vids. let mut changes = Vec::new(); for constraint in self.data.constraints.keys() { diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index 98cbd4c561c5..e41ec7e6c010 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -29,11 +29,6 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { "Lub" } - fn intercrate(&self) -> bool { - assert!(!self.fields.infcx.intercrate); - false - } - fn tcx(&self) -> TyCtxt<'tcx> { self.fields.tcx() } @@ -46,10 +41,6 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { self.a_is_expected } - fn mark_ambiguous(&mut self) { - bug!("mark_ambiguous used outside of coherence"); - } - fn relate_with_variance>( &mut self, variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 9903ffa90bae..b4f2ad0bb343 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -2130,13 +2130,17 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>( fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { if let ty::Infer(_) = t.kind() { + let idx = { + let idx = self.idx; + self.idx += 1; + idx + }; self.tcx.mk_placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, - name: ty::BoundTyKind::Anon({ - let idx = self.idx; - self.idx += 1; - idx - }), + bound: ty::BoundTy { + var: ty::BoundVar::from_u32(idx), + kind: ty::BoundTyKind::Anon, + }, }) } else { t.super_fold_with(self) @@ -2153,7 +2157,7 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>( self.tcx.mk_const( ty::PlaceholderConst { universe: ty::UniverseIndex::ROOT, - name: ty::BoundVar::from_u32({ + bound: ty::BoundVar::from_u32({ let idx = self.idx; self.idx += 1; idx diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index f5d20cb7ebfe..9f7b26b87f45 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -296,7 +296,7 @@ where universe }); - let placeholder = ty::PlaceholderRegion { universe, name: br.kind }; + let placeholder = ty::PlaceholderRegion { universe, bound: br }; debug!(?placeholder); let placeholder_reg = nll_delegate.next_placeholder_region(placeholder); debug!(?placeholder_reg); @@ -443,10 +443,6 @@ where self.infcx.tcx } - fn intercrate(&self) -> bool { - self.infcx.intercrate - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.delegate.param_env() } @@ -459,17 +455,6 @@ where true } - fn mark_ambiguous(&mut self) { - let cause = ObligationCause::dummy_with_span(self.delegate.span()); - let param_env = self.delegate.param_env(); - self.delegate.register_obligations(vec![Obligation::new( - self.tcx(), - cause, - param_env, - ty::Binder::dummy(ty::PredicateKind::Ambiguous), - )]); - } - #[instrument(skip(self, info), level = "trace", ret)] fn relate_with_variance>( &mut self, @@ -834,11 +819,6 @@ where self.infcx.tcx } - fn intercrate(&self) -> bool { - assert!(!self.infcx.intercrate); - false - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.delegate.param_env() } @@ -851,10 +831,6 @@ where true } - fn mark_ambiguous(&mut self) { - bug!() - } - fn relate_with_variance>( &mut self, variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 3c6cc2b90010..01f900f050ee 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -137,10 +137,6 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { "Match" } - fn intercrate(&self) -> bool { - false - } - fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -151,10 +147,6 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { true } // irrelevant - fn mark_ambiguous(&mut self) { - bug!() - } - #[instrument(level = "trace", skip(self))] fn relate_with_variance>( &mut self, diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 89ada23c6673..b8ba98fc0a9f 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -290,9 +290,9 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> { ) -> TypeError<'tcx> { debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region); if self.overly_polymorphic { - TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region) + TypeError::RegionsOverlyPolymorphic(placeholder.bound.kind, other_region) } else { - TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region) + TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound.kind, other_region) } } } diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index fc73ca7606d2..0dd73a6e999e 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -35,10 +35,6 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { "Sub" } - fn intercrate(&self) -> bool { - self.fields.infcx.intercrate - } - fn tcx(&self) -> TyCtxt<'tcx> { self.fields.infcx.tcx } @@ -51,10 +47,6 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { self.a_is_expected } - fn mark_ambiguous(&mut self) { - self.fields.mark_ambiguous() - } - fn with_cause(&mut self, cause: Cause, f: F) -> R where F: FnOnce(&mut Self) -> R, diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index f3797499866a..c7f7ed149407 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,7 +1,7 @@ use smallvec::smallvec; use crate::infer::outlives::components::{push_outlives_components, Component}; -use crate::traits::{self, Obligation, ObligationCause, PredicateObligation}; +use crate::traits::{self, Obligation, PredicateObligation}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_middle::ty::{self, ToPredicate, TyCtxt}; use rustc_span::symbol::Ident; @@ -66,99 +66,129 @@ impl<'tcx> Extend> for PredicateSet<'tcx> { /// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd` /// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that /// `T: Foo`, then we know that `T: 'static`. -pub struct Elaborator<'tcx> { - stack: Vec>, +pub struct Elaborator<'tcx, O> { + stack: Vec, visited: PredicateSet<'tcx>, } -pub fn elaborate_trait_ref<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, -) -> impl Iterator> { - elaborate_predicates(tcx, std::iter::once(trait_ref.without_const().to_predicate(tcx))) +/// Describes how to elaborate an obligation into a sub-obligation. +/// +/// For [`Obligation`], a sub-obligation is combined with the current obligation's +/// param-env and cause code. For [`ty::Predicate`], none of this is needed, since +/// there is no param-env or cause code to copy over. +pub trait Elaboratable<'tcx> { + fn predicate(&self) -> ty::Predicate<'tcx>; + + // Makes a new `Self` but with a different predicate. + fn child(&self, predicate: ty::Predicate<'tcx>) -> Self; + + // Makes a new `Self` but with a different predicate and a different cause + // code (if `Self` has one). + fn child_with_derived_cause( + &self, + predicate: ty::Predicate<'tcx>, + span: Span, + parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + index: usize, + ) -> Self; } -pub fn elaborate_trait_refs<'tcx>( - tcx: TyCtxt<'tcx>, - trait_refs: impl Iterator>, -) -> impl Iterator> { - let predicates = trait_refs.map(move |trait_ref| trait_ref.without_const().to_predicate(tcx)); - elaborate_predicates(tcx, predicates) +impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> { + fn predicate(&self) -> ty::Predicate<'tcx> { + self.predicate + } + + fn child(&self, predicate: ty::Predicate<'tcx>) -> Self { + Obligation { + cause: self.cause.clone(), + param_env: self.param_env, + recursion_depth: 0, + predicate, + } + } + + fn child_with_derived_cause( + &self, + predicate: ty::Predicate<'tcx>, + span: Span, + parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + index: usize, + ) -> Self { + let cause = self.cause.clone().derived_cause(parent_trait_pred, |derived| { + traits::ImplDerivedObligation(Box::new(traits::ImplDerivedObligationCause { + derived, + impl_or_alias_def_id: parent_trait_pred.def_id(), + impl_def_predicate_index: Some(index), + span, + })) + }); + Obligation { cause, param_env: self.param_env, recursion_depth: 0, predicate } + } } -pub fn elaborate_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - predicates: impl Iterator>, -) -> impl Iterator> { - elaborate_obligations( - tcx, - predicates - .map(|predicate| { - Obligation::new( - tcx, - // We'll dump the cause/param-env later - ObligationCause::dummy(), - ty::ParamEnv::empty(), - predicate, - ) - }) - .collect(), - ) - .map(|obl| obl.predicate) +impl<'tcx> Elaboratable<'tcx> for ty::Predicate<'tcx> { + fn predicate(&self) -> ty::Predicate<'tcx> { + *self + } + + fn child(&self, predicate: ty::Predicate<'tcx>) -> Self { + predicate + } + + fn child_with_derived_cause( + &self, + predicate: ty::Predicate<'tcx>, + _span: Span, + _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + _index: usize, + ) -> Self { + predicate + } } -pub fn elaborate_predicates_with_span<'tcx>( - tcx: TyCtxt<'tcx>, - predicates: impl Iterator, Span)>, -) -> impl Iterator, Span)> { - elaborate_obligations( - tcx, - predicates - .map(|(predicate, span)| { - Obligation::new( - tcx, - // We'll dump the cause/param-env later - ObligationCause::dummy_with_span(span), - ty::ParamEnv::empty(), - predicate, - ) - }) - .collect(), - ) - .map(|obl| (obl.predicate, obl.cause.span)) +impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) { + fn predicate(&self) -> ty::Predicate<'tcx> { + self.0 + } + + fn child(&self, predicate: ty::Predicate<'tcx>) -> Self { + (predicate, self.1) + } + + fn child_with_derived_cause( + &self, + predicate: ty::Predicate<'tcx>, + _span: Span, + _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + _index: usize, + ) -> Self { + (predicate, self.1) + } } -pub fn elaborate_obligations<'tcx>( +pub fn elaborate<'tcx, O: Elaboratable<'tcx>>( tcx: TyCtxt<'tcx>, - obligations: Vec>, -) -> Elaborator<'tcx> { + obligations: impl IntoIterator, +) -> Elaborator<'tcx, O> { let mut elaborator = Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx) }; elaborator.extend_deduped(obligations); elaborator } -fn predicate_obligation<'tcx>( - predicate: ty::Predicate<'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, -) -> PredicateObligation<'tcx> { - Obligation { cause, param_env, recursion_depth: 0, predicate } -} - -impl<'tcx> Elaborator<'tcx> { - fn extend_deduped(&mut self, obligations: impl IntoIterator>) { +impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { + fn extend_deduped(&mut self, obligations: impl IntoIterator) { // Only keep those bounds that we haven't already seen. // This is necessary to prevent infinite recursion in some // cases. One common case is when people define // `trait Sized: Sized { }` rather than `trait Sized { }`. // let visited = &mut self.visited; - self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate))); + self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate()))); } - fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) { + fn elaborate(&mut self, elaboratable: &O) { let tcx = self.visited.tcx; - let bound_predicate = obligation.predicate.kind(); + let bound_predicate = elaboratable.predicate().kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { // Get predicates declared on the trait. @@ -170,24 +200,11 @@ impl<'tcx> Elaborator<'tcx> { if data.constness == ty::BoundConstness::NotConst { pred = pred.without_const(tcx); } - - let cause = obligation.cause.clone().derived_cause( - bound_predicate.rebind(data), - |derived| { - traits::ImplDerivedObligation(Box::new( - traits::ImplDerivedObligationCause { - derived, - impl_or_alias_def_id: data.def_id(), - impl_def_predicate_index: Some(index), - span, - }, - )) - }, - ); - predicate_obligation( + elaboratable.child_with_derived_cause( pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)), - obligation.param_env, - cause, + span, + bound_predicate.rebind(data), + index, ) }); debug!(?data, ?obligations, "super_predicates"); @@ -290,13 +307,7 @@ impl<'tcx> Elaborator<'tcx> { .map(|predicate_kind| { bound_predicate.rebind(predicate_kind).to_predicate(tcx) }) - .map(|predicate| { - predicate_obligation( - predicate, - obligation.param_env, - obligation.cause.clone(), - ) - }), + .map(|predicate| elaboratable.child(predicate)), ); } ty::PredicateKind::TypeWellFormedFromEnv(..) => { @@ -313,8 +324,8 @@ impl<'tcx> Elaborator<'tcx> { } } -impl<'tcx> Iterator for Elaborator<'tcx> { - type Item = PredicateObligation<'tcx>; +impl<'tcx, O: Elaboratable<'tcx>> Iterator for Elaborator<'tcx, O> { + type Item = O; fn size_hint(&self) -> (usize, Option) { (self.stack.len(), None) @@ -339,17 +350,21 @@ pub fn supertraits<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> impl Iterator> { - FilterToTraits::new(elaborate_trait_ref(tcx, trait_ref)) + let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx); + FilterToTraits::new(elaborate(tcx, [pred])) } pub fn transitive_bounds<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator>, ) -> impl Iterator> { - FilterToTraits::new(elaborate_trait_refs(tcx, trait_refs)) + FilterToTraits::new(elaborate( + tcx, + trait_refs.map(|trait_ref| -> ty::Predicate<'tcx> { trait_ref.to_predicate(tcx) }), + )) } -/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may +/// A specialized variant of `elaborate` that only elaborates trait references that may /// define the given associated type `assoc_name`. It uses the /// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that /// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 413b40ab808e..0e4e20c7cd1d 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -230,7 +230,7 @@ fn configure_and_expand( features: Some(features), recursion_limit, trace_mac: sess.opts.unstable_opts.trace_macros, - should_test: sess.opts.test, + should_test: sess.is_test_crate(), span_debug: sess.opts.unstable_opts.span_debug, proc_macro_backtrace: sess.opts.unstable_opts.proc_macro_backtrace, ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) @@ -292,7 +292,7 @@ fn configure_and_expand( } sess.time("maybe_create_a_macro_crate", || { - let is_test_crate = sess.opts.test; + let is_test_crate = sess.is_test_crate(); rustc_builtin_macros::proc_macro_harness::inject( &mut krate, sess, @@ -765,7 +765,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { parallel!( { sess.time("match_checking", || { - tcx.hir().par_body_owners(|def_id| tcx.ensure().check_match(def_id.to_def_id())) + tcx.hir().par_body_owners(|def_id| tcx.ensure().check_match(def_id)) }); }, { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index d2293780836d..818f450a58c1 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -7,7 +7,7 @@ use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{AppendOnlyVec, Lrc, OnceCell, RwLock, WorkerLocal}; +use rustc_data_structures::sync::{AppendOnlyIndexVec, Lrc, OnceCell, RwLock, WorkerLocal}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_incremental::DepGraphFuture; @@ -215,7 +215,7 @@ impl<'tcx> Queries<'tcx> { let cstore = RwLock::new(Box::new(CStore::new(sess)) as _); let definitions = RwLock::new(Definitions::new(sess.local_stable_crate_id())); - let source_span = AppendOnlyVec::new(); + let source_span = AppendOnlyIndexVec::new(); let _id = source_span.push(krate.spans.inner_span); debug_assert_eq!(_id, CRATE_DEF_ID); let untracked = Untracked { cstore, source_span, definitions }; diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index eb5990507fb6..10dfd32d418a 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -5,6 +5,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_session::config::rustc_optgroups; +use rustc_session::config::DebugInfo; use rustc_session::config::Input; use rustc_session::config::InstrumentXRay; use rustc_session::config::TraitSolver; @@ -574,7 +575,7 @@ fn test_codegen_options_tracking_hash() { tracked!(code_model, Some(CodeModel::Large)); tracked!(control_flow_guard, CFGuard::Checks); tracked!(debug_assertions, Some(true)); - tracked!(debuginfo, 0xdeadbeef); + tracked!(debuginfo, DebugInfo::Limited); tracked!(embed_bitcode, false); tracked!(force_frame_pointers, Some(false)); tracked!(force_unwind_tables, Some(true)); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c1b247e3d615..6b387df785e7 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1947,7 +1947,7 @@ impl KeywordIdents { }; // Don't lint `r#foo`. - if cx.sess().parse_sess.raw_identifier_spans.borrow().contains(&ident.span) { + if cx.sess().parse_sess.raw_identifier_spans.contains(ident.span) { return; } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index a76229dd3524..a2a7c93a7ca9 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -266,12 +266,12 @@ impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> { let LintExpectationId::Stable { attr_id: Some(attr_id), hir_id, attr_index, .. } = id else { bug!("unstable expectation id should already be mapped") }; let key = LintExpectationId::Unstable { attr_id, lint_index: None }; - if !self.unstable_to_stable_ids.contains_key(&key) { - self.unstable_to_stable_ids.insert( - key, - LintExpectationId::Stable { hir_id, attr_index, lint_index: None, attr_id: None }, - ); - } + self.unstable_to_stable_ids.entry(key).or_insert(LintExpectationId::Stable { + hir_id, + attr_index, + lint_index: None, + attr_id: None, + }); self.expectations.push((id.normalize(), expectation)); } diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index 3045fc1a4761..4c25d94a1f37 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -2,9 +2,9 @@ use crate::lints::CStringPtr; use crate::LateContext; use crate::LateLintPass; use crate::LintContext; -use rustc_hir::{Expr, ExprKind, PathSegment}; +use rustc_hir::{Expr, ExprKind}; use rustc_middle::ty; -use rustc_span::{symbol::sym, ExpnKind, Span}; +use rustc_span::{symbol::sym, Span}; declare_lint! { /// The `temporary_cstring_as_ptr` lint detects getting the inner pointer of @@ -34,47 +34,14 @@ declare_lint! { declare_lint_pass!(TemporaryCStringAsPtr => [TEMPORARY_CSTRING_AS_PTR]); -fn in_macro(span: Span) -> bool { - if span.from_expansion() { - !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..)) - } else { - false - } -} - -fn first_method_call<'tcx>( - expr: &'tcx Expr<'tcx>, -) -> Option<(&'tcx PathSegment<'tcx>, &'tcx Expr<'tcx>)> { - if let ExprKind::MethodCall(path, receiver, args, ..) = &expr.kind { - if args.iter().any(|e| e.span.from_expansion()) || receiver.span.from_expansion() { - None - } else { - Some((path, *receiver)) - } - } else { - None - } -} - impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if in_macro(expr.span) { - return; - } - - match first_method_call(expr) { - Some((path, unwrap_arg)) if path.ident.name == sym::as_ptr => { - let as_ptr_span = path.ident.span; - match first_method_call(unwrap_arg) { - Some((path, receiver)) - if path.ident.name == sym::unwrap || path.ident.name == sym::expect => - { - lint_cstring_as_ptr(cx, as_ptr_span, receiver, unwrap_arg); - } - _ => return, - } - } - _ => return, + if let ExprKind::MethodCall(as_ptr_path, as_ptr_receiver, ..) = expr.kind + && as_ptr_path.ident.name == sym::as_ptr + && let ExprKind::MethodCall(unwrap_path, unwrap_receiver, ..) = as_ptr_receiver.kind + && (unwrap_path.ident.name == sym::unwrap || unwrap_path.ident.name == sym::expect) + { + lint_cstring_as_ptr(cx, as_ptr_path.ident.span, unwrap_receiver, as_ptr_receiver); } } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 42e59f92840e..35c461f5acee 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -12,7 +12,7 @@ use rustc_errors::{pluralize, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_infer::traits::util::elaborate_predicates_with_span; +use rustc_infer::traits::util::elaborate; use rustc_middle::ty::adjustment; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::Symbol; @@ -254,24 +254,21 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } ty::Adt(def, _) => is_def_must_use(cx, def.did(), span), ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { - elaborate_predicates_with_span( - cx.tcx, - cx.tcx.explicit_item_bounds(def).iter().cloned(), - ) - .find_map(|(pred, _span)| { - // We only look at the `DefId`, so it is safe to skip the binder here. - if let ty::PredicateKind::Clause(ty::Clause::Trait( - ref poly_trait_predicate, - )) = pred.kind().skip_binder() - { - let def_id = poly_trait_predicate.trait_ref.def_id; + elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned()) + .find_map(|(pred, _span)| { + // We only look at the `DefId`, so it is safe to skip the binder here. + if let ty::PredicateKind::Clause(ty::Clause::Trait( + ref poly_trait_predicate, + )) = pred.kind().skip_binder() + { + let def_id = poly_trait_predicate.trait_ref.def_id; - is_def_must_use(cx, def_id, span) - } else { - None - } - }) - .map(|inner| MustUsePath::Opaque(Box::new(inner))) + is_def_must_use(cx, def_id, span) + } else { + None + } + }) + .map(|inner| MustUsePath::Opaque(Box::new(inner))) } ty::Dynamic(binders, _, _) => binders.iter().find_map(|predicate| { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() @@ -805,7 +802,9 @@ trait UnusedDelimLint { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { use ast::ItemKind::*; - if let Const(.., Some(expr)) | Static(.., Some(expr)) = &item.kind { + if let Const(box ast::ConstItem { expr: Some(expr), .. }) + | Static(box ast::StaticItem { expr: Some(expr), .. }) = &item.kind + { self.check_unused_delims_expr( cx, expr, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index e3493caaaf74..cadb6b1e23fe 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -152,10 +152,6 @@ LLVMRustInsertPrivateGlobal(LLVMModuleRef M, LLVMTypeRef Ty) { nullptr)); } -extern "C" LLVMTypeRef LLVMRustMetadataTypeInContext(LLVMContextRef C) { - return wrap(Type::getMetadataTy(*unwrap(C))); -} - static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { switch (Kind) { case AlwaysInline: @@ -480,11 +476,6 @@ extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints, #endif } -extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm, - size_t AsmLen) { - unwrap(M)->appendModuleInlineAsm(StringRef(Asm, AsmLen)); -} - typedef DIBuilder *LLVMRustDIBuilderRef; template DIT *unwrapDIPtr(LLVMMetadataRef Ref) { @@ -682,6 +673,7 @@ enum class LLVMRustDebugEmissionKind { NoDebug, FullDebug, LineTablesOnly, + DebugDirectivesOnly, }; static DICompileUnit::DebugEmissionKind fromRust(LLVMRustDebugEmissionKind Kind) { @@ -692,6 +684,8 @@ static DICompileUnit::DebugEmissionKind fromRust(LLVMRustDebugEmissionKind Kind) return DICompileUnit::DebugEmissionKind::FullDebug; case LLVMRustDebugEmissionKind::LineTablesOnly: return DICompileUnit::DebugEmissionKind::LineTablesOnly; + case LLVMRustDebugEmissionKind::DebugDirectivesOnly: + return DICompileUnit::DebugEmissionKind::DebugDirectivesOnly; default: report_fatal_error("bad DebugEmissionKind."); } @@ -750,10 +744,6 @@ extern "C" bool LLVMRustHasModuleFlag(LLVMModuleRef M, const char *Name, return unwrap(M)->getModuleFlag(StringRef(Name, Len)) != nullptr; } -extern "C" LLVMValueRef LLVMRustMetadataAsValue(LLVMContextRef C, LLVMMetadataRef MD) { - return wrap(MetadataAsValue::get(*unwrap(C), unwrap(MD))); -} - extern "C" void LLVMRustGlobalAddMetadata( LLVMValueRef Global, unsigned Kind, LLVMMetadataRef MD) { unwrap(Global)->addMetadata(Kind, *unwrap(MD)); @@ -1150,6 +1140,8 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef V, } // LLVMArrayType function does not support 64-bit ElementCount +// FIXME: replace with LLVMArrayType2 when bumped minimal version to llvm-17 +// https://github.com/llvm/llvm-project/commit/35276f16e5a2cae0dfb49c0fbf874d4d2f177acc extern "C" LLVMTypeRef LLVMRustArrayType(LLVMTypeRef ElementTy, uint64_t ElementCount) { return wrap(ArrayType::get(unwrap(ElementTy), ElementCount)); @@ -1405,61 +1397,6 @@ extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, return true; } -extern "C" LLVMValueRef LLVMRustBuildCleanupPad(LLVMBuilderRef B, - LLVMValueRef ParentPad, - unsigned ArgCount, - LLVMValueRef *LLArgs, - const char *Name) { - Value **Args = unwrap(LLArgs); - if (ParentPad == nullptr) { - Type *Ty = Type::getTokenTy(unwrap(B)->getContext()); - ParentPad = wrap(Constant::getNullValue(Ty)); - } - return wrap(unwrap(B)->CreateCleanupPad( - unwrap(ParentPad), ArrayRef(Args, ArgCount), Name)); -} - -extern "C" LLVMValueRef LLVMRustBuildCleanupRet(LLVMBuilderRef B, - LLVMValueRef CleanupPad, - LLVMBasicBlockRef UnwindBB) { - CleanupPadInst *Inst = cast(unwrap(CleanupPad)); - return wrap(unwrap(B)->CreateCleanupRet(Inst, unwrap(UnwindBB))); -} - -extern "C" LLVMValueRef -LLVMRustBuildCatchPad(LLVMBuilderRef B, LLVMValueRef ParentPad, - unsigned ArgCount, LLVMValueRef *LLArgs, const char *Name) { - Value **Args = unwrap(LLArgs); - return wrap(unwrap(B)->CreateCatchPad( - unwrap(ParentPad), ArrayRef(Args, ArgCount), Name)); -} - -extern "C" LLVMValueRef LLVMRustBuildCatchRet(LLVMBuilderRef B, - LLVMValueRef Pad, - LLVMBasicBlockRef BB) { - return wrap(unwrap(B)->CreateCatchRet(cast(unwrap(Pad)), - unwrap(BB))); -} - -extern "C" LLVMValueRef LLVMRustBuildCatchSwitch(LLVMBuilderRef B, - LLVMValueRef ParentPad, - LLVMBasicBlockRef BB, - unsigned NumHandlers, - const char *Name) { - if (ParentPad == nullptr) { - Type *Ty = Type::getTokenTy(unwrap(B)->getContext()); - ParentPad = wrap(Constant::getNullValue(Ty)); - } - return wrap(unwrap(B)->CreateCatchSwitch(unwrap(ParentPad), unwrap(BB), - NumHandlers, Name)); -} - -extern "C" void LLVMRustAddHandler(LLVMValueRef CatchSwitchRef, - LLVMBasicBlockRef Handler) { - Value *CatchSwitch = unwrap(CatchSwitchRef); - cast(CatchSwitch)->addHandler(unwrap(Handler)); -} - extern "C" OperandBundleDef *LLVMRustBuildOperandBundleDef(const char *Name, LLVMValueRef *Inputs, unsigned NumInputs) { @@ -1624,6 +1561,7 @@ extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMSetLinkage(V, fromRust(RustLinkage)); } +// FIXME: replace with LLVMConstInBoundsGEP2 when bumped minimal version to llvm-14 extern "C" LLVMValueRef LLVMRustConstInBoundsGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal, LLVMValueRef *ConstantIndices, @@ -1701,12 +1639,6 @@ extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef V) { return toRust(LLVMGetVisibility(V)); } -// Oh hey, a binding that makes sense for once? (because LLVM’s own do not) -extern "C" LLVMValueRef LLVMRustBuildIntCast(LLVMBuilderRef B, LLVMValueRef Val, - LLVMTypeRef DestTy, bool isSigned) { - return wrap(unwrap(B)->CreateIntCast(unwrap(Val), unwrap(DestTy), isSigned, "")); -} - extern "C" void LLVMRustSetVisibility(LLVMValueRef V, LLVMRustVisibility RustVisibility) { LLVMSetVisibility(V, fromRust(RustVisibility)); diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 8542dcf5bf0f..ec3cf34d7109 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -30,7 +30,7 @@ pub unsafe extern "C" fn LLVMRustStringWriteImpl( ptr: *const c_char, size: size_t, ) { - let slice = slice::from_raw_parts(ptr as *const u8, size as usize); + let slice = slice::from_raw_parts(ptr as *const u8, size); sr.bytes.borrow_mut().extend_from_slice(slice); } diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index 22924efa9484..21f6a404a015 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -83,7 +83,7 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> { .with_verbose_exit(verbose_entry_exit) .with_verbose_entry(verbose_entry_exit) .with_indent_amount(2); - #[cfg(parallel_compiler)] + #[cfg(all(parallel_compiler, debug_assertions))] let layer = layer.with_thread_ids(true).with_thread_names(true); let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index 547c8debb505..745983e7e869 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -10,8 +10,8 @@ proc-macro = true annotate-snippets = "0.9" fluent-bundle = "0.15.2" fluent-syntax = "0.11" -synstructure = "0.12.1" -syn = { version = "1", features = ["full"] } +synstructure = "0.13.0" +syn = { version = "2", features = ["full"] } proc-macro2 = "1" quote = "1" unic-langid = { version = "0.9.0", features = ["macros"] } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 7fbe3bc2888c..4540ded0f41a 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -1,8 +1,7 @@ #![deny(unused_must_use)] use crate::diagnostics::error::{ - invalid_nested_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, - DiagnosticDeriveError, + span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError, }; use crate::diagnostics::utils::{ build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error, @@ -11,9 +10,8 @@ use crate::diagnostics::utils::{ }; use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote}; -use syn::{ - parse_quote, spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path, Type, -}; +use syn::Token; +use syn::{parse_quote, spanned::Spanned, Attribute, Meta, Path, Type}; use synstructure::{BindingInfo, Structure, VariantInfo}; /// What kind of diagnostic is being derived - a fatal/error/warning or a lint? @@ -77,7 +75,7 @@ impl DiagnosticDeriveBuilder { match ast.data { syn::Data::Struct(..) | syn::Data::Enum(..) => (), syn::Data::Union(..) => { - span_err(span, "diagnostic derives can only be used on structs and enums"); + span_err(span, "diagnostic derives can only be used on structs and enums").emit(); } } @@ -121,7 +119,7 @@ impl DiagnosticDeriveBuilder { impl<'a> DiagnosticDeriveVariantBuilder<'a> { /// Generates calls to `code` and similar functions based on the attributes on the type or /// variant. - pub fn preamble<'s>(&mut self, variant: &VariantInfo<'s>) -> TokenStream { + pub fn preamble(&mut self, variant: &VariantInfo<'_>) -> TokenStream { let ast = variant.ast(); let attrs = &ast.attrs; let preamble = attrs.iter().map(|attr| { @@ -135,7 +133,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { /// Generates calls to `span_label` and similar functions based on the attributes on fields or /// calls to `set_arg` when no attributes are present. - pub fn body<'s>(&mut self, variant: &VariantInfo<'s>) -> TokenStream { + pub fn body(&mut self, variant: &VariantInfo<'_>) -> TokenStream { let mut body = quote! {}; // Generate `set_arg` calls first.. for binding in variant.bindings().iter().filter(|bi| should_generate_set_arg(bi.ast())) { @@ -160,8 +158,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { }; if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag { - let meta = attr.parse_meta()?; - throw_invalid_attr!(attr, &meta, |diag| diag + throw_invalid_attr!(attr, |diag| diag .help("consider creating a `Subdiagnostic` instead")); } @@ -191,71 +188,44 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { return Ok(quote! {}); } - let name = attr.path.segments.last().unwrap().ident.to_string(); + let name = attr.path().segments.last().unwrap().ident.to_string(); let name = name.as_str(); - let meta = attr.parse_meta()?; + + let mut first = true; if name == "diag" { - let Meta::List(MetaList { ref nested, .. }) = meta else { - throw_invalid_attr!( - attr, - &meta - ); - }; - - let mut nested_iter = nested.into_iter().peekable(); - - match nested_iter.peek() { - Some(NestedMeta::Meta(Meta::Path(slug))) => { - self.slug.set_once(slug.clone(), slug.span().unwrap()); - nested_iter.next(); - } - Some(NestedMeta::Meta(Meta::NameValue { .. })) => {} - Some(nested_attr) => throw_invalid_nested_attr!(attr, nested_attr, |diag| diag - .help("a diagnostic slug is required as the first argument")), - None => throw_invalid_attr!(attr, &meta, |diag| diag - .help("a diagnostic slug is required as the first argument")), - }; - - // Remaining attributes are optional, only `code = ".."` at the moment. let mut tokens = TokenStream::new(); - for nested_attr in nested_iter { - let (value, path) = match nested_attr { - NestedMeta::Meta(Meta::NameValue(MetaNameValue { - lit: syn::Lit::Str(value), - path, - .. - })) => (value, path), - NestedMeta::Meta(Meta::Path(_)) => { - invalid_nested_attr(attr, nested_attr) - .help("diagnostic slug must be the first argument") - .emit(); - continue; - } - _ => { - invalid_nested_attr(attr, nested_attr).emit(); - continue; - } + attr.parse_nested_meta(|nested| { + let path = &nested.path; + + if first && (nested.input.is_empty() || nested.input.peek(Token![,])) { + self.slug.set_once(path.clone(), path.span().unwrap()); + first = false; + return Ok(()) + } + + first = false; + + let Ok(nested) = nested.value() else { + span_err(nested.input.span().unwrap(), "diagnostic slug must be the first argument").emit(); + return Ok(()) }; - let nested_name = path.segments.last().unwrap().ident.to_string(); - // Struct attributes are only allowed to be applied once, and the diagnostic - // changes will be set in the initialisation code. - let span = value.span().unwrap(); - match nested_name.as_str() { - "code" => { - self.code.set_once((), span); + if path.is_ident("code") { + self.code.set_once((), path.span().unwrap()); - let code = value.value(); - tokens.extend(quote! { - #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); - }); - } - _ => invalid_nested_attr(attr, nested_attr) - .help("only `code` is a valid nested attributes following the slug") - .emit(), + let code = nested.parse::()?; + tokens.extend(quote! { + #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); + }); + } else { + span_err(path.span().unwrap(), "unknown argument").note("only the `code` parameter is valid after the slug").emit(); + + // consume the buffer so we don't have syntax errors from syn + let _ = nested.parse::(); } - } + Ok(()) + })?; return Ok(tokens); } @@ -270,7 +240,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { Ok(self.add_subdiagnostic(&fn_ident, slug)) } SubdiagnosticKind::Label | SubdiagnosticKind::Suggestion { .. } => { - throw_invalid_attr!(attr, &meta, |diag| diag + throw_invalid_attr!(attr, |diag| diag .help("`#[label]` and `#[suggestion]` can only be applied to fields")); } SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(), @@ -309,7 +279,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { return quote! {}; } - let name = attr.path.segments.last().unwrap().ident.to_string(); + let name = attr.path().segments.last().unwrap().ident.to_string(); let needs_clone = name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_)); let (binding, needs_destructure) = if needs_clone { @@ -343,11 +313,10 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { binding: TokenStream, ) -> Result { let diag = &self.parent.diag; - let meta = attr.parse_meta()?; - let ident = &attr.path.segments.last().unwrap().ident; + let ident = &attr.path().segments.last().unwrap().ident; let name = ident.to_string(); - match (&meta, name.as_str()) { + match (&attr.meta, name.as_str()) { // Don't need to do anything - by virtue of the attribute existing, the // `set_arg` call will not be generated. (Meta::Path(_), "skip_arg") => return Ok(quote! {}), @@ -361,7 +330,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { }); } DiagnosticDeriveKind::LintDiagnostic => { - throw_invalid_attr!(attr, &meta, |diag| { + throw_invalid_attr!(attr, |diag| { diag.help("the `primary_span` field attribute is not valid for lint diagnostics") }) } @@ -378,26 +347,34 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { return Ok(quote! { #diag.subdiagnostic(#binding); }); } } - (Meta::List(MetaList { ref nested, .. }), "subdiagnostic") => { - if nested.len() == 1 - && let Some(NestedMeta::Meta(Meta::Path(path))) = nested.first() - && path.is_ident("eager") { - let handler = match &self.parent.kind { - DiagnosticDeriveKind::Diagnostic { handler } => handler, - DiagnosticDeriveKind::LintDiagnostic => { - throw_invalid_attr!(attr, &meta, |diag| { - diag.help("eager subdiagnostics are not supported on lints") - }) - } - }; - return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); }); - } else { - throw_invalid_attr!(attr, &meta, |diag| { - diag.help( - "`eager` is the only supported nested attribute for `subdiagnostic`", - ) - }) + (Meta::List(meta_list), "subdiagnostic") => { + let err = || { + span_err( + meta_list.span().unwrap(), + "`eager` is the only supported nested attribute for `subdiagnostic`", + ) + .emit(); + }; + + let Ok(p): Result = meta_list.parse_args() else { + err(); + return Ok(quote! {}); + }; + + if !p.is_ident("eager") { + err(); + return Ok(quote! {}); } + + let handler = match &self.parent.kind { + DiagnosticDeriveKind::Diagnostic { handler } => handler, + DiagnosticDeriveKind::LintDiagnostic => { + throw_invalid_attr!(attr, |diag| { + diag.help("eager subdiagnostics are not supported on lints") + }) + } + }; + return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); }); } _ => (), } @@ -432,7 +409,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { code_init, } => { if let FieldInnerTy::Vec(_) = info.ty { - throw_invalid_attr!(attr, &meta, |diag| { + throw_invalid_attr!(attr, |diag| { diag .note("`#[suggestion(...)]` applied to `Vec` field is ambiguous") .help("to show a suggestion consisting of multiple parts, use a `Subdiagnostic` annotated with `#[multipart_suggestion(...)]`") diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs index 2d62d5931638..b37dc826d288 100644 --- a/compiler/rustc_macros/src/diagnostics/error.rs +++ b/compiler/rustc_macros/src/diagnostics/error.rs @@ -1,7 +1,7 @@ use proc_macro::{Diagnostic, Level, MultiSpan}; use proc_macro2::TokenStream; use quote::quote; -use syn::{spanned::Spanned, Attribute, Error as SynError, Meta, NestedMeta}; +use syn::{spanned::Spanned, Attribute, Error as SynError, Meta}; #[derive(Debug)] pub(crate) enum DiagnosticDeriveError { @@ -53,6 +53,7 @@ fn path_to_string(path: &syn::Path) -> String { } /// Returns an error diagnostic on span `span` with msg `msg`. +#[must_use] pub(crate) fn span_err(span: impl MultiSpan, msg: &str) -> Diagnostic { Diagnostic::spanned(span, Level::Error, msg) } @@ -72,10 +73,10 @@ macro_rules! throw_span_err { pub(crate) use throw_span_err; /// Returns an error diagnostic for an invalid attribute. -pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic { +pub(crate) fn invalid_attr(attr: &Attribute) -> Diagnostic { let span = attr.span().unwrap(); - let path = path_to_string(&attr.path); - match meta { + let path = path_to_string(attr.path()); + match attr.meta { Meta::Path(_) => span_err(span, &format!("`#[{path}]` is not a valid attribute")), Meta::NameValue(_) => { span_err(span, &format!("`#[{path} = ...]` is not a valid attribute")) @@ -89,51 +90,11 @@ pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic { /// /// For methods that return a `Result<_, DiagnosticDeriveError>`: macro_rules! throw_invalid_attr { - ($attr:expr, $meta:expr) => {{ throw_invalid_attr!($attr, $meta, |diag| diag) }}; - ($attr:expr, $meta:expr, $f:expr) => {{ - let diag = crate::diagnostics::error::invalid_attr($attr, $meta); + ($attr:expr) => {{ throw_invalid_attr!($attr, |diag| diag) }}; + ($attr:expr, $f:expr) => {{ + let diag = crate::diagnostics::error::invalid_attr($attr); return Err(crate::diagnostics::error::_throw_err(diag, $f)); }}; } pub(crate) use throw_invalid_attr; - -/// Returns an error diagnostic for an invalid nested attribute. -pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diagnostic { - let name = attr.path.segments.last().unwrap().ident.to_string(); - let name = name.as_str(); - - let span = nested.span().unwrap(); - let meta = match nested { - syn::NestedMeta::Meta(meta) => meta, - syn::NestedMeta::Lit(_) => { - return span_err(span, &format!("`#[{name}(\"...\")]` is not a valid attribute")); - } - }; - - let span = meta.span().unwrap(); - let path = path_to_string(meta.path()); - match meta { - Meta::NameValue(..) => { - span_err(span, &format!("`#[{name}({path} = ...)]` is not a valid attribute")) - } - Meta::Path(..) => span_err(span, &format!("`#[{name}({path})]` is not a valid attribute")), - Meta::List(..) => { - span_err(span, &format!("`#[{name}({path}(...))]` is not a valid attribute")) - } - } -} - -/// Emit an error diagnostic for an invalid nested attribute (optionally performing additional -/// decoration using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`. -/// -/// For methods that return a `Result<_, DiagnosticDeriveError>`: -macro_rules! throw_invalid_nested_attr { - ($attr:expr, $nested_attr:expr) => {{ throw_invalid_nested_attr!($attr, $nested_attr, |diag| diag) }}; - ($attr:expr, $nested_attr:expr, $f:expr) => {{ - let diag = crate::diagnostics::error::invalid_nested_attr($attr, $nested_attr); - return Err(crate::diagnostics::error::_throw_err(diag, $f)); - }}; -} - -pub(crate) use throw_invalid_nested_attr; diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs index 9f96a0414879..607d51f5608d 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -100,7 +100,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok Diagnostic::spanned( resource_span, Level::Error, - format!("could not open Fluent resource: {}", e.to_string()), + format!("could not open Fluent resource: {e}"), ) .emit(); return failed(&crate_name); diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 90660fc1f93d..62d49c1c64e2 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -1,8 +1,7 @@ #![deny(unused_must_use)] use crate::diagnostics::error::{ - invalid_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, - DiagnosticDeriveError, + invalid_attr, span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError, }; use crate::diagnostics::utils::{ build_field_mapping, is_doc_comment, new_code_ident, @@ -11,7 +10,7 @@ use crate::diagnostics::utils::{ }; use proc_macro2::TokenStream; use quote::{format_ident, quote}; -use syn::{spanned::Spanned, Attribute, Meta, MetaList, NestedMeta, Path}; +use syn::{spanned::Spanned, Attribute, Meta, MetaList, Path}; use synstructure::{BindingInfo, Structure, VariantInfo}; use super::utils::{build_suggestion_code, AllowMultipleAlternatives}; @@ -39,7 +38,8 @@ impl SubdiagnosticDeriveBuilder { span_err( span, "`#[derive(Subdiagnostic)]` can only be used on structs and enums", - ); + ) + .emit(); } } @@ -192,7 +192,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { }; let Some(slug) = slug else { - let name = attr.path.segments.last().unwrap().ident.to_string(); + let name = attr.path().segments.last().unwrap().ident.to_string(); let name = name.as_str(); throw_span_err!( @@ -265,17 +265,18 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { info: FieldInfo<'_>, clone_suggestion_code: bool, ) -> Result { - let meta = attr.parse_meta()?; - match meta { - Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path), - Meta::List(list @ MetaList { .. }) => self.generate_field_code_inner_list( + match &attr.meta { + Meta::Path(path) => { + self.generate_field_code_inner_path(kind_stats, attr, info, path.clone()) + } + Meta::List(list) => self.generate_field_code_inner_list( kind_stats, attr, info, list, clone_suggestion_code, ), - _ => throw_invalid_attr!(attr, &meta), + _ => throw_invalid_attr!(attr), } } @@ -296,7 +297,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { "skip_arg" => Ok(quote! {}), "primary_span" => { if kind_stats.has_multipart_suggestion { - invalid_attr(attr, &Meta::Path(path)) + invalid_attr(attr) .help( "multipart suggestions use one or more `#[suggestion_part]`s rather \ than one `#[primary_span]`", @@ -309,7 +310,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { // FIXME(#100717): support `Option` on `primary_span` like in the // diagnostic derive if !matches!(info.ty, FieldInnerTy::Plain(_)) { - throw_invalid_attr!(attr, &Meta::Path(path), |diag| { + throw_invalid_attr!(attr, |diag| { let diag = diag.note("there must be exactly one primary span"); if kind_stats.has_normal_suggestion { @@ -335,7 +336,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`") .emit(); } else { - invalid_attr(attr, &Meta::Path(path)) + invalid_attr(attr) .help( "`#[suggestion_part(...)]` is only valid in multipart suggestions, \ use `#[primary_span]` instead", @@ -375,7 +376,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { span_attrs.push("primary_span") } - invalid_attr(attr, &Meta::Path(path)) + invalid_attr(attr) .help(format!( "only `{}`, `applicability` and `skip_arg` are valid field attributes", span_attrs.join(", ") @@ -394,7 +395,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { kind_stats: KindsStatistics, attr: &Attribute, info: FieldInfo<'_>, - list: MetaList, + list: &MetaList, clone_suggestion_code: bool, ) -> Result { let span = attr.span().unwrap(); @@ -405,7 +406,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { match name { "suggestion_part" => { if !kind_stats.has_multipart_suggestion { - throw_invalid_attr!(attr, &Meta::List(list), |diag| { + throw_invalid_attr!(attr, |diag| { diag.help( "`#[suggestion_part(...)]` is only valid in multipart suggestions", ) @@ -417,31 +418,27 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { report_error_if_not_applied_to_span(attr, &info)?; let mut code = None; - for nested_attr in list.nested.iter() { - let NestedMeta::Meta(ref meta) = nested_attr else { - throw_invalid_nested_attr!(attr, nested_attr); - }; - let span = meta.span().unwrap(); - let nested_name = meta.path().segments.last().unwrap().ident.to_string(); - let nested_name = nested_name.as_str(); - - match nested_name { - "code" => { - let code_field = new_code_ident(); - let formatting_init = build_suggestion_code( - &code_field, - meta, - self, - AllowMultipleAlternatives::No, - ); - code.set_once((code_field, formatting_init), span); - } - _ => throw_invalid_nested_attr!(attr, nested_attr, |diag| { - diag.help("`code` is the only valid nested attribute") - }), + list.parse_nested_meta(|nested| { + if nested.path.is_ident("code") { + let code_field = new_code_ident(); + let span = nested.path.span().unwrap(); + let formatting_init = build_suggestion_code( + &code_field, + nested, + self, + AllowMultipleAlternatives::No, + ); + code.set_once((code_field, formatting_init), span); + } else { + span_err( + nested.path.span().unwrap(), + "`code` is the only valid nested attribute", + ) + .emit(); } - } + Ok(()) + })?; let Some((code_field, formatting_init)) = code.value() else { span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`") @@ -458,7 +455,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { }; Ok(quote! { suggestions.push((#binding, #code_field)); }) } - _ => throw_invalid_attr!(attr, &Meta::List(list), |diag| { + _ => throw_invalid_attr!(attr, |diag| { let mut span_attrs = vec![]; if kind_stats.has_multipart_suggestion { span_attrs.push("suggestion_part"); diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 65bb154d7f39..b9b09c66230b 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -1,5 +1,5 @@ use crate::diagnostics::error::{ - span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError, + span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError, }; use proc_macro::Span; use proc_macro2::{Ident, TokenStream}; @@ -8,11 +8,13 @@ use std::cell::RefCell; use std::collections::{BTreeSet, HashMap}; use std::fmt; use std::str::FromStr; +use syn::meta::ParseNestedMeta; +use syn::punctuated::Punctuated; +use syn::{parenthesized, LitStr, Path, Token}; use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple}; -use syn::{MetaList, MetaNameValue, NestedMeta, Path}; use synstructure::{BindingInfo, VariantInfo}; -use super::error::{invalid_attr, invalid_nested_attr}; +use super::error::invalid_attr; thread_local! { pub static CODE_IDENT_COUNT: RefCell = RefCell::new(0); @@ -60,8 +62,8 @@ pub(crate) fn report_type_error( attr: &Attribute, ty_name: &str, ) -> Result { - let name = attr.path.segments.last().unwrap().ident.to_string(); - let meta = attr.parse_meta()?; + let name = attr.path().segments.last().unwrap().ident.to_string(); + let meta = &attr.meta; throw_span_err!( attr.span().unwrap(), @@ -418,59 +420,62 @@ pub(super) enum AllowMultipleAlternatives { Yes, } +fn parse_suggestion_values( + nested: ParseNestedMeta<'_>, + allow_multiple: AllowMultipleAlternatives, +) -> syn::Result> { + let values = if let Ok(val) = nested.value() { + vec![val.parse()?] + } else { + let content; + parenthesized!(content in nested.input); + + if let AllowMultipleAlternatives::No = allow_multiple { + span_err( + nested.input.span().unwrap(), + "expected exactly one string literal for `code = ...`", + ) + .emit(); + vec![] + } else { + let literals = Punctuated::::parse_terminated(&content); + + match literals { + Ok(p) if p.is_empty() => { + span_err( + content.span().unwrap(), + "expected at least one string literal for `code(...)`", + ) + .emit(); + vec![] + } + Ok(p) => p.into_iter().collect(), + Err(_) => { + span_err( + content.span().unwrap(), + "`code(...)` must contain only string literals", + ) + .emit(); + vec![] + } + } + } + }; + + Ok(values) +} + /// Constructs the `format!()` invocation(s) necessary for a `#[suggestion*(code = "foo")]` or /// `#[suggestion*(code("foo", "bar"))]` attribute field pub(super) fn build_suggestion_code( code_field: &Ident, - meta: &Meta, + nested: ParseNestedMeta<'_>, fields: &impl HasFieldMap, allow_multiple: AllowMultipleAlternatives, ) -> TokenStream { - let values = match meta { - // `code = "foo"` - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => vec![s], - // `code("foo", "bar")` - Meta::List(MetaList { nested, .. }) => { - if let AllowMultipleAlternatives::No = allow_multiple { - span_err( - meta.span().unwrap(), - "expected exactly one string literal for `code = ...`", - ) - .emit(); - vec![] - } else if nested.is_empty() { - span_err( - meta.span().unwrap(), - "expected at least one string literal for `code(...)`", - ) - .emit(); - vec![] - } else { - nested - .into_iter() - .filter_map(|item| { - if let NestedMeta::Lit(syn::Lit::Str(s)) = item { - Some(s) - } else { - span_err( - item.span().unwrap(), - "`code(...)` must contain only string literals", - ) - .emit(); - None - } - }) - .collect() - } - } - _ => { - span_err( - meta.span().unwrap(), - r#"`code = "..."`/`code(...)` must contain only string literals"#, - ) - .emit(); - vec![] - } + let values = match parse_suggestion_values(nested, allow_multiple) { + Ok(x) => x, + Err(e) => return e.into_compile_error(), }; if let AllowMultipleAlternatives::Yes = allow_multiple { @@ -601,11 +606,9 @@ impl SubdiagnosticKind { let span = attr.span().unwrap(); - let name = attr.path.segments.last().unwrap().ident.to_string(); + let name = attr.path().segments.last().unwrap().ident.to_string(); let name = name.as_str(); - let meta = attr.parse_meta()?; - let mut kind = match name { "label" => SubdiagnosticKind::Label, "note" => SubdiagnosticKind::Note, @@ -618,7 +621,7 @@ impl SubdiagnosticKind { name.strip_prefix("suggestion").and_then(SuggestionKind::from_suffix) { if suggestion_kind != SuggestionKind::Normal { - invalid_attr(attr, &meta) + invalid_attr(attr) .help(format!( r#"Use `#[suggestion(..., style = "{suggestion_kind}")]` instead"# )) @@ -635,7 +638,7 @@ impl SubdiagnosticKind { name.strip_prefix("multipart_suggestion").and_then(SuggestionKind::from_suffix) { if suggestion_kind != SuggestionKind::Normal { - invalid_attr(attr, &meta) + invalid_attr(attr) .help(format!( r#"Use `#[multipart_suggestion(..., style = "{suggestion_kind}")]` instead"# )) @@ -647,16 +650,16 @@ impl SubdiagnosticKind { applicability: None, } } else { - throw_invalid_attr!(attr, &meta); + throw_invalid_attr!(attr); } } }; - let nested = match meta { - Meta::List(MetaList { ref nested, .. }) => { + let list = match &attr.meta { + Meta::List(list) => { // An attribute with properties, such as `#[suggestion(code = "...")]` or // `#[error(some::slug)]` - nested + list } Meta::Path(_) => { // An attribute without a slug or other properties, such as `#[note]` - return @@ -678,69 +681,68 @@ impl SubdiagnosticKind { } } _ => { - throw_invalid_attr!(attr, &meta) + throw_invalid_attr!(attr) } }; let mut code = None; let mut suggestion_kind = None; - let mut nested_iter = nested.into_iter().peekable(); + let mut first = true; + let mut slug = None; - // Peek at the first nested attribute: if it's a slug path, consume it. - let slug = if let Some(NestedMeta::Meta(Meta::Path(path))) = nested_iter.peek() { - let path = path.clone(); - // Advance the iterator. - nested_iter.next(); - Some(path) - } else { - None - }; - - for nested_attr in nested_iter { - let meta = match nested_attr { - NestedMeta::Meta(ref meta) => meta, - NestedMeta::Lit(_) => { - invalid_nested_attr(attr, nested_attr).emit(); - continue; + list.parse_nested_meta(|nested| { + if nested.input.is_empty() || nested.input.peek(Token![,]) { + if first { + slug = Some(nested.path); + } else { + span_err(nested.input.span().unwrap(), "a diagnostic slug must be the first argument to the attribute").emit(); } - }; - let span = meta.span().unwrap(); - let nested_name = meta.path().segments.last().unwrap().ident.to_string(); + first = false; + return Ok(()); + } + + first = false; + + let nested_name = nested.path.segments.last().unwrap().ident.to_string(); let nested_name = nested_name.as_str(); - let string_value = match meta { - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => Some(value), + let path_span = nested.path.span().unwrap(); + let val_span = nested.input.span().unwrap(); - Meta::Path(_) => throw_invalid_nested_attr!(attr, nested_attr, |diag| { - diag.help("a diagnostic slug must be the first argument to the attribute") - }), - _ => None, - }; + macro_rules! get_string { + () => {{ + let Ok(value) = nested.value().and_then(|x| x.parse::()) else { + span_err(val_span, "expected `= \"xxx\"`").emit(); + return Ok(()); + }; + value + }}; + } + + let mut has_errors = false; + let input = nested.input; match (nested_name, &mut kind) { ("code", SubdiagnosticKind::Suggestion { code_field, .. }) => { let code_init = build_suggestion_code( code_field, - meta, + nested, fields, AllowMultipleAlternatives::Yes, ); - code.set_once(code_init, span); + code.set_once(code_init, path_span); } ( "applicability", SubdiagnosticKind::Suggestion { ref mut applicability, .. } | SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. }, ) => { - let Some(value) = string_value else { - invalid_nested_attr(attr, nested_attr).emit(); - continue; - }; - + let value = get_string!(); let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| { - span_err(span, "invalid applicability").emit(); + span_err(value.span().unwrap(), "invalid applicability").emit(); + has_errors = true; Applicability::Unspecified }); applicability.set_once(value, span); @@ -750,15 +752,13 @@ impl SubdiagnosticKind { SubdiagnosticKind::Suggestion { .. } | SubdiagnosticKind::MultipartSuggestion { .. }, ) => { - let Some(value) = string_value else { - invalid_nested_attr(attr, nested_attr).emit(); - continue; - }; + let value = get_string!(); let value = value.value().parse().unwrap_or_else(|()| { span_err(value.span().unwrap(), "invalid suggestion style") .help("valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`") .emit(); + has_errors = true; SuggestionKind::Normal }); @@ -767,22 +767,32 @@ impl SubdiagnosticKind { // Invalid nested attribute (_, SubdiagnosticKind::Suggestion { .. }) => { - invalid_nested_attr(attr, nested_attr) + span_err(path_span, "invalid nested attribute") .help( "only `style`, `code` and `applicability` are valid nested attributes", ) .emit(); + has_errors = true; } (_, SubdiagnosticKind::MultipartSuggestion { .. }) => { - invalid_nested_attr(attr, nested_attr) + span_err(path_span, "invalid nested attribute") .help("only `style` and `applicability` are valid nested attributes") - .emit() + .emit(); + has_errors = true; } _ => { - invalid_nested_attr(attr, nested_attr).emit(); + span_err(path_span, "invalid nested attribute").emit(); + has_errors = true; } } - } + + if has_errors { + // Consume the rest of the input to avoid spamming errors + let _ = input.parse::(); + } + + Ok(()) + })?; match kind { SubdiagnosticKind::Suggestion { @@ -845,5 +855,5 @@ pub(super) fn should_generate_set_arg(field: &Field) -> bool { } pub(super) fn is_doc_comment(attr: &Attribute) -> bool { - attr.path.segments.last().unwrap().ident == "doc" + attr.path().segments.last().unwrap().ident == "doc" } diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs index 63bdcea87f81..75a2f7009c25 100644 --- a/compiler/rustc_macros/src/hash_stable.rs +++ b/compiler/rustc_macros/src/hash_stable.rs @@ -1,6 +1,6 @@ use proc_macro2::{self, Ident}; use quote::quote; -use syn::{self, parse_quote, Meta, NestedMeta}; +use syn::{self, parse_quote}; struct Attributes { ignore: bool, @@ -10,32 +10,29 @@ struct Attributes { fn parse_attributes(field: &syn::Field) -> Attributes { let mut attrs = Attributes { ignore: false, project: None }; for attr in &field.attrs { - if let Ok(meta) = attr.parse_meta() { - if !meta.path().is_ident("stable_hasher") { - continue; + let meta = &attr.meta; + if !meta.path().is_ident("stable_hasher") { + continue; + } + let mut any_attr = false; + let _ = attr.parse_nested_meta(|nested| { + if nested.path.is_ident("ignore") { + attrs.ignore = true; + any_attr = true; } - let mut any_attr = false; - if let Meta::List(list) = meta { - for nested in list.nested.iter() { - if let NestedMeta::Meta(meta) = nested { - if meta.path().is_ident("ignore") { - attrs.ignore = true; - any_attr = true; - } - if meta.path().is_ident("project") { - if let Meta::List(list) = meta { - if let Some(NestedMeta::Meta(meta)) = list.nested.iter().next() { - attrs.project = meta.path().get_ident().cloned(); - any_attr = true; - } - } - } + if nested.path.is_ident("project") { + let _ = nested.parse_nested_meta(|meta| { + if attrs.project.is_none() { + attrs.project = meta.path.get_ident().cloned(); } - } - } - if !any_attr { - panic!("error parsing stable_hasher"); + any_attr = true; + Ok(()) + }); } + Ok(()) + }); + if !any_attr { + panic!("error parsing stable_hasher"); } } attrs diff --git a/compiler/rustc_macros/src/newtype.rs b/compiler/rustc_macros/src/newtype.rs index 89ea89cf502e..78a6f74887d4 100644 --- a/compiler/rustc_macros/src/newtype.rs +++ b/compiler/rustc_macros/src/newtype.rs @@ -25,7 +25,7 @@ impl Parse for Newtype { let mut encodable = true; let mut ord = true; - attrs.retain(|attr| match attr.path.get_ident() { + attrs.retain(|attr| match attr.path().get_ident() { Some(ident) => match &*ident.to_string() { "custom_encodable" => { encodable = false; @@ -36,22 +36,22 @@ impl Parse for Newtype { false } "max" => { - let Ok(Meta::NameValue(literal) )= attr.parse_meta() else { + let Meta::NameValue(MetaNameValue { value: Expr::Lit(lit), .. }) = &attr.meta else { panic!("#[max = NUMBER] attribute requires max value"); }; - if let Some(old) = max.replace(literal.lit) { + if let Some(old) = max.replace(lit.lit.clone()) { panic!("Specified multiple max: {old:?}"); } false } "debug_format" => { - let Ok(Meta::NameValue(literal) )= attr.parse_meta() else { + let Meta::NameValue(MetaNameValue { value: Expr::Lit(lit), .. }) = &attr.meta else { panic!("#[debug_format = FMT] attribute requires a format"); }; - if let Some(old) = debug_format.replace(literal.lit) { + if let Some(old) = debug_format.replace(lit.lit.clone()) { panic!("Specified multiple debug format options: {old:?}"); } diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 08e42a8a08f9..f85ba38003c1 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -15,7 +15,7 @@ mod kw { /// Ensures only doc comment attributes are used fn check_attributes(attrs: Vec) -> Result> { let inner = |attr: Attribute| { - if !attr.path.is_ident("doc") { + if !attr.path().is_ident("doc") { Err(Error::new(attr.span(), "attributes not supported on queries")) } else if attr.style != AttrStyle::Outer { Err(Error::new( @@ -48,7 +48,7 @@ impl Parse for Query { let name: Ident = input.parse()?; let arg_content; parenthesized!(arg_content in input); - let key = arg_content.parse()?; + let key = Pat::parse_single(&arg_content)?; arg_content.parse::()?; let arg = arg_content.parse()?; let result = input.parse()?; @@ -158,7 +158,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { } else { None }; - let list = attr_content.parse_terminated(Expr::parse)?; + let list = attr_content.parse_terminated(Expr::parse, Token![,])?; try_insert!(desc = (tcx, list)); } else if modifier == "cache_on_disk_if" { // Parse a cache modifier like: @@ -166,7 +166,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { let args = if input.peek(token::Paren) { let args; parenthesized!(args in input); - let tcx = args.parse()?; + let tcx = Pat::parse_single(&args)?; Some(tcx) } else { None diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index 388e254cd645..5ee4d8793135 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -1,5 +1,5 @@ use quote::{quote, ToTokens}; -use syn::{parse_quote, Attribute, Meta, NestedMeta}; +use syn::parse_quote; pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { if let syn::Data::Union(_) = s.ast().data { @@ -17,21 +17,20 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: vi.construct(|_, index| { let bind = &bindings[index]; + let mut fixed = false; + // retain value of fields with #[type_foldable(identity)] - let fixed = bind - .ast() - .attrs - .iter() - .map(Attribute::parse_meta) - .filter_map(Result::ok) - .flat_map(|attr| match attr { - Meta::List(list) if list.path.is_ident("type_foldable") => list.nested, - _ => Default::default(), - }) - .any(|nested| match nested { - NestedMeta::Meta(Meta::Path(path)) => path.is_ident("identity"), - _ => false, + bind.ast().attrs.iter().for_each(|x| { + if !x.path().is_ident("type_foldable") { + return; + } + let _ = x.parse_nested_meta(|nested| { + if nested.path.is_ident("identity") { + fixed = true; + } + Ok(()) }); + }); if fixed { bind.to_token_stream() diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs index f6f4c4779c30..dcd505a105e5 100644 --- a/compiler/rustc_macros/src/type_visitable.rs +++ b/compiler/rustc_macros/src/type_visitable.rs @@ -1,5 +1,5 @@ use quote::quote; -use syn::{parse_quote, Attribute, Meta, NestedMeta}; +use syn::parse_quote; pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { if let syn::Data::Union(_) = s.ast().data { @@ -8,19 +8,21 @@ pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: // ignore fields with #[type_visitable(ignore)] s.filter(|bi| { - !bi.ast() - .attrs - .iter() - .map(Attribute::parse_meta) - .filter_map(Result::ok) - .flat_map(|attr| match attr { - Meta::List(list) if list.path.is_ident("type_visitable") => list.nested, - _ => Default::default(), - }) - .any(|nested| match nested { - NestedMeta::Meta(Meta::Path(path)) => path.is_ident("ignore"), - _ => false, - }) + let mut ignored = false; + + bi.ast().attrs.iter().for_each(|attr| { + if !attr.path().is_ident("type_visitable") { + return; + } + let _ = attr.parse_nested_meta(|nested| { + if nested.path.is_ident("ignore") { + ignored = true; + } + Ok(()) + }); + }); + + !ignored }); if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 23c1aebb8ae3..23aceca06223 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -185,7 +185,7 @@ impl CStore { fn push_dependencies_in_postorder(&self, deps: &mut Vec, cnum: CrateNum) { if !deps.contains(&cnum) { let data = self.get_crate_data(cnum); - for &dep in data.dependencies().iter() { + for dep in data.dependencies() { if dep != cnum { self.push_dependencies_in_postorder(deps, dep); } @@ -605,7 +605,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { if cmeta.update_extern_crate(extern_crate) { // Propagate the extern crate info to dependencies if it was updated. let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate }; - for &dep_cnum in cmeta.dependencies().iter() { + for dep_cnum in cmeta.dependencies() { self.update_extern_crate(dep_cnum, extern_crate); } } diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 880da5ca5937..81e62eccb8a5 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -22,8 +22,6 @@ extern crate proc_macro; extern crate rustc_macros; #[macro_use] extern crate rustc_middle; -#[macro_use] -extern crate rustc_data_structures; #[macro_use] extern crate tracing; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 79c42a128e79..c6af8d632898 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -218,7 +218,7 @@ use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::memmap::Mmap; -use rustc_data_structures::owning_ref::OwningRef; +use rustc_data_structures::owned_slice::slice_owned; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg}; @@ -236,6 +236,7 @@ use rustc_target::spec::{Target, TargetTriple}; use snap::read::FrameDecoder; use std::borrow::Cow; use std::io::{Read, Result as IoResult, Write}; +use std::ops::Deref; use std::path::{Path, PathBuf}; use std::{cmp, fmt}; @@ -761,14 +762,14 @@ impl<'a> CrateLocator<'a> { } pub(crate) fn into_error(self, root: Option) -> CrateError { - CrateError::LocatorCombined(CombinedLocatorError { + CrateError::LocatorCombined(Box::new(CombinedLocatorError { crate_name: self.crate_name, root, triple: self.triple, dll_prefix: self.target.dll_prefix.to_string(), dll_suffix: self.target.dll_suffix.to_string(), crate_rejections: self.crate_rejections, - }) + })) } } @@ -814,15 +815,14 @@ fn get_metadata_section<'p>( // Assume the decompressed data will be at least the size of the compressed data, so we // don't have to grow the buffer as much. let mut inflated = Vec::with_capacity(compressed_bytes.len()); - match FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated) { - Ok(_) => rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()), - Err(_) => { - return Err(MetadataError::LoadFailure(format!( - "failed to decompress metadata: {}", - filename.display() - ))); - } - } + FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated).map_err(|_| { + MetadataError::LoadFailure(format!( + "failed to decompress metadata: {}", + filename.display() + )) + })?; + + slice_owned(inflated, Deref::deref) } CrateFlavor::Rmeta => { // mmap the file, because only a small fraction of it is read. @@ -840,7 +840,7 @@ fn get_metadata_section<'p>( )) })?; - rustc_erase_owner!(OwningRef::new(mmap).map_owner_box()) + slice_owned(mmap, Deref::deref) } }; let blob = MetadataBlob::new(raw_bytes); @@ -958,7 +958,7 @@ pub(crate) enum CrateError { StableCrateIdCollision(Symbol, Symbol), DlOpen(String), DlSym(String), - LocatorCombined(CombinedLocatorError), + LocatorCombined(Box), NonDylibPlugin(Symbol), } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 43e5946f3135..f9d32ffceef6 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -7,7 +7,7 @@ use rustc_ast as ast; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{Lock, LockGuard, Lrc, OnceCell}; +use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc, OnceCell}; use rustc_data_structures::unhash::UnhashMap; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro}; @@ -51,12 +51,6 @@ mod cstore_impl; #[derive(Clone)] pub(crate) struct MetadataBlob(Lrc); -// This is needed so we can create an OwningRef into the blob. -// The data behind a `MetadataBlob` has a stable address because it is -// contained within an Rc/Arc. -unsafe impl rustc_data_structures::owning_ref::StableAddress for MetadataBlob {} - -// This is needed so we can create an OwningRef into the blob. impl std::ops::Deref for MetadataBlob { type Target = [u8]; @@ -109,7 +103,7 @@ pub(crate) struct CrateMetadata { /// IDs as they are seen from the current compilation session. cnum_map: CrateNumMap, /// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime. - dependencies: Lock>, + dependencies: AppendOnlyVec, /// How to link (or not link) this crate to the currently compiled crate. dep_kind: Lock, /// Filesystem location of this crate. @@ -997,7 +991,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { _ => false, }; - ModChild { ident, res, vis, span, macro_rules } + ModChild { ident, res, vis, span, macro_rules, reexport_chain: Default::default() } } /// Iterates over all named children of the given module, @@ -1594,7 +1588,7 @@ impl CrateMetadata { .collect(); let alloc_decoding_state = AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect()); - let dependencies = Lock::new(cnum_map.iter().cloned().collect()); + let dependencies = cnum_map.iter().copied().collect(); // Pre-decode the DefPathHash->DefIndex table. This is a cheap operation // that does not copy any data. It just does some data verification. @@ -1634,12 +1628,12 @@ impl CrateMetadata { cdata } - pub(crate) fn dependencies(&self) -> LockGuard<'_, Vec> { - self.dependencies.borrow() + pub(crate) fn dependencies(&self) -> impl Iterator + '_ { + self.dependencies.iter() } pub(crate) fn add_dependency(&self, cnum: CrateNum) { - self.dependencies.borrow_mut().push(cnum); + self.dependencies.push(cnum); } pub(crate) fn update_extern_crate(&self, new_extern_crate: ExternCrate) -> bool { diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs index a6133f1b417a..02cab561b8f6 100644 --- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs +++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs @@ -1,14 +1,14 @@ use crate::rmeta::DecodeContext; use crate::rmeta::EncodeContext; -use crate::rmeta::MetadataBlob; -use rustc_data_structures::owning_ref::OwningRef; +use rustc_data_structures::owned_slice::slice_owned; +use rustc_data_structures::owned_slice::OwnedSlice; use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap}; use rustc_middle::parameterized_over_tcx; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::def_id::{DefIndex, DefPathHash}; pub(crate) enum DefPathHashMapRef<'tcx> { - OwnedFromMetadata(odht::HashTable>), + OwnedFromMetadata(odht::HashTable), BorrowedFromTcx(&'tcx DefPathHashMap), } @@ -50,11 +50,11 @@ impl<'a, 'tcx> Decodable> for DefPathHashMapRef<'static> let len = d.read_usize(); let pos = d.position(); - let o = OwningRef::new(d.blob().clone()).map(|x| &x[pos..pos + len]); + let o = slice_owned(d.blob().clone(), |blob| &blob[pos..pos + len]); - // Although we already have the data we need via the OwningRef, we still need - // to advance the DecodeContext's position so it's in a valid state after - // the method. We use read_raw_bytes() for that. + // Although we already have the data we need via the `OwnedSlice`, we still need + // to advance the `DecodeContext`'s position so it's in a valid state after + // the method. We use `read_raw_bytes()` for that. let _ = d.read_raw_bytes(len); let inner = odht::HashTable::from_raw_bytes(o).unwrap_or_else(|e| { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 2652a4280d37..4291b9aa1426 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -112,8 +112,6 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> { emit_i8(i8); emit_bool(bool); - emit_f64(f64); - emit_f32(f32); emit_char(char); emit_str(&str); emit_raw_bytes(&[u8]); @@ -1329,8 +1327,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } })); - if let Some(reexports) = tcx.module_reexports(local_def_id) { - assert!(!reexports.is_empty()); + let reexports = tcx.module_reexports(local_def_id); + if !reexports.is_empty() { record_array!(self.tables.module_reexports[def_id] <- reexports); } } @@ -1712,8 +1710,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let stability = tcx.lookup_stability(CRATE_DEF_ID); let macros = self.lazy_array(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index)); - let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans(); - for (i, span) in spans.into_iter().enumerate() { + for (i, span) in self.tcx.sess.parse_sess.proc_macro_quoted_spans() { let span = self.lazy(span); self.tables.proc_macro_quoted_spans.set_some(i, span); } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 9f16ecbdaa93..dd1e254f405b 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -119,6 +119,7 @@ macro_rules! arena_types { [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, [] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>), + [] mod_child: rustc_middle::metadata::ModChild, ]); ) } diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 84510fe218cf..0ddbe7d1c292 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -94,7 +94,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { } #[inline] - fn dep_kind_info(&self, dep_kind: DepKind) -> &DepKindStruct<'tcx> { - &self.query_kinds[dep_kind as usize] + fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> { + &self.query_kinds[dk as usize] } } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 89a485b47ca8..9d97a75a2fa6 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -74,18 +74,17 @@ impl<'hir> Iterator for ParentHirIterator<'hir> { if self.current_id == CRATE_HIR_ID { return None; } - loop { - // There are nodes that do not have entries, so we need to skip them. - let parent_id = self.map.parent_id(self.current_id); - if parent_id == self.current_id { - self.current_id = CRATE_HIR_ID; - return None; - } + // There are nodes that do not have entries, so we need to skip them. + let parent_id = self.map.parent_id(self.current_id); - self.current_id = parent_id; - return Some(parent_id); + if parent_id == self.current_id { + self.current_id = CRATE_HIR_ID; + return None; } + + self.current_id = parent_id; + return Some(parent_id); } } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 7f8fc17744dc..b5b712c367d0 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -35,9 +35,9 @@ use std::ops::Index; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct Canonical<'tcx, V> { + pub value: V, pub max_universe: ty::UniverseIndex, pub variables: CanonicalVarInfos<'tcx>, - pub value: V, } pub type CanonicalVarInfos<'tcx> = &'tcx List>; @@ -80,6 +80,18 @@ impl CanonicalVarValues<'_> { } }) } + + pub fn is_identity_modulo_regions(&self) -> bool { + self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() { + ty::GenericArgKind::Lifetime(_) => true, + ty::GenericArgKind::Type(ty) => { + matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv) + } + ty::GenericArgKind::Const(ct) => { + matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv) + } + }) + } } /// When we canonicalize a value to form a query, we wind up replacing @@ -149,15 +161,15 @@ impl<'tcx> CanonicalVarInfo<'tcx> { } } - pub fn expect_anon_placeholder(self) -> u32 { + pub fn expect_placeholder_index(self) -> usize { match self.kind { CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_, _) => bug!("expected placeholder: {self:?}"), - CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.name.expect_anon(), - CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.name.expect_anon(), - CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.name.as_u32(), + CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.bound.var.as_usize(), + CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.bound.var.as_usize(), + CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.bound.as_usize(), } } } @@ -411,7 +423,7 @@ impl<'tcx> CanonicalVarValues<'tcx> { CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { let br = ty::BoundRegion { var: ty::BoundVar::from_usize(i), - kind: ty::BrAnon(i as u32, None), + kind: ty::BrAnon(None), }; tcx.mk_re_late_bound(ty::INNERMOST, br).into() } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 0e883424fd47..b4edb02f6c48 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -33,6 +33,7 @@ #![feature(generators)] #![feature(get_mut_unchecked)] #![feature(if_let_guard)] +#![feature(inline_const)] #![feature(iter_from_generator)] #![feature(local_key_cell_methods)] #![feature(negative_impls)] diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index 5ff014c7815a..fabc6bce7317 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -5,13 +5,34 @@ use rustc_macros::HashStable; use rustc_span::def_id::DefId; use rustc_span::symbol::Ident; use rustc_span::Span; +use smallvec::SmallVec; + +/// A simplified version of `ImportKind` from resolve. +/// `DefId`s here correspond to `use` and `extern crate` items themselves, not their targets. +#[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, HashStable)] +pub enum Reexport { + Single(DefId), + Glob(DefId), + ExternCrate(DefId), + MacroUse, + MacroExport, +} + +impl Reexport { + pub fn id(self) -> Option { + match self { + Reexport::Single(id) | Reexport::Glob(id) | Reexport::ExternCrate(id) => Some(id), + Reexport::MacroUse | Reexport::MacroExport => None, + } + } +} /// This structure is supposed to keep enough data to re-create `NameBinding`s for other crates /// during name resolution. Right now the bindings are not recreated entirely precisely so we may /// need to add more data in the future to correctly support macros 2.0, for example. /// Module child can be either a proper item or a reexport (including private imports). /// In case of reexport all the fields describe the reexport item itself, not what it refers to. -#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(Debug, TyEncodable, TyDecodable, HashStable)] pub struct ModChild { /// Name of the item. pub ident: Ident, @@ -24,4 +45,7 @@ pub struct ModChild { pub span: Span, /// A proper `macro_rules` item (not a reexport). pub macro_rules: bool, + /// Reexport chain linking this module child to its original reexported item. + /// Empty if the module child is a proper item. + pub reexport_chain: SmallVec<[Reexport; 2]>, } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 2f2c7b154165..1a8e48264471 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -109,26 +109,34 @@ const MAX_HASHED_BUFFER_LEN: usize = 2 * MAX_BYTES_TO_HASH; // large. impl hash::Hash for Allocation { fn hash(&self, state: &mut H) { + let Self { + bytes, + provenance, + init_mask, + align, + mutability, + extra: (), // don't bother hashing () + } = self; + // Partially hash the `bytes` buffer when it is large. To limit collisions with common // prefixes and suffixes, we hash the length and some slices of the buffer. - let byte_count = self.bytes.len(); + let byte_count = bytes.len(); if byte_count > MAX_HASHED_BUFFER_LEN { // Hash the buffer's length. byte_count.hash(state); // And its head and tail. - self.bytes[..MAX_BYTES_TO_HASH].hash(state); - self.bytes[byte_count - MAX_BYTES_TO_HASH..].hash(state); + bytes[..MAX_BYTES_TO_HASH].hash(state); + bytes[byte_count - MAX_BYTES_TO_HASH..].hash(state); } else { - self.bytes.hash(state); + bytes.hash(state); } // Hash the other fields as usual. - self.provenance.hash(state); - self.init_mask.hash(state); - self.align.hash(state); - self.mutability.hash(state); - self.extra.hash(state); + provenance.hash(state); + init_mask.hash(state); + align.hash(state); + mutability.hash(state); } } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 1766d7a66980..1f8b650e34cf 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -263,7 +263,8 @@ impl AllocDecodingState { } pub fn new(data_offsets: Vec) -> Self { - let decoding_state = vec![Lock::new(State::Empty); data_offsets.len()]; + let decoding_state = + std::iter::repeat_with(|| Lock::new(State::Empty)).take(data_offsets.len()).collect(); Self { decoding_state, data_offsets } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 44fd8478be9b..56755e588cb4 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -915,7 +915,7 @@ pub enum LocalInfo<'tcx> { impl<'tcx> LocalDecl<'tcx> { pub fn local_info(&self) -> &LocalInfo<'tcx> { - &**self.local_info.as_ref().assert_crate_local() + &self.local_info.as_ref().assert_crate_local() } /// Returns `true` only if local is a binding that can itself be @@ -1036,8 +1036,7 @@ impl<'tcx> LocalDecl<'tcx> { #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum VarDebugInfoContents<'tcx> { - /// NOTE(eddyb) There's an unenforced invariant that this `Place` is - /// based on a `Local`, not a `Static`, and contains no indexing. + /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`. Place(Place<'tcx>), Const(Constant<'tcx>), /// The user variable's data is split across several fragments, @@ -1047,6 +1046,7 @@ pub enum VarDebugInfoContents<'tcx> { /// the underlying debuginfo feature this relies on. Composite { /// Type of the original user variable. + /// This cannot contain a union or an enum. ty: Ty<'tcx>, /// All the parts of the original user variable, which ended /// up in disjoint places, due to optimizations. @@ -1075,17 +1075,16 @@ pub struct VarDebugInfoFragment<'tcx> { /// Where in the composite user variable this fragment is, /// represented as a "projection" into the composite variable. /// At lower levels, this corresponds to a byte/bit range. - // NOTE(eddyb) there's an unenforced invariant that this contains - // only `Field`s, and not into `enum` variants or `union`s. - // FIXME(eddyb) support this for `enum`s by either using DWARF's + /// + /// This can only contain `PlaceElem::Field`. + // FIXME support this for `enum`s by either using DWARF's // more advanced control-flow features (unsupported by LLVM?) // to match on the discriminant, or by using custom type debuginfo // with non-overlapping variants for the composite variable. pub projection: Vec>, /// Where the data for this fragment can be found. - // NOTE(eddyb) There's an unenforced invariant that this `Place` is - // contains no indexing (with a non-constant index). + /// This `Place` only contains projection which satisfy `can_use_in_debuginfo`. pub contents: Place<'tcx>, } @@ -1538,6 +1537,17 @@ impl ProjectionElem { pub fn is_field_to(&self, f: FieldIdx) -> bool { matches!(*self, Self::Field(x, _) if x == f) } + + /// Returns `true` if this is accepted inside `VarDebugInfoContents::Place`. + pub fn can_use_in_debuginfo(&self) -> bool { + match self { + Self::Deref | Self::Downcast(_, _) | Self::Field(_, _) => true, + Self::ConstantIndex { .. } + | Self::Index(_) + | Self::OpaqueCast(_) + | Self::Subslice { .. } => false, + } + } } /// Alias for projections as they appear in `UserTypeProjection`, where we @@ -1991,6 +2001,13 @@ impl<'tcx> Rvalue<'tcx> { } impl BorrowKind { + pub fn mutability(&self) -> Mutability { + match *self { + BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => Mutability::Not, + BorrowKind::Mut { .. } => Mutability::Mut, + } + } + pub fn allows_two_phase_borrow(&self) -> bool { match *self { BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index eb860c04de20..f62853c3e740 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -12,6 +12,9 @@ pub struct MirPatch<'tcx> { new_statements: Vec<(Location, StatementKind<'tcx>)>, new_locals: Vec>, resume_block: Option, + // Only for unreachable in cleanup path. + unreachable_cleanup_block: Option, + terminate_block: Option, body_span: Span, next_local: usize, } @@ -25,14 +28,31 @@ impl<'tcx> MirPatch<'tcx> { new_locals: vec![], next_local: body.local_decls.len(), resume_block: None, + unreachable_cleanup_block: None, + terminate_block: None, body_span: body.span, }; - // Check if we already have a resume block for (bb, block) in body.basic_blocks.iter_enumerated() { + // Check if we already have a resume block if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() { result.resume_block = Some(bb); - break; + continue; + } + + // Check if we already have an unreachable block + if let TerminatorKind::Unreachable = block.terminator().kind + && block.statements.is_empty() + && block.is_cleanup + { + result.unreachable_cleanup_block = Some(bb); + continue; + } + + // Check if we already have a terminate block + if let TerminatorKind::Terminate = block.terminator().kind && block.statements.is_empty() { + result.terminate_block = Some(bb); + continue; } } @@ -56,6 +76,40 @@ impl<'tcx> MirPatch<'tcx> { bb } + pub fn unreachable_cleanup_block(&mut self) -> BasicBlock { + if let Some(bb) = self.unreachable_cleanup_block { + return bb; + } + + let bb = self.new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: SourceInfo::outermost(self.body_span), + kind: TerminatorKind::Unreachable, + }), + is_cleanup: true, + }); + self.unreachable_cleanup_block = Some(bb); + bb + } + + pub fn terminate_block(&mut self) -> BasicBlock { + if let Some(bb) = self.terminate_block { + return bb; + } + + let bb = self.new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: SourceInfo::outermost(self.body_span), + kind: TerminatorKind::Terminate, + }), + is_cleanup: true, + }); + self.terminate_block = Some(bb); + bb + } + pub fn is_patched(&self, bb: BasicBlock) -> bool { self.patch_map[bb].is_some() } @@ -79,21 +133,21 @@ impl<'tcx> MirPatch<'tcx> { let mut new_decl = LocalDecl::new(ty, span).internal(); **new_decl.local_info.as_mut().assert_crate_local() = local_info; self.new_locals.push(new_decl); - Local::new(index as usize) + Local::new(index) } pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local { let index = self.next_local; self.next_local += 1; self.new_locals.push(LocalDecl::new(ty, span)); - Local::new(index as usize) + Local::new(index) } pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local { let index = self.next_local; self.next_local += 1; self.new_locals.push(LocalDecl::new(ty, span).internal()); - Local::new(index as usize) + Local::new(index) } pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 68561cf6dd77..cfdf1dcf5c02 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -411,10 +411,8 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self { let inner = tcx.fold_regions(ty, |r, depth| match r.kind() { ty::ReVar(vid) => { - let br = ty::BoundRegion { - var: ty::BoundVar::new(vid.index()), - kind: ty::BrAnon(vid.as_u32(), None), - }; + let br = + ty::BoundRegion { var: ty::BoundVar::new(vid.index()), kind: ty::BrAnon(None) }; tcx.mk_re_late_bound(depth, br) } _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"), diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 1a23f9dadd4f..2165403da267 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -262,7 +262,7 @@ pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str { Goto { .. } => "Goto", SwitchInt { .. } => "SwitchInt", Resume => "Resume", - Abort => "Abort", + Terminate => "Terminate", Return => "Return", Unreachable => "Unreachable", Drop { .. } => "Drop", diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index cc35e6106e29..135889d0da81 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -515,15 +515,15 @@ pub struct CopyNonOverlapping<'tcx> { /// /// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the /// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such -/// terminators have a `cleanup: Option` field on them. If stack unwinding occurs, then -/// once the current function is reached, execution continues at the given basic block, if any. If -/// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is -/// equivalent to the execution of a `Resume` terminator. +/// terminators have a `unwind: UnwindAction` field on them. If stack unwinding occurs, then +/// once the current function is reached, an action will be taken based on the `unwind` field. +/// If the action is `Cleanup`, then the execution continues at the given basic block. If the +/// action is `Continue` then no cleanup is performed, and the stack continues unwinding. /// -/// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup` -/// basic blocks have a couple restrictions: -/// 1. All `cleanup` fields in them must be `None`. -/// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are. +/// The basic block pointed to by a `Cleanup` unwind action must have its `cleanup` flag set. +/// `cleanup` basic blocks have a couple restrictions: +/// 1. All `unwind` fields in them must be `UnwindAction::Terminate` or `UnwindAction::Unreachable`. +/// 2. `Return` terminators are not allowed in them. `Terminate` and `Resume` terminators are. /// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks /// must also be `cleanup`. This is a part of the type system and checked statically, so it is /// still an error to have such an edge in the CFG even if it's known that it won't be taken at @@ -565,11 +565,11 @@ pub enum TerminatorKind<'tcx> { /// deaggregation runs. Resume, - /// Indicates that the landing pad is finished and that the process should abort. + /// Indicates that the landing pad is finished and that the process should terminate. /// /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in /// cleanup blocks. - Abort, + Terminate, /// Returns from the function. /// @@ -604,7 +604,7 @@ pub enum TerminatorKind<'tcx> { /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to /// > the place or one of its "parents" occurred more recently than a move out of it. This does not /// > consider indirect assignments. - Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option }, + Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction }, /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of /// the referred to function. The operand types must match the argument types of the function. @@ -628,8 +628,8 @@ pub enum TerminatorKind<'tcx> { destination: Place<'tcx>, /// Where to go after this call returns. If none, the call necessarily diverges. target: Option, - /// Cleanups to be done if the call unwinds. - cleanup: Option, + /// Action to be taken if the call unwinds. + unwind: UnwindAction, /// `true` if this is from a call in HIR rather than from an overloaded /// operator. True for overloaded function call. from_hir_call: bool, @@ -654,7 +654,7 @@ pub enum TerminatorKind<'tcx> { expected: bool, msg: AssertMessage<'tcx>, target: BasicBlock, - cleanup: Option, + unwind: UnwindAction, }, /// Marks a suspend point. @@ -720,9 +720,8 @@ pub enum TerminatorKind<'tcx> { /// in practice, but in order to avoid fragility we want to always /// consider it in borrowck. We don't want to accept programs which /// pass borrowck only when `panic=abort` or some assertions are disabled - /// due to release vs. debug mode builds. This needs to be an `Option` because - /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes. - unwind: Option, + /// due to release vs. debug mode builds. + unwind: UnwindAction, }, /// Block ends with an inline assembly block. This is a terminator since @@ -745,12 +744,31 @@ pub enum TerminatorKind<'tcx> { /// diverging (InlineAsmOptions::NORETURN). destination: Option, - /// Cleanup to be done if the inline assembly unwinds. This is present + /// Action to be taken if the inline assembly unwinds. This is present /// if and only if InlineAsmOptions::MAY_UNWIND is set. - cleanup: Option, + unwind: UnwindAction, }, } +/// Action to be taken when a stack unwind happens. +#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub enum UnwindAction { + /// No action is to be taken. Continue unwinding. + /// + /// This is similar to `Cleanup(bb)` where `bb` does nothing but `Resume`, but they are not + /// equivalent, as presence of `Cleanup(_)` will make a frame non-POF. + Continue, + /// Triggers undefined behavior if unwind happens. + Unreachable, + /// Terminates the execution if unwind happens. + /// + /// Depending on the platform and situation this may cause a non-unwindable panic or abort. + Terminate, + /// Cleanups to be done. + Cleanup(BasicBlock), +} + /// Information about an assertion failure. #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] pub enum AssertKind { diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 0092401470f5..4f00abf7fabc 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -98,7 +98,7 @@ impl<'tcx> PlaceTy<'tcx> { ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64), ty::Array(inner, size) if from_end => { let size = size.eval_target_usize(tcx, param_env); - let len = size - (from as u64) - (to as u64); + let len = size - from - to; tcx.mk_array(*inner, len) } _ => bug!("cannot subslice non-array type: `{:?}`", self), diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index cd970270727f..2c6126cdd29c 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -1,6 +1,6 @@ use smallvec::SmallVec; -use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind}; +use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind, UnwindAction}; use rustc_ast::InlineAsmTemplatePiece; pub use rustc_ast::Mutability; use rustc_macros::HashStable; @@ -118,11 +118,11 @@ impl<'tcx> Terminator<'tcx> { self.kind.successors_mut() } - pub fn unwind(&self) -> Option<&Option> { + pub fn unwind(&self) -> Option<&UnwindAction> { self.kind.unwind() } - pub fn unwind_mut(&mut self) -> Option<&mut Option> { + pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> { self.kind.unwind_mut() } } @@ -135,34 +135,34 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn successors(&self) -> Successors<'_> { use self::TerminatorKind::*; match *self { + Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } + | Yield { resume: t, drop: Some(ref u), .. } + | Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. } + | Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. } + | FalseUnwind { real_target: t, unwind: UnwindAction::Cleanup(ref u) } + | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => { + Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied()) + } + Goto { target: t } + | Call { target: None, unwind: UnwindAction::Cleanup(t), .. } + | Call { target: Some(t), unwind: _, .. } + | Yield { resume: t, drop: None, .. } + | Drop { target: t, unwind: _, .. } + | Assert { target: t, unwind: _, .. } + | FalseUnwind { real_target: t, unwind: _ } + | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. } + | InlineAsm { destination: Some(t), unwind: _, .. } => { + Some(t).into_iter().chain((&[]).into_iter().copied()) + } Resume - | Abort + | Terminate | GeneratorDrop | Return | Unreachable - | Call { target: None, cleanup: None, .. } - | InlineAsm { destination: None, cleanup: None, .. } => { + | Call { target: None, unwind: _, .. } + | InlineAsm { destination: None, unwind: _, .. } => { None.into_iter().chain((&[]).into_iter().copied()) } - Goto { target: t } - | Call { target: None, cleanup: Some(t), .. } - | Call { target: Some(t), cleanup: None, .. } - | Yield { resume: t, drop: None, .. } - | Drop { target: t, unwind: None, .. } - | Assert { target: t, cleanup: None, .. } - | FalseUnwind { real_target: t, unwind: None } - | InlineAsm { destination: Some(t), cleanup: None, .. } - | InlineAsm { destination: None, cleanup: Some(t), .. } => { - Some(t).into_iter().chain((&[]).into_iter().copied()) - } - Call { target: Some(t), cleanup: Some(ref u), .. } - | Yield { resume: t, drop: Some(ref u), .. } - | Drop { target: t, unwind: Some(ref u), .. } - | Assert { target: t, cleanup: Some(ref u), .. } - | FalseUnwind { real_target: t, unwind: Some(ref u) } - | InlineAsm { destination: Some(t), cleanup: Some(ref u), .. } => { - Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied()) - } SwitchInt { ref targets, .. } => { None.into_iter().chain(targets.targets.iter().copied()) } @@ -175,32 +175,34 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { use self::TerminatorKind::*; match *self { + Call { target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), .. } + | Yield { resume: ref mut t, drop: Some(ref mut u), .. } + | Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. } + | Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. } + | FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u) } + | InlineAsm { + destination: Some(ref mut t), + unwind: UnwindAction::Cleanup(ref mut u), + .. + } => Some(t).into_iter().chain(slice::from_mut(u)), + Goto { target: ref mut t } + | Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. } + | Call { target: Some(ref mut t), unwind: _, .. } + | Yield { resume: ref mut t, drop: None, .. } + | Drop { target: ref mut t, unwind: _, .. } + | Assert { target: ref mut t, unwind: _, .. } + | FalseUnwind { real_target: ref mut t, unwind: _ } + | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(ref mut t), .. } + | InlineAsm { destination: Some(ref mut t), unwind: _, .. } => { + Some(t).into_iter().chain(&mut []) + } Resume - | Abort + | Terminate | GeneratorDrop | Return | Unreachable - | Call { target: None, cleanup: None, .. } - | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []), - Goto { target: ref mut t } - | Call { target: None, cleanup: Some(ref mut t), .. } - | Call { target: Some(ref mut t), cleanup: None, .. } - | Yield { resume: ref mut t, drop: None, .. } - | Drop { target: ref mut t, unwind: None, .. } - | Assert { target: ref mut t, cleanup: None, .. } - | FalseUnwind { real_target: ref mut t, unwind: None } - | InlineAsm { destination: Some(ref mut t), cleanup: None, .. } - | InlineAsm { destination: None, cleanup: Some(ref mut t), .. } => { - Some(t).into_iter().chain(&mut []) - } - Call { target: Some(ref mut t), cleanup: Some(ref mut u), .. } - | Yield { resume: ref mut t, drop: Some(ref mut u), .. } - | Drop { target: ref mut t, unwind: Some(ref mut u), .. } - | Assert { target: ref mut t, cleanup: Some(ref mut u), .. } - | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } - | InlineAsm { destination: Some(ref mut t), cleanup: Some(ref mut u), .. } => { - Some(t).into_iter().chain(slice::from_mut(u)) - } + | Call { target: None, unwind: _, .. } + | InlineAsm { destination: None, unwind: _, .. } => None.into_iter().chain(&mut []), SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets), FalseEdge { ref mut real_target, ref mut imaginary_target } => { Some(real_target).into_iter().chain(slice::from_mut(imaginary_target)) @@ -208,41 +210,41 @@ impl<'tcx> TerminatorKind<'tcx> { } } - pub fn unwind(&self) -> Option<&Option> { + pub fn unwind(&self) -> Option<&UnwindAction> { match *self { TerminatorKind::Goto { .. } | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } | TerminatorKind::SwitchInt { .. } | TerminatorKind::FalseEdge { .. } => None, - TerminatorKind::Call { cleanup: ref unwind, .. } - | TerminatorKind::Assert { cleanup: ref unwind, .. } + TerminatorKind::Call { ref unwind, .. } + | TerminatorKind::Assert { ref unwind, .. } | TerminatorKind::Drop { ref unwind, .. } | TerminatorKind::FalseUnwind { ref unwind, .. } - | TerminatorKind::InlineAsm { cleanup: ref unwind, .. } => Some(unwind), + | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind), } } - pub fn unwind_mut(&mut self) -> Option<&mut Option> { + pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> { match *self { TerminatorKind::Goto { .. } | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } | TerminatorKind::SwitchInt { .. } | TerminatorKind::FalseEdge { .. } => None, - TerminatorKind::Call { cleanup: ref mut unwind, .. } - | TerminatorKind::Assert { cleanup: ref mut unwind, .. } + TerminatorKind::Call { ref mut unwind, .. } + | TerminatorKind::Assert { ref mut unwind, .. } | TerminatorKind::Drop { ref mut unwind, .. } | TerminatorKind::FalseUnwind { ref mut unwind, .. } - | TerminatorKind::InlineAsm { cleanup: ref mut unwind, .. } => Some(unwind), + | TerminatorKind::InlineAsm { ref mut unwind, .. } => Some(unwind), } } @@ -268,11 +270,17 @@ impl<'tcx> Debug for TerminatorKind<'tcx> { let labels = self.fmt_successor_labels(); assert_eq!(successor_count, labels.len()); - match successor_count { - 0 => Ok(()), - - 1 => write!(fmt, " -> {:?}", self.successors().next().unwrap()), + let unwind = match self.unwind() { + // Not needed or included in successors + None | Some(UnwindAction::Continue) | Some(UnwindAction::Cleanup(_)) => None, + Some(UnwindAction::Unreachable) => Some("unwind unreachable"), + Some(UnwindAction::Terminate) => Some("unwind terminate"), + }; + match (successor_count, unwind) { + (0, None) => Ok(()), + (0, Some(unwind)) => write!(fmt, " -> {}", unwind), + (1, None) => write!(fmt, " -> {:?}", self.successors().next().unwrap()), _ => { write!(fmt, " -> [")?; for (i, target) in self.successors().enumerate() { @@ -281,6 +289,9 @@ impl<'tcx> Debug for TerminatorKind<'tcx> { } write!(fmt, "{}: {:?}", labels[i], target)?; } + if let Some(unwind) = unwind { + write!(fmt, ", {unwind}")?; + } write!(fmt, "]") } } @@ -299,7 +310,7 @@ impl<'tcx> TerminatorKind<'tcx> { Return => write!(fmt, "return"), GeneratorDrop => write!(fmt, "generator_drop"), Resume => write!(fmt, "resume"), - Abort => write!(fmt, "abort"), + Terminate => write!(fmt, "abort"), Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value), Unreachable => write!(fmt, "unreachable"), Drop { place, .. } => write!(fmt, "drop({:?})", place), @@ -378,7 +389,7 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn fmt_successor_labels(&self) -> Vec> { use self::TerminatorKind::*; match *self { - Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], + Return | Resume | Terminate | Unreachable | GeneratorDrop => vec![], Goto { .. } => vec!["".into()], SwitchInt { ref targets, .. } => targets .values @@ -386,31 +397,35 @@ impl<'tcx> TerminatorKind<'tcx> { .map(|&u| Cow::Owned(u.to_string())) .chain(iter::once("otherwise".into())) .collect(), - Call { target: Some(_), cleanup: Some(_), .. } => { + Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => { vec!["return".into(), "unwind".into()] } - Call { target: Some(_), cleanup: None, .. } => vec!["return".into()], - Call { target: None, cleanup: Some(_), .. } => vec!["unwind".into()], - Call { target: None, cleanup: None, .. } => vec![], + Call { target: Some(_), unwind: _, .. } => vec!["return".into()], + Call { target: None, unwind: UnwindAction::Cleanup(_), .. } => vec!["unwind".into()], + Call { target: None, unwind: _, .. } => vec![], Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()], Yield { drop: None, .. } => vec!["resume".into()], - Drop { unwind: None, .. } => { + Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()], + Drop { unwind: _, .. } => vec!["return".into()], + Assert { unwind: UnwindAction::Cleanup(_), .. } => { + vec!["success".into(), "unwind".into()] + } + Assert { unwind: _, .. } => vec!["success".into()], + FalseEdge { .. } => vec!["real".into(), "imaginary".into()], + FalseUnwind { unwind: UnwindAction::Cleanup(_), .. } => { + vec!["real".into(), "unwind".into()] + } + FalseUnwind { unwind: _, .. } => vec!["real".into()], + InlineAsm { destination: Some(_), unwind: UnwindAction::Cleanup(_), .. } => { + vec!["return".into(), "unwind".into()] + } + InlineAsm { destination: Some(_), unwind: _, .. } => { vec!["return".into()] } - Drop { unwind: Some(_), .. } => { - vec!["return".into(), "unwind".into()] + InlineAsm { destination: None, unwind: UnwindAction::Cleanup(_), .. } => { + vec!["unwind".into()] } - Assert { cleanup: None, .. } => vec!["".into()], - Assert { .. } => vec!["success".into(), "unwind".into()], - FalseEdge { .. } => vec!["real".into(), "imaginary".into()], - FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()], - FalseUnwind { unwind: None, .. } => vec!["real".into()], - InlineAsm { destination: Some(_), cleanup: Some(_), .. } => { - vec!["return".into(), "unwind".into()] - } - InlineAsm { destination: Some(_), cleanup: None, .. } => vec!["return".into()], - InlineAsm { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()], - InlineAsm { destination: None, cleanup: None, .. } => vec![], + InlineAsm { destination: None, unwind: _, .. } => vec![], } } } diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 62cdf794b1e9..7d247eeb656c 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -178,17 +178,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // When we yield `B` and call `traverse_successor`, we push `C` to the stack, but // since we've already visited `E`, that child isn't added to the stack. The last // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A] - loop { - let bb = if let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() { - if let Some(bb) = iter.next() { - bb - } else { - break; - } - } else { - break; - }; - + while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next() { if self.visited.insert(bb) { if let Some(term) = &self.basic_blocks[bb].terminator { self.visit_stack.push((bb, term.successors())); diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 7aa446ae966c..6c4ea065abeb 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -462,7 +462,7 @@ macro_rules! make_mir_visitor { match kind { TerminatorKind::Goto { .. } | TerminatorKind::Resume | - TerminatorKind::Abort | + TerminatorKind::Terminate | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable | TerminatorKind::FalseEdge { .. } | @@ -509,7 +509,7 @@ macro_rules! make_mir_visitor { args, destination, target: _, - cleanup: _, + unwind: _, from_hir_call: _, fn_span: _ } => { @@ -529,7 +529,7 @@ macro_rules! make_mir_visitor { expected: _, msg, target: _, - cleanup: _, + unwind: _, } => { self.visit_operand(cond, location); self.visit_assert_message(msg, location); @@ -555,7 +555,7 @@ macro_rules! make_mir_visitor { options: _, line_spans: _, destination: _, - cleanup: _, + unwind: _, } => { for op in operands { match op { diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs new file mode 100644 index 000000000000..24d98665a7b4 --- /dev/null +++ b/compiler/rustc_middle/src/query/erase.rs @@ -0,0 +1,336 @@ +use crate::mir; +use crate::traits; +use crate::ty::{self, Ty}; +use std::mem::{size_of, transmute_copy, MaybeUninit}; + +#[derive(Copy, Clone)] +pub struct Erased { + // We use `MaybeUninit` here so we can store any value + // in `data` since we aren't actually storing a `T`. + data: MaybeUninit, +} + +pub trait EraseType: Copy { + type Result: Copy; +} + +// Allow `type_alias_bounds` since compilation will fail without `EraseType`. +#[allow(type_alias_bounds)] +pub type Erase = Erased; + +#[inline(always)] +pub fn erase(src: T) -> Erase { + // Ensure the sizes match + const { + if std::mem::size_of::() != std::mem::size_of::() { + panic!("size of T must match erased type T::Result") + } + }; + + Erased::<::Result> { + // SAFETY: Is it safe to transmute to MaybeUninit for types with the same sizes. + data: unsafe { transmute_copy(&src) }, + } +} + +/// Restores an erased value. +#[inline(always)] +pub fn restore(value: Erase) -> T { + let value: Erased<::Result> = value; + // SAFETY: Due to the use of impl Trait in `Erase` the only way to safetly create an instance + // of `Erase` is to call `erase`, so we know that `value.data` is a valid instance of `T` of + // the right size. + unsafe { transmute_copy(&value.data) } +} + +impl EraseType for &'_ T { + type Result = [u8; size_of::<*const ()>()]; +} + +impl EraseType for &'_ [T] { + type Result = [u8; size_of::<*const [()]>()]; +} + +impl EraseType for &'_ ty::List { + type Result = [u8; size_of::<*const ()>()]; +} + +impl EraseType for Result<&'_ T, traits::query::NoSolution> { + type Result = [u8; size_of::>()]; +} + +impl EraseType for Result<&'_ T, rustc_errors::ErrorGuaranteed> { + type Result = [u8; size_of::>()]; +} + +impl EraseType for Result<&'_ T, traits::CodegenObligationError> { + type Result = [u8; size_of::>()]; +} + +impl EraseType for Result<&'_ T, ty::layout::FnAbiError<'_>> { + type Result = [u8; size_of::>>()]; +} + +impl EraseType for Result<(&'_ T, rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed> { + type Result = [u8; size_of::< + Result<(&'static (), rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed>, + >()]; +} + +impl EraseType for Result>, rustc_errors::ErrorGuaranteed> { + type Result = + [u8; size_of::>, rustc_errors::ErrorGuaranteed>>()]; +} + +impl EraseType for Result>, rustc_errors::ErrorGuaranteed> { + type Result = + [u8; size_of::>, rustc_errors::ErrorGuaranteed>>()]; +} + +impl EraseType for Result, traits::query::NoSolution> { + type Result = [u8; size_of::, traits::query::NoSolution>>()]; +} + +impl EraseType for Result> { + type Result = [u8; size_of::>>()]; +} + +impl EraseType for Result>, ty::layout::LayoutError<'_>> { + type Result = [u8; size_of::< + Result< + rustc_target::abi::TyAndLayout<'static, Ty<'static>>, + ty::layout::LayoutError<'static>, + >, + >()]; +} + +impl EraseType for Result, mir::interpret::LitToConstError> { + type Result = [u8; size_of::, mir::interpret::LitToConstError>>()]; +} + +impl EraseType for Result, mir::interpret::LitToConstError> { + type Result = + [u8; size_of::, mir::interpret::LitToConstError>>()]; +} + +impl EraseType for Result, mir::interpret::ErrorHandled> { + type Result = [u8; size_of::< + Result, mir::interpret::ErrorHandled>, + >()]; +} + +impl EraseType for Result, mir::interpret::ErrorHandled> { + type Result = [u8; size_of::< + Result, mir::interpret::ErrorHandled>, + >()]; +} + +impl EraseType for Result>, mir::interpret::ErrorHandled> { + type Result = + [u8; size_of::>, mir::interpret::ErrorHandled>>()]; +} + +impl EraseType for Result<&'_ ty::List>, ty::util::AlwaysRequiresDrop> { + type Result = + [u8; size_of::>, ty::util::AlwaysRequiresDrop>>()]; +} + +impl EraseType for Option<&'_ T> { + type Result = [u8; size_of::>()]; +} + +impl EraseType for Option<&'_ [T]> { + type Result = [u8; size_of::>()]; +} + +impl EraseType for Option> { + type Result = [u8; size_of::>>()]; +} + +impl EraseType for Option> { + type Result = [u8; size_of::>>()]; +} + +impl EraseType for Option>> { + type Result = [u8; size_of::>>>()]; +} + +impl EraseType for Option>> { + type Result = [u8; size_of::>>>()]; +} + +impl EraseType for rustc_hir::MaybeOwner<&'_ T> { + type Result = [u8; size_of::>()]; +} + +impl EraseType for ty::EarlyBinder { + type Result = T::Result; +} + +impl EraseType for ty::Binder<'_, ty::FnSig<'_>> { + type Result = [u8; size_of::>>()]; +} + +impl EraseType for (&'_ T0, &'_ T1) { + type Result = [u8; size_of::<(&'static (), &'static ())>()]; +} + +impl EraseType for (&'_ T0, &'_ [T1]) { + type Result = [u8; size_of::<(&'static (), &'static [()])>()]; +} + +macro_rules! trivial { + ($($ty:ty),+ $(,)?) => { + $( + impl EraseType for $ty { + type Result = [u8; size_of::<$ty>()]; + } + )* + } +} + +trivial! { + (), + bool, + Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Result<(), rustc_errors::ErrorGuaranteed>, + Result<(), rustc_middle::traits::query::NoSolution>, + Result, + rustc_ast::expand::allocator::AllocatorKind, + rustc_attr::ConstStability, + rustc_attr::DefaultBodyStability, + rustc_attr::Deprecation, + rustc_attr::Stability, + rustc_data_structures::svh::Svh, + rustc_errors::ErrorGuaranteed, + rustc_hir::Constness, + rustc_hir::def_id::DefId, + rustc_hir::def_id::DefIndex, + rustc_hir::def_id::LocalDefId, + rustc_hir::def::DefKind, + rustc_hir::Defaultness, + rustc_hir::definitions::DefKey, + rustc_hir::GeneratorKind, + rustc_hir::HirId, + rustc_hir::IsAsync, + rustc_hir::ItemLocalId, + rustc_hir::LangItem, + rustc_hir::OwnerId, + rustc_hir::Upvar, + rustc_index::bit_set::FiniteBitSet, + rustc_middle::middle::dependency_format::Linkage, + rustc_middle::middle::exported_symbols::SymbolExportInfo, + rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault, + rustc_middle::middle::resolve_bound_vars::ResolvedArg, + rustc_middle::middle::stability::DeprecationEntry, + rustc_middle::mir::ConstQualifs, + rustc_middle::mir::interpret::AllocId, + rustc_middle::mir::interpret::ErrorHandled, + rustc_middle::mir::interpret::LitToConstError, + rustc_middle::thir::ExprId, + rustc_middle::traits::CodegenObligationError, + rustc_middle::traits::EvaluationResult, + rustc_middle::traits::OverflowError, + rustc_middle::traits::query::NoSolution, + rustc_middle::traits::WellFormedLoc, + rustc_middle::ty::adjustment::CoerceUnsizedInfo, + rustc_middle::ty::AssocItem, + rustc_middle::ty::AssocItemContainer, + rustc_middle::ty::BoundVariableKind, + rustc_middle::ty::DeducedParamAttrs, + rustc_middle::ty::Destructor, + rustc_middle::ty::fast_reject::SimplifiedType, + rustc_middle::ty::ImplPolarity, + rustc_middle::ty::Representability, + rustc_middle::ty::ReprOptions, + rustc_middle::ty::UnusedGenericParams, + rustc_middle::ty::util::AlwaysRequiresDrop, + rustc_middle::ty::Visibility, + rustc_session::config::CrateType, + rustc_session::config::EntryFnType, + rustc_session::config::OptLevel, + rustc_session::config::SymbolManglingVersion, + rustc_session::cstore::CrateDepKind, + rustc_session::cstore::ExternCrate, + rustc_session::cstore::LinkagePreference, + rustc_session::Limits, + rustc_session::lint::LintExpectationId, + rustc_span::def_id::CrateNum, + rustc_span::def_id::DefPathHash, + rustc_span::ExpnHash, + rustc_span::ExpnId, + rustc_span::Span, + rustc_span::Symbol, + rustc_span::symbol::Ident, + rustc_target::spec::PanicStrategy, + rustc_type_ir::Variance, + u32, + usize, +} + +macro_rules! tcx_lifetime { + ($($($fake_path:ident)::+),+ $(,)?) => { + $( + impl<'tcx> EraseType for $($fake_path)::+<'tcx> { + type Result = [u8; size_of::<$($fake_path)::+<'static>>()]; + } + )* + } +} + +tcx_lifetime! { + rustc_middle::hir::Owner, + rustc_middle::middle::exported_symbols::ExportedSymbol, + rustc_middle::mir::ConstantKind, + rustc_middle::mir::DestructuredConstant, + rustc_middle::mir::interpret::ConstAlloc, + rustc_middle::mir::interpret::ConstValue, + rustc_middle::mir::interpret::GlobalId, + rustc_middle::mir::interpret::LitToConstInput, + rustc_middle::traits::ChalkEnvironmentAndGoal, + rustc_middle::traits::query::MethodAutoderefStepsResult, + rustc_middle::traits::query::type_op::AscribeUserType, + rustc_middle::traits::query::type_op::Eq, + rustc_middle::traits::query::type_op::ProvePredicate, + rustc_middle::traits::query::type_op::Subtype, + rustc_middle::ty::AdtDef, + rustc_middle::ty::AliasTy, + rustc_middle::ty::Clause, + rustc_middle::ty::ClosureTypeInfo, + rustc_middle::ty::Const, + rustc_middle::ty::DestructuredConst, + rustc_middle::ty::ExistentialTraitRef, + rustc_middle::ty::FnSig, + rustc_middle::ty::GenericArg, + rustc_middle::ty::GenericPredicates, + rustc_middle::ty::inhabitedness::InhabitedPredicate, + rustc_middle::ty::Instance, + rustc_middle::ty::InstanceDef, + rustc_middle::ty::layout::FnAbiError, + rustc_middle::ty::layout::LayoutError, + rustc_middle::ty::ParamEnv, + rustc_middle::ty::Predicate, + rustc_middle::ty::SymbolName, + rustc_middle::ty::TraitRef, + rustc_middle::ty::Ty, + rustc_middle::ty::UnevaluatedConst, + rustc_middle::ty::ValTree, + rustc_middle::ty::VtblEntry, +} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9203dd59a7e6..a0fce4b47ca3 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -7,6 +7,7 @@ use crate::ty::{self, print::describe_as_module, TyCtxt}; use rustc_span::def_id::LOCAL_CRATE; +pub mod erase; mod keys; pub use keys::{AsLocalKey, Key, LocalCrate}; @@ -1114,9 +1115,9 @@ rustc_queries! { desc { "converting literal to mir constant" } } - query check_match(key: DefId) { - desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } + query check_match(key: LocalDefId) { + desc { |tcx| "match-checking `{}`", tcx.def_path_str(key.to_def_id()) } + cache_on_disk_if { true } } /// Performs part of the privacy check and computes effective visibilities. @@ -1509,7 +1510,7 @@ rustc_queries! { desc { "getting traits in scope at a block" } } - query module_reexports(def_id: LocalDefId) -> Option<&'tcx [ModChild]> { + query module_reexports(def_id: LocalDefId) -> &'tcx [ModChild] { desc { |tcx| "looking up reexports of module `{}`", tcx.def_path_str(def_id.to_def_id()) } } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 82a7cf785173..7d79a13d3fde 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -227,6 +227,9 @@ pub enum StmtKind<'tcx> { /// The lint level for this `let` statement. lint_level: LintLevel, + + /// Span of the `let = ` part. + span: Span, }, } @@ -594,6 +597,55 @@ impl<'tcx> Pat<'tcx> { _ => None, } } + + /// Call `f` on every "binding" in a pattern, e.g., on `a` in + /// `match foo() { Some(a) => (), None => () }` + pub fn each_binding(&self, mut f: impl FnMut(Symbol, BindingMode, Ty<'tcx>, Span)) { + self.walk_always(|p| { + if let PatKind::Binding { name, mode, ty, .. } = p.kind { + f(name, mode, ty, p.span); + } + }); + } + + /// Walk the pattern in left-to-right order. + /// + /// If `it(pat)` returns `false`, the children are not visited. + pub fn walk(&self, mut it: impl FnMut(&Pat<'tcx>) -> bool) { + self.walk_(&mut it) + } + + fn walk_(&self, it: &mut impl FnMut(&Pat<'tcx>) -> bool) { + if !it(self) { + return; + } + + use PatKind::*; + match &self.kind { + Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } => {} + AscribeUserType { subpattern, .. } + | Binding { subpattern: Some(subpattern), .. } + | Deref { subpattern } => subpattern.walk_(it), + Leaf { subpatterns } | Variant { subpatterns, .. } => { + subpatterns.iter().for_each(|field| field.pattern.walk_(it)) + } + Or { pats } => pats.iter().for_each(|p| p.walk_(it)), + Array { box ref prefix, ref slice, box ref suffix } + | Slice { box ref prefix, ref slice, box ref suffix } => { + prefix.iter().chain(slice.iter()).chain(suffix.iter()).for_each(|p| p.walk_(it)) + } + } + } + + /// Walk the pattern in left-to-right order. + /// + /// If you always want to recurse, prefer this method over `walk`. + pub fn walk_always(&self, mut it: impl FnMut(&Pat<'tcx>)) { + self.walk(|p| { + it(p); + true + }) + } } impl<'tcx> IntoDiagnosticArg for Pat<'tcx> { @@ -879,7 +931,7 @@ mod size_asserts { static_assert_size!(ExprKind<'_>, 40); static_assert_size!(Pat<'_>, 72); static_assert_size!(PatKind<'_>, 56); - static_assert_size!(Stmt<'_>, 48); - static_assert_size!(StmtKind<'_>, 40); + static_assert_size!(Stmt<'_>, 56); + static_assert_size!(StmtKind<'_>, 48); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 79a0e75aa7c7..5614528c4cb2 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -175,6 +175,7 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm ref pattern, lint_level: _, else_block, + span: _, } => { if let Some(init) = initializer { visitor.visit_expr(&visitor.thir()[*init]); diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 833402abfc47..6a8ae525069c 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -923,7 +923,7 @@ impl ObjectSafetyViolation { } } ObjectSafetyViolation::SupertraitNonLifetimeBinder(_) => { - format!("where clause cannot reference non-lifetime `for<...>` variables").into() + "where clause cannot reference non-lifetime `for<...>` variables".into() } ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { format!("associated function `{}` has no `self` parameter", name).into() diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 512d67f34b97..fef2be133e81 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -20,8 +20,8 @@ pub type EvaluationCache<'tcx> = Cache, QueryResult<'tcx>>; /// we're currently typechecking while the `predicate` is some trait bound. #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] pub struct Goal<'tcx, P> { - pub param_env: ty::ParamEnv<'tcx>, pub predicate: P, + pub param_env: ty::ParamEnv<'tcx>, } impl<'tcx, P> Goal<'tcx, P> { @@ -41,10 +41,10 @@ impl<'tcx, P> Goal<'tcx, P> { #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] pub struct Response<'tcx> { + pub certainty: Certainty, pub var_values: CanonicalVarValues<'tcx>, /// Additional constraints returned by this query. pub external_constraints: ExternalConstraints<'tcx>, - pub certainty: Certainty, } #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] @@ -56,9 +56,19 @@ pub enum Certainty { impl Certainty { pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity); - /// When proving multiple goals using **AND**, e.g. nested obligations for an impl, - /// use this function to unify the certainty of these goals - pub fn unify_and(self, other: Certainty) -> Certainty { + /// Use this function to merge the certainty of multiple nested subgoals. + /// + /// Given an impl like `impl Baz for T {}`, we have 2 nested + /// subgoals whenever we use the impl as a candidate: `T: Foo` and `T: Bar`. + /// If evaluating `T: Foo` results in ambiguity and `T: Bar` results in + /// success, we merge these two responses. This results in ambiguity. + /// + /// If we unify ambiguity with overflow, we return overflow. This doesn't matter + /// inside of the solver as we distinguish ambiguity from overflow. It does + /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar` + /// in ambiguity without changing the inference state, we still want to tell the + /// user that `T: Baz` results in overflow. + pub fn unify_with(self, other: Certainty) -> Certainty { match (self, other) { (Certainty::Yes, Certainty::Yes) => Certainty::Yes, (Certainty::Yes, Certainty::Maybe(_)) => other, @@ -105,7 +115,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { type Target = ExternalConstraintsData<'tcx>; fn deref(&self) -> &Self::Target { - &*self.0 + &self.0 } } diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index df9aa765dc15..468c2c818b24 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -37,10 +37,6 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { self.tcx } - fn intercrate(&self) -> bool { - false - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } @@ -48,10 +44,6 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { true } // irrelevant - fn mark_ambiguous(&mut self) { - bug!() - } - fn relate_with_variance>( &mut self, _: ty::Variance, diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 3ce80e06ad9e..8ef4a46a733a 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -511,8 +511,6 @@ macro_rules! implement_ty_decoder { read_isize -> isize; read_bool -> bool; - read_f64 -> f64; - read_f32 -> f32; read_char -> char; read_str -> &str; } diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index a7f38884ebcc..c0e557d480d3 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -337,7 +337,7 @@ impl ScalarInt { /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 16 }` /// and returns the `ScalarInt`s size in that case. pub fn try_to_i128(self) -> Result { - self.try_to_int(Size::from_bits(128)).map(|v| i128::try_from(v).unwrap()) + self.try_to_int(Size::from_bits(128)) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8d0aa622244c..c312aaf6819a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -311,7 +311,7 @@ pub struct CommonLifetimes<'tcx> { pub re_vars: Vec>, /// Pre-interned values of the form: - /// `ReLateBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon(v, None) })` + /// `ReLateBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon(None) })` /// for small values of `i` and `v`. pub re_late_bounds: Vec>>, } @@ -386,10 +386,7 @@ impl<'tcx> CommonLifetimes<'tcx> { .map(|v| { mk(ty::ReLateBound( ty::DebruijnIndex::from(i), - ty::BoundRegion { - var: ty::BoundVar::from(v), - kind: ty::BrAnon(v, None), - }, + ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BrAnon(None) }, )) }) .collect() @@ -927,7 +924,7 @@ impl<'tcx> TyCtxt<'tcx> { crate_name, // Don't print the whole stable crate id. That's just // annoying in debug output. - stable_crate_id.to_u64() >> 8 * 6, + stable_crate_id.to_u64() >> (8 * 6), self.def_path(def_id).to_string_no_crate_verbose() ) } @@ -2075,10 +2072,9 @@ impl<'tcx> TyCtxt<'tcx> { bound_region: ty::BoundRegion, ) -> Region<'tcx> { // Use a pre-interned one when possible. - if let ty::BoundRegion { var, kind: ty::BrAnon(v, None) } = bound_region - && var.as_u32() == v + if let ty::BoundRegion { var, kind: ty::BrAnon(None) } = bound_region && let Some(inner) = self.lifetimes.re_late_bounds.get(debruijn.as_usize()) - && let Some(re) = inner.get(v as usize).copied() + && let Some(re) = inner.get(var.as_usize()).copied() { re } else { @@ -2383,7 +2379,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> { let map = self.in_scope_traits_map(id.owner)?; let candidates = map.get(&id.local_id)?; - Some(&*candidates) + Some(candidates) } pub fn named_bound_var(self, id: HirId) -> Option { @@ -2506,7 +2502,7 @@ pub struct DeducedParamAttrs { pub fn provide(providers: &mut ty::query::Providers) { providers.module_reexports = - |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]); + |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map_or(&[], |v| &v[..]); providers.maybe_unused_trait_imports = |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports; providers.names_imported_by_glob_use = |tcx, id| { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 6205e2bf24dd..203e16bea27f 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -379,9 +379,7 @@ impl<'tcx> TyCtxt<'tcx> { let index = entry.index(); let var = ty::BoundVar::from_usize(index); let kind = entry - .or_insert_with(|| { - ty::BoundVariableKind::Region(ty::BrAnon(index as u32, None)) - }) + .or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon(None))) .expect_region(); let br = ty::BoundRegion { var, kind }; self.tcx.mk_re_late_bound(ty::INNERMOST, br) @@ -391,9 +389,7 @@ impl<'tcx> TyCtxt<'tcx> { let index = entry.index(); let var = ty::BoundVar::from_usize(index); let kind = entry - .or_insert_with(|| { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon(index as u32)) - }) + .or_insert_with(|| ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon)) .expect_ty(); self.tcx.mk_bound(ty::INNERMOST, BoundTy { var, kind }) } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 0f70b315aa6e..2328a1324fc3 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -5,6 +5,7 @@ use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitableExt}; use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_index::vec::IndexVec; use rustc_session::config::OptLevel; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -280,6 +281,12 @@ pub enum SizeSkeleton<'tcx> { /// Any statically computable Layout. Known(Size), + /// This is a generic const expression (i.e. N * 2), which may contain some parameters. + /// It must be of type usize, and represents the size of a type in bytes. + /// It is not required to be evaluatable to a concrete value, but can be used to check + /// that another SizeSkeleton is of equal size. + Generic(ty::Const<'tcx>), + /// A potentially-fat pointer. Pointer { /// If true, this pointer is never null. @@ -325,6 +332,37 @@ impl<'tcx> SizeSkeleton<'tcx> { ), } } + ty::Array(inner, len) + if len.ty() == tcx.types.usize && tcx.features().transmute_generic_consts => + { + match SizeSkeleton::compute(inner, tcx, param_env)? { + // This may succeed because the multiplication of two types may overflow + // but a single size of a nested array will not. + SizeSkeleton::Known(s) => { + if let Some(c) = len.try_eval_target_usize(tcx, param_env) { + let size = s + .bytes() + .checked_mul(c) + .ok_or_else(|| LayoutError::SizeOverflow(ty))?; + return Ok(SizeSkeleton::Known(Size::from_bytes(size))); + } + let len = tcx.expand_abstract_consts(len); + let prev = ty::Const::from_target_usize(tcx, s.bytes()); + let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, prev) else { + return Err(LayoutError::SizeOverflow(ty)); + }; + Ok(SizeSkeleton::Generic(gen_size)) + } + SizeSkeleton::Pointer { .. } => Err(err), + SizeSkeleton::Generic(g) => { + let len = tcx.expand_abstract_consts(len); + let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, g) else { + return Err(LayoutError::SizeOverflow(ty)); + }; + Ok(SizeSkeleton::Generic(gen_size)) + } + } + } ty::Adt(def, substs) => { // Only newtypes and enums w/ nullable pointer optimization. @@ -354,6 +392,9 @@ impl<'tcx> SizeSkeleton<'tcx> { } ptr = Some(field); } + SizeSkeleton::Generic(_) => { + return Err(err); + } } } Ok(ptr) @@ -409,11 +450,66 @@ impl<'tcx> SizeSkeleton<'tcx> { (SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => { a == b } + // constants are always pre-normalized into a canonical form so this + // only needs to check if their pointers are identical. + (SizeSkeleton::Generic(a), SizeSkeleton::Generic(b)) => a == b, _ => false, } } } +/// When creating the layout for types with abstract conts in their size (i.e. [usize; 4 * N]), +/// to ensure that they have a canonical order and can be compared directly we combine all +/// constants, and sort the other terms. This allows comparison of expressions of sizes, +/// allowing for things like transmutating between types that depend on generic consts. +/// This returns `None` if multiplication of constants overflows. +fn mul_sorted_consts<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, +) -> Option> { + use crate::mir::BinOp::Mul; + use ty::ConstKind::Expr; + use ty::Expr::Binop; + + let mut work = vec![a, b]; + let mut done = vec![]; + while let Some(n) = work.pop() { + if let Expr(Binop(Mul, l, r)) = n.kind() { + work.push(l); + work.push(r) + } else { + done.push(n); + } + } + let mut k = 1; + let mut overflow = false; + done.retain(|c| { + let Some(c) = c.try_eval_target_usize(tcx, param_env) else { + return true; + }; + let Some(next) = c.checked_mul(k) else { + overflow = true; + return false; + }; + k = next; + false + }); + if overflow { + return None; + } + if k != 1 { + done.push(ty::Const::from_target_usize(tcx, k)); + } else if k == 0 { + return Some(ty::Const::from_target_usize(tcx, 0)); + } + done.sort_unstable(); + + // create a single tree from the buffer + done.into_iter().reduce(|acc, n| tcx.mk_const(Expr(Binop(Mul, n, acc)), n.ty())) +} + pub trait HasTyCtxt<'tcx>: HasDataLayout { fn tcx(&self) -> TyCtxt<'tcx>; } @@ -635,7 +731,7 @@ where variants: Variants::Single { index: variant_index }, fields: match NonZeroUsize::new(fields) { Some(fields) => FieldsShape::Union(fields), - None => FieldsShape::Arbitrary { offsets: vec![], memory_index: vec![] }, + None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() }, }, abi: Abi::Uninhabited, largest_niche: None, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 800a230b6544..c856bb25e147 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1454,12 +1454,12 @@ impl<'tcx> OpaqueHiddenType<'tcx> { #[derive(HashStable, TyEncodable, TyDecodable)] pub struct Placeholder { pub universe: UniverseIndex, - pub name: T, + pub bound: T, } -pub type PlaceholderRegion = Placeholder; +pub type PlaceholderRegion = Placeholder; -pub type PlaceholderType = Placeholder; +pub type PlaceholderType = Placeholder; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] #[derive(TyEncodable, TyDecodable, PartialOrd, Ord)] diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 578cd82aa4c2..7c59879a187f 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -193,9 +193,9 @@ impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { let arg = self.param_env.and(arg); self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!( - "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead", - arg.value - )) + "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead", + arg.value + )) } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index de4c703107e1..bc0ccc1ebc3a 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -701,9 +701,7 @@ pub trait PrettyPrinter<'tcx>: ty::Error(_) => p!("[type error]"), ty::Param(ref param_ty) => p!(print(param_ty)), ty::Bound(debruijn, bound_ty) => match bound_ty.kind { - ty::BoundTyKind::Anon(bv) => { - self.pretty_print_bound_var(debruijn, ty::BoundVar::from_u32(bv))? - } + ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?, ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() { true if debruijn == ty::INNERMOST => p!(write("^{}", s)), true => p!(write("^{}_{}", debruijn.index(), s)), @@ -739,8 +737,8 @@ pub trait PrettyPrinter<'tcx>: p!(print(data)) } } - ty::Placeholder(placeholder) => match placeholder.name { - ty::BoundTyKind::Anon(_) => p!(write("Placeholder({:?})", placeholder)), + ty::Placeholder(placeholder) => match placeholder.bound.kind { + ty::BoundTyKind::Anon => p!(write("Placeholder({:?})", placeholder)), ty::BoundTyKind::Param(_, name) => p!(write("{}", name)), }, ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { @@ -2104,7 +2102,9 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { ty::ReLateBound(_, ty::BoundRegion { kind: br, .. }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) - | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { + | ty::RePlaceholder(ty::Placeholder { + bound: ty::BoundRegion { kind: br, .. }, .. + }) => { if br.is_named() { return true; } @@ -2181,7 +2181,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { } ty::ReLateBound(_, ty::BoundRegion { kind: br, .. }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) - | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { + | ty::RePlaceholder(ty::Placeholder { + bound: ty::BoundRegion { kind: br, .. }, .. + }) => { if let ty::BrNamed(_, name) = br && br.is_named() { p!(write("{}", name)); return Ok(self); @@ -2259,7 +2261,10 @@ impl<'a, 'tcx> ty::TypeFolder> for RegionFolder<'a, 'tcx> { ty::ReLateBound(db, br) if db >= self.current_index => { *self.region_map.entry(br).or_insert_with(|| name(Some(db), self.current_index, br)) } - ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => { + ty::RePlaceholder(ty::PlaceholderRegion { + bound: ty::BoundRegion { kind, .. }, + .. + }) => { // If this is an anonymous placeholder, don't rename. Otherwise, in some // async fns, we get a `for<'r> Send` bound match kind { diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 30246fe4dbeb..fa9fea723448 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -17,6 +17,7 @@ use crate::mir::interpret::{ }; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; +use crate::query::erase::{erase, restore, Erase}; use crate::query::{AsLocalKey, Key}; use crate::thir; use crate::traits::query::{ @@ -57,6 +58,8 @@ use rustc_hir::hir_id::OwnerId; use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; use rustc_index::vec::IndexVec; +pub(crate) use rustc_query_system::query::QueryJobId; +use rustc_query_system::query::*; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::cstore::{CrateDepKind, CrateSource}; use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; @@ -66,18 +69,19 @@ use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi; use rustc_target::spec::PanicStrategy; + +use std::marker::PhantomData; use std::mem; use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; -pub(crate) use rustc_query_system::query::QueryJobId; -use rustc_query_system::query::*; - #[derive(Default)] pub struct QuerySystem<'tcx> { pub arenas: QueryArenas<'tcx>, pub caches: QueryCaches<'tcx>, + // Since we erase query value types we tell the typesystem about them with `PhantomData`. + _phantom_values: QueryPhantomValues<'tcx>, } #[derive(Copy, Clone)] @@ -263,8 +267,8 @@ macro_rules! define_callbacks { pub fn $name<'tcx>( _tcx: TyCtxt<'tcx>, value: query_provided::$name<'tcx>, - ) -> query_values::$name<'tcx> { - query_if_arena!([$($modifiers)*] + ) -> Erase> { + erase(query_if_arena!([$($modifiers)*] { if mem::needs_drop::>() { &*_tcx.query_system.arenas.$name.alloc(value) @@ -273,7 +277,7 @@ macro_rules! define_callbacks { } } (value) - ) + )) } )* } @@ -282,7 +286,7 @@ macro_rules! define_callbacks { use super::*; $( - pub type $name<'tcx> = <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, $V>>::Cache; + pub type $name<'tcx> = <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>>>::Cache; )* } @@ -334,6 +338,11 @@ macro_rules! define_callbacks { } } + #[derive(Default)] + pub struct QueryPhantomValues<'tcx> { + $($(#[$attr])* pub $name: PhantomData>,)* + } + #[derive(Default)] pub struct QueryCaches<'tcx> { $($(#[$attr])* pub $name: query_storage::$name<'tcx>,)* @@ -395,10 +404,10 @@ macro_rules! define_callbacks { let key = key.into_query_param(); opt_remap_env_constness!([$($modifiers)*][key]); - match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) { + restore::<$V>(match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) { Some(value) => value, None => self.tcx.queries.$name(self.tcx, self.span, key, QueryMode::Get).unwrap(), - } + }) })* } @@ -459,7 +468,7 @@ macro_rules! define_callbacks { span: Span, key: query_keys::$name<'tcx>, mode: QueryMode, - ) -> Option<$V>;)* + ) -> Option>;)* } }; } @@ -486,11 +495,13 @@ macro_rules! define_feedable { opt_remap_env_constness!([$($modifiers)*][key]); let tcx = self.tcx; - let value = query_provided_to_value::$name(tcx, value); + let erased = query_provided_to_value::$name(tcx, value); + let value = restore::<$V>(erased); let cache = &tcx.query_system.caches.$name; match try_get_cached(tcx, cache, &key) { Some(old) => { + let old = restore::<$V>(old); bug!( "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}", stringify!($name), @@ -505,7 +516,7 @@ macro_rules! define_feedable { &value, hash_result!([$($modifiers)*]), ); - cache.complete(key, value, dep_node_index); + cache.complete(key, erased, dep_node_index); value } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 3fc5f5bed8fc..46c931d61dc9 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -22,8 +22,6 @@ pub enum Cause { pub trait TypeRelation<'tcx>: Sized { fn tcx(&self) -> TyCtxt<'tcx>; - fn intercrate(&self) -> bool; - fn param_env(&self) -> ty::ParamEnv<'tcx>; /// Returns a static string we can use for printouts. @@ -33,9 +31,6 @@ pub trait TypeRelation<'tcx>: Sized { /// relation. Just affects error messages. fn a_is_expected(&self) -> bool; - /// Used during coherence. If called, must emit an always-ambiguous obligation. - fn mark_ambiguous(&mut self); - fn with_cause(&mut self, _cause: Cause, f: F) -> R where F: FnOnce(&mut Self) -> R, @@ -559,23 +554,16 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }), ) if a_def_id == b_def_id => { - if relation.intercrate() { - // During coherence, opaque types should be treated as equal to each other, even if their generic params - // differ, as they could resolve to the same hidden type, even for different generic params. - relation.mark_ambiguous(); - Ok(a) - } else { - let opt_variances = tcx.variances_of(a_def_id); - let substs = relate_substs_with_variances( - relation, - a_def_id, - opt_variances, - a_substs, - b_substs, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?; - Ok(tcx.mk_opaque(a_def_id, substs)) - } + let opt_variances = tcx.variances_of(a_def_id); + let substs = relate_substs_with_variances( + relation, + a_def_id, + opt_variances, + a_substs, + b_substs, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?; + Ok(tcx.mk_opaque(a_def_id, substs)) } _ => Err(TypeError::Sorts(expected_found(relation, a, b))), diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index d4f058440b95..5c604bb6db27 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -68,7 +68,7 @@ impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> { impl fmt::Debug for ty::BoundRegionKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ty::BrAnon(n, span) => write!(f, "BrAnon({n:?}, {span:?})"), + ty::BrAnon(span) => write!(f, "BrAnon({span:?})"), ty::BrNamed(did, name) => { if did.is_crate_root() { write!(f, "BrNamed({})", name) @@ -254,8 +254,8 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::AssocKind, crate::ty::AliasKind, crate::ty::AliasRelationDirection, - crate::ty::Placeholder, - crate::ty::Placeholder, + crate::ty::Placeholder, + crate::ty::Placeholder, crate::ty::ClosureKind, crate::ty::FreeRegion, crate::ty::InferTy, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 5ea77833af25..5bbd396d6f3b 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -60,7 +60,7 @@ pub struct FreeRegion { #[derive(HashStable)] pub enum BoundRegionKind { /// An anonymous region parameter for a given fn (&T) - BrAnon(u32, Option), + BrAnon(Option), /// Named region parameters for functions (a in &'a T) /// @@ -107,15 +107,6 @@ impl BoundRegionKind { _ => None, } } - - pub fn expect_anon(&self) -> u32 { - match *self { - BoundRegionKind::BrNamed(_, _) | BoundRegionKind::BrEnv => { - bug!("expected anon region: {self:?}") - } - BoundRegionKind::BrAnon(idx, _) => idx, - } - } } pub trait Article { @@ -136,10 +127,6 @@ impl<'tcx> Article for TyKind<'tcx> { } } -// `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(TyKind<'_>, 32); - /// A closure can be modeled as a struct that looks like: /// ```ignore (illustrative) /// struct Closure<'l0...'li, T0...Tj, CK, CS, U>(...U); @@ -1533,22 +1520,13 @@ pub struct BoundTy { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable)] pub enum BoundTyKind { - Anon(u32), + Anon, Param(DefId, Symbol), } -impl BoundTyKind { - pub fn expect_anon(self) -> u32 { - match self { - BoundTyKind::Anon(i) => i, - _ => bug!(), - } - } -} - impl From for BoundTy { fn from(var: BoundVar) -> Self { - BoundTy { var, kind: BoundTyKind::Anon(var.as_u32()) } + BoundTy { var, kind: BoundTyKind::Anon } } } @@ -1632,7 +1610,7 @@ impl<'tcx> Region<'tcx> { ty::ReLateBound(_, br) => br.kind.get_name(), ty::ReFree(fr) => fr.bound_region.get_name(), ty::ReStatic => Some(kw::StaticLifetime), - ty::RePlaceholder(placeholder) => placeholder.name.get_name(), + ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(), _ => None, }; @@ -1650,7 +1628,7 @@ impl<'tcx> Region<'tcx> { ty::ReFree(fr) => fr.bound_region.is_named(), ty::ReStatic => true, ty::ReVar(..) => false, - ty::RePlaceholder(placeholder) => placeholder.name.is_named(), + ty::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(), ty::ReErased => false, ty::ReError(_) => false, } @@ -1913,7 +1891,7 @@ impl<'tcx> Ty<'tcx> { // The way we evaluate the `N` in `[T; N]` here only works since we use // `simd_size_and_type` post-monomorphization. It will probably start to ICE // if we use it in generic code. See the `simd-array-trait` ui test. - (f0_len.eval_target_usize(tcx, ParamEnv::empty()) as u64, *f0_elem_ty) + (f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty) } // Otherwise, the fields of this Adt are the SIMD components (and we assume they // all have the same type). @@ -2514,3 +2492,14 @@ impl<'tcx> VarianceDiagInfo<'tcx> { } } } + +// Some types are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +mod size_asserts { + use super::*; + use rustc_data_structures::static_assert_size; + // tidy-alphabetical-start + static_assert_size!(RegionKind<'_>, 28); + static_assert_size!(TyKind<'_>, 32); + // tidy-alphabetical-end +} diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index fcc7cbe0715f..f346cd483470 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -239,19 +239,9 @@ mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count -> } into the body mir_build_bindings_with_variant_name = - pattern binding `{$ident}` is named the same as one of the variants of the type `{$ty_path}` + pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}` .suggestion = to match on the variant, qualify the path -mir_build_irrefutable_let_patterns_generic_let = irrefutable `let` {$count -> - [one] pattern - *[other] patterns - } - .note = {$count -> - [one] this pattern - *[other] these patterns - } will always match, so the `let` is useless - .help = consider removing `let` - mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count -> [one] pattern *[other] patterns @@ -357,15 +347,13 @@ mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html -mir_build_res_defined_here = {$res} defined here - mir_build_adt_defined_here = `{$ty}` defined here mir_build_variant_defined_here = not covered mir_build_interpreted_as_const = introduce a variable instead -mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as {$article} {$res} pattern, not a new variable +mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count -> [one] variant that isn't diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 2643d33cee00..609ab19289c9 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -115,6 +115,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { initializer: Some(initializer), lint_level, else_block: Some(else_block), + span: _, } => { // When lowering the statement `let = else { };`, // the `` block is nested in the parent scope enclosing this statement. @@ -278,6 +279,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { initializer, lint_level, else_block: None, + span: _, } => { let ignores_expr_result = matches!(pattern.kind, PatKind::Wild); this.block_context.push(BlockFrame::Statement { ignores_expr_result }); diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 33b73928704a..54028dfe87b7 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -56,7 +56,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { Ok(TerminatorKind::Drop { place: self.parse_place(args[0])?, target: self.parse_block(args[1])?, - unwind: None, + unwind: UnwindAction::Continue, }) }, @call("mir_call", args) => { @@ -126,7 +126,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { args, destination, target: Some(target), - cleanup: None, + unwind: UnwindAction::Continue, from_hir_call: *from_hir_call, fn_span: *fn_span, }) diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index baa12ec11c32..8631749a524b 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -171,7 +171,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { args: vec![Operand::Move(size), Operand::Move(align)], destination: storage, target: Some(success), - cleanup: None, + unwind: UnwindAction::Continue, from_hir_call: false, fn_span: expr_span, }, @@ -702,7 +702,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.terminate( block, outer_source_info, - TerminatorKind::Drop { place: to_drop, target: success, unwind: None }, + TerminatorKind::Drop { + place: to_drop, + target: success, + unwind: UnwindAction::Continue, + }, ); this.diverge_from(block); block = success; diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 8efaba1f602e..05a723a6b675 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -228,7 +228,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.terminate( loop_block, source_info, - TerminatorKind::FalseUnwind { real_target: body_block, unwind: None }, + TerminatorKind::FalseUnwind { + real_target: body_block, + unwind: UnwindAction::Continue, + }, ); this.diverge_from(loop_block); @@ -264,7 +267,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TerminatorKind::Call { func: fun, args, - cleanup: None, + unwind: UnwindAction::Continue, destination, // The presence or absence of a return edge affects control-flow sensitive // MIR checks and ultimately whether code is accepted or not. We can only @@ -466,7 +469,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { Some(destination_block) }, - cleanup: None, + unwind: if options.contains(InlineAsmOptions::MAY_UNWIND) { + UnwindAction::Continue + } else { + UnwindAction::Unreachable + }, }, ); if options.contains(InlineAsmOptions::MAY_UNWIND) { diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 2de89f67dfdc..8a03ea7e2cc7 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -263,7 +263,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { args: vec![Operand::Move(ref_string)], destination: ref_str, target: Some(eq_block), - cleanup: None, + unwind: UnwindAction::Continue, from_hir_call: false, fn_span: source_info.span } @@ -466,7 +466,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { args: vec![val, expect], destination: eq_result, target: Some(eq_block), - cleanup: None, + unwind: UnwindAction::Continue, from_hir_call: false, fn_span: source_info.span, }, diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index ac645cce5c6a..415f5b1b1e15 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -58,6 +58,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ ty::WithOptConstParam { did, const_param_did: None } => { tcx.ensure_with_value().thir_check_unsafety(did); tcx.ensure_with_value().thir_abstract_const(did); + tcx.ensure_with_value().check_match(did); } } diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 25af221bf369..f32d2db4e712 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -369,7 +369,7 @@ impl DropTree { let terminator = TerminatorKind::Drop { target: blocks[drop_data.1].unwrap(), // The caller will handle this if needed. - unwind: None, + unwind: UnwindAction::Terminate, place: drop_data.0.local.into(), }; cfg.terminate(block, drop_data.0.source_info, terminator); @@ -1141,7 +1141,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate( block, source_info, - TerminatorKind::Drop { place, target: assign, unwind: Some(assign_unwind) }, + TerminatorKind::Drop { + place, + target: assign, + unwind: UnwindAction::Cleanup(assign_unwind), + }, ); self.diverge_from(block); @@ -1165,7 +1169,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate( block, source_info, - TerminatorKind::Assert { cond, expected, msg, target: success_block, cleanup: None }, + TerminatorKind::Assert { + cond, + expected, + msg, + target: success_block, + unwind: UnwindAction::Continue, + }, ); self.diverge_from(block); @@ -1244,7 +1254,11 @@ fn build_scope_drops<'tcx>( cfg.terminate( block, source_info, - TerminatorKind::Drop { place: local.into(), target: next, unwind: None }, + TerminatorKind::Drop { + place: local.into(), + target: next, + unwind: UnwindAction::Continue, + }, ); block = next; } @@ -1424,23 +1438,23 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind { let term = &mut cfg.block_data_mut(from).terminator_mut(); match &mut term.kind { TerminatorKind::Drop { unwind, .. } => { - if let Some(unwind) = *unwind { + if let UnwindAction::Cleanup(unwind) = *unwind { let source_info = term.source_info; cfg.terminate(unwind, source_info, TerminatorKind::Goto { target: to }); } else { - *unwind = Some(to); + *unwind = UnwindAction::Cleanup(to); } } TerminatorKind::FalseUnwind { unwind, .. } - | TerminatorKind::Call { cleanup: unwind, .. } - | TerminatorKind::Assert { cleanup: unwind, .. } - | TerminatorKind::InlineAsm { cleanup: unwind, .. } => { - *unwind = Some(to); + | TerminatorKind::Call { unwind, .. } + | TerminatorKind::Assert { unwind, .. } + | TerminatorKind::InlineAsm { unwind, .. } => { + *unwind = UnwindAction::Cleanup(to); } TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Yield { .. } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index cbfca77bd25d..431c3255ab2a 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -6,11 +6,11 @@ use rustc_errors::{ error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan, SubdiagnosticMessage, }; -use rustc_hir::def::Res; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::thir::Pat; use rustc_middle::ty::{self, Ty}; -use rustc_span::{symbol::Ident, Span}; +use rustc_span::symbol::Symbol; +use rustc_span::Span; #[derive(LintDiagnostic)] #[diag(mir_build_unconditional_recursion)] @@ -534,18 +534,10 @@ pub struct TrailingIrrefutableLetPatterns { #[derive(LintDiagnostic)] #[diag(mir_build_bindings_with_variant_name, code = "E0170")] pub struct BindingsWithVariantName { - #[suggestion(code = "{ty_path}::{ident}", applicability = "machine-applicable")] + #[suggestion(code = "{ty_path}::{name}", applicability = "machine-applicable")] pub suggestion: Option, pub ty_path: String, - pub ident: Ident, -} - -#[derive(LintDiagnostic)] -#[diag(mir_build_irrefutable_let_patterns_generic_let)] -#[note] -#[help] -pub struct IrrefutableLetPatternsGenericLet { - pub count: usize, + pub name: Symbol, } #[derive(LintDiagnostic)] @@ -584,13 +576,12 @@ pub struct IrrefutableLetPatternsWhileLet { #[diag(mir_build_borrow_of_moved_value)] pub struct BorrowOfMovedValue<'tcx> { #[primary_span] - pub span: Span, #[label] #[label(mir_build_occurs_because_label)] pub binding_span: Span, #[label(mir_build_value_borrowed_label)] pub conflicts_ref: Vec, - pub name: Ident, + pub name: Symbol, pub ty: Ty<'tcx>, #[suggestion(code = "ref ", applicability = "machine-applicable")] pub suggest_borrowing: Option, @@ -638,19 +629,19 @@ pub enum Conflict { Mut { #[primary_span] span: Span, - name: Ident, + name: Symbol, }, #[label(mir_build_borrow)] Ref { #[primary_span] span: Span, - name: Ident, + name: Symbol, }, #[label(mir_build_moved)] Moved { #[primary_span] span: Span, - name: Ident, + name: Symbol, }, } @@ -802,8 +793,6 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { pub let_suggestion: Option, #[subdiagnostic] pub misc_suggestion: Option, - #[subdiagnostic] - pub res_defined_here: Option, } #[derive(Subdiagnostic)] @@ -837,14 +826,6 @@ impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> { } } -#[derive(Subdiagnostic)] -#[label(mir_build_res_defined_here)] -pub struct ResDefinedHere { - #[primary_span] - pub def_span: Span, - pub res: Res, -} - #[derive(Subdiagnostic)] #[suggestion( mir_build_interpreted_as_const, @@ -855,9 +836,7 @@ pub struct ResDefinedHere { pub struct InterpretedAsConst { #[primary_span] pub span: Span, - pub article: &'static str, pub variable: String, - pub res: Res, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 8937b78fe34e..8e41957af0eb 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -3,7 +3,7 @@ use rustc_data_structures::graph::iterate::{ NodeStatus, TriColorDepthFirstSearch, TriColorVisitor, }; use rustc_hir::def::DefKind; -use rustc_middle::mir::{BasicBlock, BasicBlocks, Body, Operand, TerminatorKind}; +use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Operand, TerminatorKind}; use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION; @@ -108,7 +108,7 @@ impl<'mir, 'tcx> TriColorVisitor> for Search<'mir, 'tcx> { match self.body[bb].terminator().kind { // These terminators return control flow to the caller. - TerminatorKind::Abort + TerminatorKind::Terminate | TerminatorKind::GeneratorDrop | TerminatorKind::Resume | TerminatorKind::Return @@ -149,7 +149,9 @@ impl<'mir, 'tcx> TriColorVisitor> for Search<'mir, 'tcx> { fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool { let terminator = self.body[bb].terminator(); - if terminator.unwind() == Some(&Some(target)) && terminator.successors().count() > 1 { + if terminator.unwind() == Some(&mir::UnwindAction::Cleanup(target)) + && terminator.successors().count() > 1 + { return true; } // Don't traverse successors of recursive calls or false CFG edges. diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 321353ca20ba..8aacec53f945 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -105,6 +105,10 @@ impl<'tcx> Cx<'tcx> { } } + let span = match local.init { + Some(init) => local.span.with_hi(init.span.hi()), + None => local.span, + }; let stmt = Stmt { kind: StmtKind::Let { remainder_scope, @@ -116,6 +120,7 @@ impl<'tcx> Cx<'tcx> { initializer: local.init.map(|init| self.mirror_expr(init)), else_block, lint_level: LintLevel::Explicit(local.hir_id), + span, }, opt_destruction_scope: opt_dxn_ext, }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 2640ca56b00e..0882b473f108 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -2,45 +2,48 @@ use super::deconstruct_pat::{Constructor, DeconstructedPat}; use super::usefulness::{ compute_match_usefulness, MatchArm, MatchCheckCtxt, Reachability, UsefulnessReport, }; -use super::{PatCtxt, PatternError}; use crate::errors::*; -use hir::{ExprKind, PatKind}; use rustc_arena::TypedArena; -use rustc_ast::{LitKind, Mutability}; +use rustc_ast::Mutability; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::*; -use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{HirId, Pat}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::HirId; +use rustc_middle::thir::visit::{self, Visitor}; +use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; - use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, }; use rustc_session::Session; -use rustc_span::source_map::Spanned; -use rustc_span::{BytePos, Span}; - -pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { - let body_id = match def_id.as_local() { - None => return, - Some(def_id) => tcx.hir().body_owned_by(def_id), - }; +use rustc_span::hygiene::DesugaringKind; +use rustc_span::Span; +pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) { + let Ok((thir, expr)) = tcx.thir_body(ty::WithOptConstParam::unknown(def_id)) else { return }; + let thir = thir.borrow(); let pattern_arena = TypedArena::default(); let mut visitor = MatchVisitor { tcx, - typeck_results: tcx.typeck_body(body_id), + thir: &*thir, param_env: tcx.param_env(def_id), + lint_level: tcx.hir().local_def_id_to_hir_id(def_id), + let_source: LetSource::None, pattern_arena: &pattern_arena, }; - visitor.visit_body(tcx.hir().body(body_id)); + visitor.visit_expr(&thir[expr]); + for param in thir.params.iter() { + if let Some(box ref pattern) = param.pat { + visitor.check_irrefutable(pattern, "function argument", None); + } + } } fn create_e0004( @@ -58,77 +61,132 @@ enum RefutableFlag { } use RefutableFlag::*; +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum LetSource { + None, + IfLet, + IfLetGuard, + LetElse, + WhileLet, +} + struct MatchVisitor<'a, 'p, 'tcx> { tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, + thir: &'a Thir<'tcx>, + lint_level: HirId, + let_source: LetSource, pattern_arena: &'p TypedArena>, } -impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { - fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { - intravisit::walk_expr(self, ex); - match &ex.kind { - hir::ExprKind::Match(scrut, arms, source) => { - self.check_match(scrut, arms, *source, ex.span) +impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { + fn thir(&self) -> &'a Thir<'tcx> { + self.thir + } + + #[instrument(level = "trace", skip(self))] + fn visit_arm(&mut self, arm: &Arm<'tcx>) { + match arm.guard { + Some(Guard::If(expr)) => { + self.with_let_source(LetSource::IfLetGuard, |this| { + this.visit_expr(&this.thir[expr]) + }); } - hir::ExprKind::Let(hir::Let { pat, init, span, .. }) => { - self.check_let(pat, init, *span) + Some(Guard::IfLet(ref pat, expr)) => { + self.with_let_source(LetSource::IfLetGuard, |this| { + this.check_let(pat, expr, LetSource::IfLetGuard, pat.span); + this.visit_pat(pat); + this.visit_expr(&this.thir[expr]); + }); + } + None => {} + } + self.visit_pat(&arm.pattern); + self.visit_expr(&self.thir[arm.body]); + } + + #[instrument(level = "trace", skip(self))] + fn visit_expr(&mut self, ex: &Expr<'tcx>) { + match ex.kind { + ExprKind::Scope { value, lint_level, .. } => { + let old_lint_level = self.lint_level; + if let LintLevel::Explicit(hir_id) = lint_level { + self.lint_level = hir_id; + } + self.visit_expr(&self.thir[value]); + self.lint_level = old_lint_level; + return; + } + ExprKind::If { cond, then, else_opt, if_then_scope: _ } => { + // Give a specific `let_source` for the condition. + let let_source = match ex.span.desugaring_kind() { + Some(DesugaringKind::WhileLoop) => LetSource::WhileLet, + _ => LetSource::IfLet, + }; + self.with_let_source(let_source, |this| this.visit_expr(&self.thir[cond])); + self.with_let_source(LetSource::None, |this| { + this.visit_expr(&this.thir[then]); + if let Some(else_) = else_opt { + this.visit_expr(&this.thir[else_]); + } + }); + return; + } + ExprKind::Match { scrutinee, box ref arms } => { + let source = match ex.span.desugaring_kind() { + Some(DesugaringKind::ForLoop) => hir::MatchSource::ForLoopDesugar, + Some(DesugaringKind::QuestionMark) => hir::MatchSource::TryDesugar, + Some(DesugaringKind::Await) => hir::MatchSource::AwaitDesugar, + _ => hir::MatchSource::Normal, + }; + self.check_match(scrutinee, arms, source, ex.span); + } + ExprKind::Let { box ref pat, expr } => { + self.check_let(pat, expr, self.let_source, ex.span); + } + ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { + self.check_let_chain(self.let_source, ex.span, lhs, rhs); + } + _ => {} + }; + self.with_let_source(LetSource::None, |this| visit::walk_expr(this, ex)); + } + + fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { + let old_lint_level = self.lint_level; + match stmt.kind { + StmtKind::Let { + box ref pattern, initializer, else_block, lint_level, span, .. + } => { + if let LintLevel::Explicit(lint_level) = lint_level { + self.lint_level = lint_level; + } + + if let Some(initializer) = initializer && else_block.is_some() { + self.check_let(pattern, initializer, LetSource::LetElse, span); + } + + if else_block.is_none() { + self.check_irrefutable(pattern, "local binding", Some(span)); + } } _ => {} } - } - - fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) { - intravisit::walk_local(self, loc); - let els = loc.els; - if let Some(init) = loc.init && els.is_some() { - // Build a span without the else { ... } as we don't want to underline - // the entire else block in the IDE setting. - let span = loc.span.with_hi(init.span.hi()); - self.check_let(&loc.pat, init, span); - } - - let (msg, sp) = match loc.source { - hir::LocalSource::Normal => ("local binding", Some(loc.span)), - hir::LocalSource::AsyncFn => ("async fn binding", None), - hir::LocalSource::AwaitDesugar => ("`await` future binding", None), - hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None), - }; - if els.is_none() { - self.check_irrefutable(&loc.pat, msg, sp); - } - } - - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - intravisit::walk_param(self, param); - self.check_irrefutable(¶m.pat, "function argument", None); - } -} - -impl PatCtxt<'_, '_> { - fn report_inlining_errors(&self) { - for error in &self.errors { - match *error { - PatternError::StaticInPattern(span) => { - self.tcx.sess.emit_err(StaticInPattern { span }); - } - PatternError::AssocConstInPattern(span) => { - self.tcx.sess.emit_err(AssocConstInPattern { span }); - } - PatternError::ConstParamInPattern(span) => { - self.tcx.sess.emit_err(ConstParamInPattern { span }); - } - PatternError::NonConstPath(span) => { - self.tcx.sess.emit_err(NonConstPath { span }); - } - } - } + visit::walk_stmt(self, stmt); + self.lint_level = old_lint_level; } } impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { - fn check_patterns(&self, pat: &Pat<'_>, rf: RefutableFlag) { + #[instrument(level = "trace", skip(self, f))] + fn with_let_source(&mut self, let_source: LetSource, f: impl FnOnce(&mut Self)) { + let old_let_source = self.let_source; + self.let_source = let_source; + ensure_sufficient_stack(|| f(self)); + self.let_source = old_let_source; + } + + fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) { pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat)); check_for_bindings_named_same_as_variants(self, pat, rf); } @@ -136,73 +194,63 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { fn lower_pattern( &self, cx: &mut MatchCheckCtxt<'p, 'tcx>, - pat: &'tcx hir::Pat<'tcx>, - have_errors: &mut bool, + pattern: &Pat<'tcx>, ) -> &'p DeconstructedPat<'p, 'tcx> { - let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.typeck_results); - patcx.include_lint_checks(); - let pattern = patcx.lower_pattern(pat); - let pattern: &_ = cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern)); - if !patcx.errors.is_empty() { - *have_errors = true; - patcx.report_inlining_errors(); - } - pattern + cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern)) } - fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'p, 'tcx> { + fn new_cx(&self, hir_id: HirId, refutable: bool) -> MatchCheckCtxt<'p, 'tcx> { MatchCheckCtxt { tcx: self.tcx, param_env: self.param_env, module: self.tcx.parent_module(hir_id).to_def_id(), pattern_arena: &self.pattern_arena, + refutable, } } - fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, scrutinee: &hir::Expr<'_>, span: Span) { + #[instrument(level = "trace", skip(self))] + fn check_let(&mut self, pat: &Pat<'tcx>, scrutinee: ExprId, source: LetSource, span: Span) { + if let LetSource::None = source { + return; + } self.check_patterns(pat, Refutable); - let mut cx = self.new_cx(scrutinee.hir_id); - let tpat = self.lower_pattern(&mut cx, pat, &mut false); - self.check_let_reachability(&mut cx, pat.hir_id, tpat, span); + let mut cx = self.new_cx(self.lint_level, true); + let tpat = self.lower_pattern(&mut cx, pat); + self.check_let_reachability(&mut cx, self.lint_level, source, tpat, span); } fn check_match( &mut self, - scrut: &hir::Expr<'_>, - hir_arms: &'tcx [hir::Arm<'tcx>], + scrut: ExprId, + arms: &[ArmId], source: hir::MatchSource, expr_span: Span, ) { - let mut cx = self.new_cx(scrut.hir_id); + let mut cx = self.new_cx(self.lint_level, true); - for arm in hir_arms { + for &arm in arms { // Check the arm for some things unrelated to exhaustiveness. - self.check_patterns(&arm.pat, Refutable); - if let Some(hir::Guard::IfLet(ref let_expr)) = arm.guard { - self.check_patterns(let_expr.pat, Refutable); - let tpat = self.lower_pattern(&mut cx, let_expr.pat, &mut false); - self.check_let_reachability(&mut cx, let_expr.pat.hir_id, tpat, tpat.span()); - } + let arm = &self.thir.arms[arm]; + self.check_patterns(&arm.pattern, Refutable); } - let mut have_errors = false; - - let arms: Vec<_> = hir_arms + let tarms: Vec<_> = arms .iter() - .map(|hir::Arm { pat, guard, .. }| MatchArm { - pat: self.lower_pattern(&mut cx, pat, &mut have_errors), - hir_id: pat.hir_id, - has_guard: guard.is_some(), + .map(|&arm| { + let arm = &self.thir.arms[arm]; + let hir_id = match arm.lint_level { + LintLevel::Explicit(hir_id) => hir_id, + LintLevel::Inherited => self.lint_level, + }; + let pat = self.lower_pattern(&mut cx, &arm.pattern); + MatchArm { pat, hir_id, has_guard: arm.guard.is_some() } }) .collect(); - // Bail out early if lowering failed. - if have_errors { - return; - } - - let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut); - let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty); + let scrut = &self.thir[scrut]; + let scrut_ty = scrut.ty; + let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty); match source { // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }` @@ -219,12 +267,18 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { // Check if the match is exhaustive. let witnesses = report.non_exhaustiveness_witnesses; if !witnesses.is_empty() { - if source == hir::MatchSource::ForLoopDesugar && hir_arms.len() == 2 { + if source == hir::MatchSource::ForLoopDesugar && arms.len() == 2 { // the for loop pattern is not irrefutable - let pat = hir_arms[1].pat.for_loop_some().unwrap(); - self.check_irrefutable(pat, "`for` loop binding", None); + let pat = &self.thir[arms[1]].pattern; + // `pat` should be `Some()` from a desugared for loop. + debug_assert_eq!(pat.span.desugaring_kind(), Some(DesugaringKind::ForLoop)); + let PatKind::Variant { ref subpatterns, .. } = pat.kind else { bug!() }; + let [pat_field] = &subpatterns[..] else { bug!() }; + self.check_irrefutable(&pat_field.pattern, "`for` loop binding", None); } else { - non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, hir_arms, expr_span); + non_exhaustive_match( + &cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span, + ); } } } @@ -233,114 +287,96 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { &mut self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId, + source: LetSource, pat: &'p DeconstructedPat<'p, 'tcx>, span: Span, ) { - if self.check_let_chain(cx, pat_id) { - return; - } - if is_let_irrefutable(cx, pat_id, pat) { - irrefutable_let_pattern(cx.tcx, pat_id, span); + irrefutable_let_patterns(cx.tcx, pat_id, source, 1, span); } } - fn check_let_chain(&mut self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId) -> bool { - let hir = self.tcx.hir(); - let parent = hir.parent_id(pat_id); - - // First, figure out if the given pattern is part of a let chain, - // and if so, obtain the top node of the chain. - let mut top = parent; - let mut part_of_chain = false; - loop { - let new_top = hir.parent_id(top); - if let hir::Node::Expr( - hir::Expr { - kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, lhs, rhs), - .. - }, - .., - ) = hir.get(new_top) - { - // If this isn't the first iteration, we need to check - // if there is a let expr before us in the chain, so - // that we avoid doubly checking the let chain. - - // The way a chain of &&s is encoded is ((let ... && let ...) && let ...) && let ... - // as && is left-to-right associative. Thus, we need to check rhs. - if part_of_chain && matches!(rhs.kind, hir::ExprKind::Let(..)) { - return true; - } - // If there is a let at the lhs, and we provide the rhs, we don't do any checking either. - if !part_of_chain && matches!(lhs.kind, hir::ExprKind::Let(..)) && rhs.hir_id == top - { - return true; - } - } else { - // We've reached the top. - break; - } - - // Since this function is called within a let context, it is reasonable to assume that any parent - // `&&` infers a let chain - part_of_chain = true; - top = new_top; - } - if !part_of_chain { - return false; + #[instrument(level = "trace", skip(self))] + fn check_let_chain( + &mut self, + let_source: LetSource, + top_expr_span: Span, + mut lhs: ExprId, + rhs: ExprId, + ) { + if let LetSource::None = let_source { + return; } - // Second, obtain the refutabilities of all exprs in the chain, + // Lint level enclosing the next `lhs`. + let mut cur_lint_level = self.lint_level; + + // Obtain the refutabilities of all exprs in the chain, // and record chain members that aren't let exprs. let mut chain_refutabilities = Vec::new(); - let hir::Node::Expr(top_expr) = hir.get(top) else { - // We ensure right above that it's an Expr - unreachable!() - }; - let mut cur_expr = top_expr; - loop { - let mut add = |expr: &hir::Expr<'tcx>| { - let refutability = match expr.kind { - hir::ExprKind::Let(hir::Let { pat, init, span, .. }) => { - let mut ncx = self.new_cx(init.hir_id); - let tpat = self.lower_pattern(&mut ncx, pat, &mut false); - let refutable = !is_let_irrefutable(&mut ncx, pat.hir_id, tpat); - Some((*span, refutable)) - } - _ => None, - }; - chain_refutabilities.push(refutability); - }; - if let hir::Expr { - kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, lhs, rhs), - .. - } = cur_expr + let add = |expr: ExprId, mut local_lint_level| { + // `local_lint_level` is the lint level enclosing the pattern inside `expr`. + let mut expr = &self.thir[expr]; + debug!(?expr, ?local_lint_level, "add"); + // Fast-forward through scopes. + while let ExprKind::Scope { value, lint_level, .. } = expr.kind { + if let LintLevel::Explicit(hir_id) = lint_level { + local_lint_level = hir_id + } + expr = &self.thir[value]; + } + debug!(?expr, ?local_lint_level, "after scopes"); + match expr.kind { + ExprKind::Let { box ref pat, expr: _ } => { + let mut ncx = self.new_cx(local_lint_level, true); + let tpat = self.lower_pattern(&mut ncx, pat); + let refutable = !is_let_irrefutable(&mut ncx, local_lint_level, tpat); + Some((expr.span, refutable)) + } + ExprKind::LogicalOp { op: LogicalOp::And, .. } => { + bug!() + } + _ => None, + } + }; + + // Let chains recurse on the left, so we start by adding the rightmost. + chain_refutabilities.push(add(rhs, cur_lint_level)); + + loop { + while let ExprKind::Scope { value, lint_level, .. } = self.thir[lhs].kind { + if let LintLevel::Explicit(hir_id) = lint_level { + cur_lint_level = hir_id + } + lhs = value; + } + if let ExprKind::LogicalOp { op: LogicalOp::And, lhs: new_lhs, rhs: expr } = + self.thir[lhs].kind { - add(rhs); - cur_expr = lhs; + chain_refutabilities.push(add(expr, cur_lint_level)); + lhs = new_lhs; } else { - add(cur_expr); + chain_refutabilities.push(add(lhs, cur_lint_level)); break; } } + debug!(?chain_refutabilities); chain_refutabilities.reverse(); // Third, emit the actual warnings. - if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, false)))) { // The entire chain is made up of irrefutable `let` statements - let let_source = let_source_parent(self.tcx, top, None); irrefutable_let_patterns( - cx.tcx, - top, + self.tcx, + self.lint_level, let_source, chain_refutabilities.len(), - top_expr.span, + top_expr_span, ); - return true; + return; } + if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 { // The chain has a non-zero prefix of irrefutable `let` statements. @@ -350,7 +386,6 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { // so can't always be moved out. // FIXME: Add checking whether the bindings are actually used in the prefix, // and lint if they are not. - let let_source = let_source_parent(self.tcx, top, None); if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) { // Emit the lint let prefix = &chain_refutabilities[..until]; @@ -358,9 +393,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let span_end = prefix.last().unwrap().unwrap().0; let span = span_start.to(span_end); let count = prefix.len(); - cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, LeadingIrrefutableLetPatterns { count }); + self.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, self.lint_level, span, LeadingIrrefutableLetPatterns { count }); } } + if let Some(from) = chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) && from != (chain_refutabilities.len() - 1) { // The chain has a non-empty suffix of irrefutable `let` statements let suffix = &chain_refutabilities[from + 1..]; @@ -368,18 +404,18 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let span_end = suffix.last().unwrap().unwrap().0; let span = span_start.to(span_end); let count = suffix.len(); - cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, TrailingIrrefutableLetPatterns { count }); + self.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, self.lint_level, span, TrailingIrrefutableLetPatterns { count }); } - true } - fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option) { - let mut cx = self.new_cx(pat.hir_id); + #[instrument(level = "trace", skip(self))] + fn check_irrefutable(&self, pat: &Pat<'tcx>, origin: &str, sp: Option) { + let mut cx = self.new_cx(self.lint_level, false); - let pattern = self.lower_pattern(&mut cx, pat, &mut false); + let pattern = self.lower_pattern(&mut cx, pat); let pattern_ty = pattern.ty(); - let arm = MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false }; - let report = compute_match_usefulness(&cx, &[arm], pat.hir_id, pattern_ty); + let arm = MatchArm { pat: pattern, hir_id: self.lint_level, has_guard: false }; + let report = compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty); // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We // only care about exhaustiveness here. @@ -390,58 +426,45 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { return; } - let (inform, interpreted_as_const, res_defined_here,let_suggestion, misc_suggestion) = - if let hir::PatKind::Path(hir::QPath::Resolved( - None, - hir::Path { - segments: &[hir::PathSegment { args: None, res, ident, .. }], - .. - }, - )) = &pat.kind - { - ( - None, - Some(InterpretedAsConst { - span: pat.span, - article: res.article(), - variable: ident.to_string().to_lowercase(), - res, - }), - try { - ResDefinedHere { - def_span: cx.tcx.hir().res_span(res)?, - res, - } - }, - None, - None, - ) - } else if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) { - let mut bindings = vec![]; - pat.walk_always(&mut |pat: &hir::Pat<'_>| { - if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { - bindings.push(ident); - } + let inform = sp.is_some().then_some(Inform); + let mut let_suggestion = None; + let mut misc_suggestion = None; + let mut interpreted_as_const = None; + if let PatKind::Constant { .. } = pat.kind + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) + { + // If the pattern to match is an integer literal: + if snippet.chars().all(|c| c.is_digit(10)) { + // Then give a suggestion, the user might've meant to create a binding instead. + misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral { + start_span: pat.span.shrink_to_lo() }); - let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1)); - let start_span = span.shrink_to_lo(); - let end_span = semi_span.shrink_to_lo(); - let count = witnesses.len(); + } else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') { + interpreted_as_const = Some(InterpretedAsConst { + span: pat.span, + variable: snippet, + }); + } + } - // If the pattern to match is an integer literal: - let int_suggestion = if - let PatKind::Lit(expr) = &pat.kind - && bindings.is_empty() - && let ExprKind::Lit(Spanned { node: LitKind::Int(_, _), span }) = expr.kind { - // Then give a suggestion, the user might've meant to create a binding instead. - Some(MiscPatternSuggestion::AttemptedIntegerLiteral { start_span: span.shrink_to_lo() }) - } else { None }; + if let Some(span) = sp + && self.tcx.sess.source_map().is_span_accessible(span) + && interpreted_as_const.is_none() + { + let mut bindings = vec![]; + pat.each_binding(|name, _, _, _| bindings.push(name)); - let let_suggestion = if bindings.is_empty() {SuggestLet::If{start_span, semi_span, count}} else{ SuggestLet::Else{end_span, count }}; - (sp.map(|_|Inform), None, None, Some(let_suggestion), int_suggestion) - } else{ - (sp.map(|_|Inform), None, None, None, None) - }; + let semi_span = span.shrink_to_hi(); + let start_span = span.shrink_to_lo(); + let end_span = semi_span.shrink_to_lo(); + let count = witnesses.len(); + + let_suggestion = Some(if bindings.is_empty() { + SuggestLet::If { start_span, semi_span, count } + } else { + SuggestLet::Else { end_span, count } + }); + }; let adt_defined_here = try { let ty = pattern_ty.peel_refs(); @@ -465,7 +488,6 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { pattern_ty, let_suggestion, misc_suggestion, - res_defined_here, adt_defined_here, }); } @@ -477,14 +499,18 @@ fn check_for_bindings_named_same_as_variants( rf: RefutableFlag, ) { pat.walk_always(|p| { - if let hir::PatKind::Binding(_, _, ident, None) = p.kind - && let Some(ty::BindByValue(hir::Mutability::Not)) = - cx.typeck_results.extract_binding_mode(cx.tcx.sess, p.hir_id, p.span) - && let pat_ty = cx.typeck_results.pat_ty(p).peel_refs() - && let ty::Adt(edef, _) = pat_ty.kind() + if let PatKind::Binding { + name, + mode: BindingMode::ByValue, + mutability: Mutability::Not, + subpattern: None, + ty, + .. + } = p.kind + && let ty::Adt(edef, _) = ty.peel_refs().kind() && edef.is_enum() && edef.variants().iter().any(|variant| { - variant.ident(cx.tcx) == ident && variant.ctor_kind() == Some(CtorKind::Const) + variant.name == name && variant.ctor_kind() == Some(CtorKind::Const) }) { let variant_count = edef.variants().len(); @@ -493,7 +519,7 @@ fn check_for_bindings_named_same_as_variants( }); cx.tcx.emit_spanned_lint( BINDINGS_WITH_VARIANT_NAME, - p.hir_id, + cx.lint_level, p.span, BindingsWithVariantName { // If this is an irrefutable pattern, and there's > 1 variant, @@ -503,7 +529,7 @@ fn check_for_bindings_named_same_as_variants( Some(p.span) } else { None }, ty_path, - ident, + name, }, ) } @@ -529,11 +555,6 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option< ); } -fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) { - let source = let_source(tcx, id); - irrefutable_let_patterns(tcx, id, source, 1, span); -} - fn irrefutable_let_patterns( tcx: TyCtxt<'_>, id: HirId, @@ -548,7 +569,7 @@ fn irrefutable_let_patterns( } match source { - LetSource::GenericLet => emit_diag!(IrrefutableLetPatternsGenericLet), + LetSource::None => bug!(), LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet), LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard), LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse), @@ -604,10 +625,11 @@ fn report_arm_reachability<'p, 'tcx>( /// Report that a match is not exhaustive. fn non_exhaustive_match<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, + thir: &Thir<'tcx>, scrut_ty: Ty<'tcx>, sp: Span, witnesses: Vec>, - arms: &[hir::Arm<'tcx>], + arms: &[ArmId], expr_span: Span, ) { let is_empty_match = arms.is_empty(); @@ -705,6 +727,7 @@ fn non_exhaustive_match<'p, 'tcx>( )); } [only] => { + let only = &thir[*only]; let (pre_indentation, is_multiline) = if let Some(snippet) = sm.indentation_before(only.span) && let Ok(with_trailing) = sm.span_extend_while(only.span, |c| c.is_whitespace() || c == ',') && sm.is_multiline(with_trailing) @@ -713,8 +736,9 @@ fn non_exhaustive_match<'p, 'tcx>( } else { (" ".to_string(), false) }; - let comma = if matches!(only.body.kind, hir::ExprKind::Block(..)) - && only.span.eq_ctxt(only.body.span) + let only_body = &thir[only.body]; + let comma = if matches!(only_body.kind, ExprKind::Block { .. }) + && only.span.eq_ctxt(only_body.span) && is_multiline { "" @@ -726,24 +750,29 @@ fn non_exhaustive_match<'p, 'tcx>( format!("{}{}{} => todo!()", comma, pre_indentation, pattern), )); } - [.., prev, last] if prev.span.eq_ctxt(last.span) => { - let comma = if matches!(last.body.kind, hir::ExprKind::Block(..)) - && last.span.eq_ctxt(last.body.span) - { - "" - } else { - "," - }; - let spacing = if sm.is_multiline(prev.span.between(last.span)) { - sm.indentation_before(last.span).map(|indent| format!("\n{indent}")) - } else { - Some(" ".to_string()) - }; - if let Some(spacing) = spacing { - suggestion = Some(( - last.span.shrink_to_hi(), - format!("{}{}{} => todo!()", comma, spacing, pattern), - )); + [.., prev, last] => { + let prev = &thir[*prev]; + let last = &thir[*last]; + if prev.span.eq_ctxt(last.span) { + let last_body = &thir[last.body]; + let comma = if matches!(last_body.kind, ExprKind::Block { .. }) + && last.span.eq_ctxt(last_body.span) + { + "" + } else { + "," + }; + let spacing = if sm.is_multiline(prev.span.between(last.span)) { + sm.indentation_before(last.span).map(|indent| format!("\n{indent}")) + } else { + Some(" ".to_string()) + }; + if let Some(spacing) = spacing { + suggestion = Some(( + last.span.shrink_to_hi(), + format!("{}{}{} => todo!()", comma, spacing, pattern), + )); + } } } _ => {} @@ -863,10 +892,6 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( } /// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`. -fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId) -> bool { - !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx, cx.param_env) -} - /// Check that there are no borrow or move conflicts in `binding @ subpat` patterns. /// /// For example, this would reject: @@ -877,45 +902,36 @@ fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId) -> bool { /// - `x @ Some(ref mut? y)`. /// /// This analysis is *not* subsumed by NLL. -fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pat<'_>) { +fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, pat: &Pat<'tcx>) { // Extract `sub` in `binding @ sub`. - let (name, sub) = match &pat.kind { - hir::PatKind::Binding(.., name, Some(sub)) => (*name, sub), - _ => return, - }; - let binding_span = pat.span.with_hi(name.span.hi()); + let PatKind::Binding { name, mode, ty, subpattern: Some(box ref sub), .. } = pat.kind else { return }; + + let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); - let typeck_results = cx.typeck_results; let sess = cx.tcx.sess; // Get the binding move, extract the mutability if by-ref. - let mut_outer = match typeck_results.extract_binding_mode(sess, pat.hir_id, pat.span) { - Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id) => { + let mut_outer = match mode { + BindingMode::ByValue if is_binding_by_move(ty) => { // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`. let mut conflicts_ref = Vec::new(); - sub.each_binding(|_, hir_id, span, _| { - match typeck_results.extract_binding_mode(sess, hir_id, span) { - Some(ty::BindByValue(_)) | None => {} - Some(ty::BindByReference(_)) => conflicts_ref.push(span), - } + sub.each_binding(|_, mode, _, span| match mode { + BindingMode::ByValue => {} + BindingMode::ByRef(_) => conflicts_ref.push(span), }); if !conflicts_ref.is_empty() { sess.emit_err(BorrowOfMovedValue { - span: pat.span, - binding_span, + binding_span: pat.span, conflicts_ref, name, - ty: typeck_results.node_type(pat.hir_id), - suggest_borrowing: pat - .span - .contains(binding_span) - .then(|| binding_span.shrink_to_lo()), + ty, + suggest_borrowing: Some(pat.span.shrink_to_lo()), }); } return; } - Some(ty::BindByValue(_)) | None => return, - Some(ty::BindByReference(m)) => m, + BindingMode::ByValue => return, + BindingMode::ByRef(m) => m.mutability(), }; // We now have `ref $mut_outer binding @ sub` (semantically). @@ -923,9 +939,9 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa let mut conflicts_move = Vec::new(); let mut conflicts_mut_mut = Vec::new(); let mut conflicts_mut_ref = Vec::new(); - sub.each_binding(|_, hir_id, span, name| { - match typeck_results.extract_binding_mode(sess, hir_id, span) { - Some(ty::BindByReference(mut_inner)) => match (mut_outer, mut_inner) { + sub.each_binding(|name, mode, ty, span| { + match mode { + BindingMode::ByRef(mut_inner) => match (mut_outer, mut_inner.mutability()) { // Both sides are `ref`. (Mutability::Not, Mutability::Not) => {} // 2x `ref mut`. @@ -939,10 +955,10 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa conflicts_mut_ref.push(Conflict::Ref { span, name }) } }, - Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => { + BindingMode::ByValue if is_binding_by_move(ty) => { conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict. } - Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine. + BindingMode::ByValue => {} // `ref mut?` + by-copy is fine. } }); @@ -951,8 +967,8 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa let report_move_conflict = !conflicts_move.is_empty(); let mut occurences = match mut_outer { - Mutability::Mut => vec![Conflict::Mut { span: binding_span, name }], - Mutability::Not => vec![Conflict::Ref { span: binding_span, name }], + Mutability::Mut => vec![Conflict::Mut { span: pat.span, name }], + Mutability::Not => vec![Conflict::Ref { span: pat.span, name }], }; occurences.extend(conflicts_mut_mut); occurences.extend(conflicts_mut_ref); @@ -977,65 +993,3 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa sess.emit_err(MovedWhileBorrowed { span: pat.span, occurences }); } } - -#[derive(Clone, Copy, Debug)] -pub enum LetSource { - GenericLet, - IfLet, - IfLetGuard, - LetElse, - WhileLet, -} - -fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource { - let hir = tcx.hir(); - - let parent = hir.parent_id(pat_id); - let_source_parent(tcx, parent, Some(pat_id)) -} - -fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option) -> LetSource { - let hir = tcx.hir(); - - let parent_node = hir.get(parent); - - match parent_node { - hir::Node::Arm(hir::Arm { - guard: Some(hir::Guard::IfLet(&hir::Let { pat: hir::Pat { hir_id, .. }, .. })), - .. - }) if Some(*hir_id) == pat_id => { - return LetSource::IfLetGuard; - } - _ => {} - } - - let parent_parent = hir.parent_id(parent); - let parent_parent_node = hir.get(parent_parent); - match parent_parent_node { - hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), .. }) => { - return LetSource::LetElse; - } - hir::Node::Arm(hir::Arm { guard: Some(hir::Guard::If(_)), .. }) => { - return LetSource::IfLetGuard; - } - _ => {} - } - - let parent_parent_parent = hir.parent_id(parent_parent); - let parent_parent_parent_parent = hir.parent_id(parent_parent_parent); - let parent_parent_parent_parent_node = hir.get(parent_parent_parent_parent); - - if let hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _), - .. - }) = parent_parent_parent_parent_node - { - return LetSource::WhileLet; - } - - if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If(..), .. }) = parent_parent_node { - return LetSource::IfLet; - } - - LetSource::GenericLet -} diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 2dbef740d1a6..32d0404bd073 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -59,8 +59,6 @@ struct ConstToPat<'tcx> { // inference context used for checking `T: Structural` bounds. infcx: InferCtxt<'tcx>, - include_lint_checks: bool, - treat_byte_string_as_slice: bool, } @@ -93,7 +91,6 @@ impl<'tcx> ConstToPat<'tcx> { span, infcx, param_env: pat_ctxt.param_env, - include_lint_checks: pat_ctxt.include_lint_checks, saw_const_match_error: Cell::new(false), saw_const_match_lint: Cell::new(false), behind_reference: Cell::new(false), @@ -134,7 +131,7 @@ impl<'tcx> ConstToPat<'tcx> { }) }); - if self.include_lint_checks && !self.saw_const_match_error.get() { + if !self.saw_const_match_error.get() { // If we were able to successfully convert the const to some pat, // double-check that all types in the const implement `Structural`. @@ -239,21 +236,19 @@ impl<'tcx> ConstToPat<'tcx> { let kind = match cv.ty().kind() { ty::Float(_) => { - if self.include_lint_checks { tcx.emit_spanned_lint( lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, id, span, FloatPattern, ); - } PatKind::Constant { value: cv } } ty::Adt(adt_def, _) if adt_def.is_union() => { // Matching on union fields is unsafe, we can't hide it in constants self.saw_const_match_error.set(true); let err = UnionPattern { span }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); PatKind::Wild } ty::Adt(..) @@ -267,7 +262,7 @@ impl<'tcx> ConstToPat<'tcx> { { self.saw_const_match_error.set(true); let err = TypeNotStructural { span, non_sm_ty }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); PatKind::Wild } // If the type is not structurally comparable, just emit the constant directly, @@ -280,8 +275,7 @@ impl<'tcx> ConstToPat<'tcx> { // Backwards compatibility hack because we can't cause hard errors on these // types, so we compare them via `PartialEq::eq` at runtime. ty::Adt(..) if !self.type_marked_structural(cv.ty()) && self.behind_reference.get() => { - if self.include_lint_checks - && !self.saw_const_match_error.get() + if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); @@ -305,7 +299,7 @@ impl<'tcx> ConstToPat<'tcx> { ); self.saw_const_match_error.set(true); let err = TypeNotStructural { span, non_sm_ty: cv.ty() }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); PatKind::Wild } ty::Adt(adt_def, substs) if adt_def.is_enum() => { @@ -339,7 +333,7 @@ impl<'tcx> ConstToPat<'tcx> { ty::Dynamic(..) => { self.saw_const_match_error.set(true); let err = InvalidPattern { span, non_sm_ty: cv.ty() }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); PatKind::Wild } // `&str` is represented as `ConstValue::Slice`, let's keep using this @@ -406,8 +400,7 @@ impl<'tcx> ConstToPat<'tcx> { // to figure out how to get a reference again. ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => { if self.behind_reference.get() { - if self.include_lint_checks - && !self.saw_const_match_error.get() + if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); @@ -423,7 +416,7 @@ impl<'tcx> ConstToPat<'tcx> { if !self.saw_const_match_error.get() { self.saw_const_match_error.set(true); let err = TypeNotStructural { span, non_sm_ty: *pointee_ty }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); } PatKind::Wild } @@ -437,7 +430,7 @@ impl<'tcx> ConstToPat<'tcx> { // (except slices, which are handled in a separate arm above). let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); PatKind::Wild } else { @@ -465,8 +458,7 @@ impl<'tcx> ConstToPat<'tcx> { // compilation choices change the runtime behaviour of the match. // See https://github.com/rust-lang/rust/issues/70861 for examples. ty::FnPtr(..) | ty::RawPtr(..) => { - if self.include_lint_checks - && !self.saw_const_match_error.get() + if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); @@ -482,13 +474,12 @@ impl<'tcx> ConstToPat<'tcx> { _ => { self.saw_const_match_error.set(true); let err = InvalidPattern { span, non_sm_ty: cv.ty() }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); PatKind::Wild } }; - if self.include_lint_checks - && !self.saw_const_match_error.get() + if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() && mir_structural_match_violation // FIXME(#73448): Find a way to bring const qualification into parity with diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index e619e095496b..7c29196447c7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -258,7 +258,7 @@ impl IntRange { pcx: &PatCtxt<'_, 'p, 'tcx>, pats: impl Iterator>, column_count: usize, - hir_id: HirId, + lint_root: HirId, ) { if self.is_singleton() { return; @@ -290,7 +290,7 @@ impl IntRange { if !overlap.is_empty() { pcx.cx.tcx.emit_spanned_lint( lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, - hir_id, + lint_root, pcx.span, OverlappingRangeEndpoints { overlap, range: pcx.span }, ); @@ -1154,8 +1154,9 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { fn wildcards_from_tys( cx: &MatchCheckCtxt<'p, 'tcx>, tys: impl IntoIterator>, + span: Span, ) -> Self { - Fields::from_iter(cx, tys.into_iter().map(DeconstructedPat::wildcard)) + Fields::from_iter(cx, tys.into_iter().map(|ty| DeconstructedPat::wildcard(ty, span))) } // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide @@ -1191,18 +1192,18 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { pub(super) fn wildcards(pcx: &PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self { let ret = match constructor { Single | Variant(_) => match pcx.ty.kind() { - ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()), - ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)), + ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter(), pcx.span), + ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty), pcx.span), ty::Adt(adt, substs) => { if adt.is_box() { // The only legal patterns of type `Box` (outside `std`) are `_` and box // patterns. If we're here we can assume this is a box pattern. - Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0))) + Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0)), pcx.span) } else { let variant = &adt.variant(constructor.variant_index_for_adt(*adt)); let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant) .map(|(_, ty)| ty); - Fields::wildcards_from_tys(pcx.cx, tys) + Fields::wildcards_from_tys(pcx.cx, tys, pcx.span) } } _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx), @@ -1210,7 +1211,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { Slice(slice) => match *pcx.ty.kind() { ty::Slice(ty) | ty::Array(ty, _) => { let arity = slice.arity(); - Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty)) + Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty), pcx.span) } _ => bug!("bad slice pattern {:?} {:?}", constructor, pcx), }, @@ -1251,8 +1252,8 @@ pub(crate) struct DeconstructedPat<'p, 'tcx> { } impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { - pub(super) fn wildcard(ty: Ty<'tcx>) -> Self { - Self::new(Wildcard, Fields::empty(), ty, DUMMY_SP) + pub(super) fn wildcard(ty: Ty<'tcx>, span: Span) -> Self { + Self::new(Wildcard, Fields::empty(), ty, span) } pub(super) fn new( @@ -1269,7 +1270,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { /// `Some(_)`. pub(super) fn wild_from_ctor(pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self { let fields = Fields::wildcards(pcx, &ctor); - DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP) + DeconstructedPat::new(ctor, fields, pcx.ty, pcx.span) } /// Clone this value. This method emphasizes that cloning loses reachability information and @@ -1298,7 +1299,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { ty::Tuple(fs) => { ctor = Single; let mut wilds: SmallVec<[_; 2]> = - fs.iter().map(DeconstructedPat::wildcard).collect(); + fs.iter().map(|ty| DeconstructedPat::wildcard(ty, pat.span)).collect(); for pat in subpatterns { wilds[pat.field.index()] = mkpat(&pat.pattern); } @@ -1317,11 +1318,11 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { // normally or through box-patterns. We'll have to figure out a proper // solution when we introduce generalized deref patterns. Also need to // prevent mixing of those two options. - let pat = subpatterns.into_iter().find(|pat| pat.field.index() == 0); - let pat = if let Some(pat) = pat { + let pattern = subpatterns.into_iter().find(|pat| pat.field.index() == 0); + let pat = if let Some(pat) = pattern { mkpat(&pat.pattern) } else { - DeconstructedPat::wildcard(substs.type_at(0)) + DeconstructedPat::wildcard(substs.type_at(0), pat.span) }; ctor = Single; fields = Fields::singleton(cx, pat); @@ -1343,7 +1344,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { ty }); let mut wilds: SmallVec<[_; 2]> = - tys.map(DeconstructedPat::wildcard).collect(); + tys.map(|ty| DeconstructedPat::wildcard(ty, pat.span)).collect(); for pat in subpatterns { if let Some(i) = field_id_to_id[pat.field.index()] { wilds[i] = mkpat(&pat.pattern); @@ -1566,8 +1567,10 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { }; let prefix = &self.fields.fields[..prefix]; let suffix = &self.fields.fields[self_slice.arity() - suffix..]; - let wildcard: &_ = - pcx.cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty)); + let wildcard: &_ = pcx + .cx + .pattern_arena + .alloc(DeconstructedPat::wildcard(inner_ty, pcx.span)); let extra_wildcards = other_slice.arity() - self_slice.arity(); let extra_wildcards = (0..extra_wildcards).map(|_| wildcard); prefix.iter().chain(extra_wildcards).chain(suffix).collect() diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 9ac92f6e0a61..70d015a39e4e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -31,20 +31,10 @@ use rustc_target::abi::FieldIdx; use std::cmp::Ordering; -#[derive(Clone, Debug)] -enum PatternError { - AssocConstInPattern(Span), - ConstParamInPattern(Span), - StaticInPattern(Span), - NonConstPath(Span), -} - struct PatCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, - errors: Vec, - include_lint_checks: bool, } pub(super) fn pat_from_hir<'a, 'tcx>( @@ -53,30 +43,13 @@ pub(super) fn pat_from_hir<'a, 'tcx>( typeck_results: &'a ty::TypeckResults<'tcx>, pat: &'tcx hir::Pat<'tcx>, ) -> Box> { - let mut pcx = PatCtxt::new(tcx, param_env, typeck_results); + let mut pcx = PatCtxt { tcx, param_env, typeck_results }; let result = pcx.lower_pattern(pat); - if !pcx.errors.is_empty() { - let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors); - tcx.sess.delay_span_bug(pat.span, &msg); - } debug!("pat_from_hir({:?}) = {:?}", pat, result); result } impl<'a, 'tcx> PatCtxt<'a, 'tcx> { - fn new( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, - ) -> Self { - PatCtxt { tcx, param_env, typeck_results, errors: vec![], include_lint_checks: false } - } - - fn include_lint_checks(&mut self) -> &mut Self { - self.include_lint_checks = true; - self - } - fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { // When implicit dereferences have been inserted in this pattern, the unadjusted lowered // pattern has the type that results *after* dereferencing. For example, in this code: @@ -473,12 +446,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { | Res::SelfTyAlias { .. } | Res::SelfCtor(..) => PatKind::Leaf { subpatterns }, _ => { - let pattern_error = match res { - Res::Def(DefKind::ConstParam, _) => PatternError::ConstParamInPattern(span), - Res::Def(DefKind::Static(_), _) => PatternError::StaticInPattern(span), - _ => PatternError::NonConstPath(span), + match res { + Res::Def(DefKind::ConstParam, _) => { + self.tcx.sess.emit_err(ConstParamInPattern { span }) + } + Res::Def(DefKind::Static(_), _) => { + self.tcx.sess.emit_err(StaticInPattern { span }) + } + _ => self.tcx.sess.emit_err(NonConstPath { span }), }; - self.errors.push(pattern_error); PatKind::Wild } }; @@ -531,7 +507,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // It should be assoc consts if there's no error but we cannot resolve it. debug_assert!(is_associated_const); - self.errors.push(PatternError::AssocConstInPattern(span)); + self.tcx.sess.emit_err(AssocConstInPattern { span }); return pat_from_kind(PatKind::Wild); } @@ -609,7 +585,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { match value { mir::ConstantKind::Ty(c) => match c.kind() { ConstKind::Param(_) => { - self.errors.push(PatternError::ConstParamInPattern(span)); + self.tcx.sess.emit_err(ConstParamInPattern { span }); return PatKind::Wild; } ConstKind::Error(_) => { diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 9edd7967e7a4..d8f66a1755b2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -300,7 +300,6 @@ use rustc_arena::TypedArena; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; use rustc_hir::HirId; -use rustc_hir::Node; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_span::{Span, DUMMY_SP}; @@ -319,6 +318,8 @@ pub(crate) struct MatchCheckCtxt<'p, 'tcx> { pub(crate) module: DefId, pub(crate) param_env: ty::ParamEnv<'tcx>, pub(crate) pattern_arena: &'p TypedArena>, + /// Only produce `NON_EXHAUSTIVE_OMITTED_PATTERNS` lint on refutable patterns. + pub(crate) refutable: bool, } impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { @@ -604,7 +605,7 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { let new_patterns = if pcx.is_non_exhaustive { // Here we don't want the user to try to list all variants, we want them to add // a wildcard, so we only suggest that. - vec![DeconstructedPat::wildcard(pcx.ty)] + vec![DeconstructedPat::wildcard(pcx.ty, pcx.span)] } else { let mut split_wildcard = SplitWildcard::new(pcx); split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); @@ -631,7 +632,7 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { .collect(); if hide_variant_show_wild { - new.push(DeconstructedPat::wildcard(pcx.ty)); + new.push(DeconstructedPat::wildcard(pcx.ty, pcx.span)); } new @@ -734,7 +735,7 @@ impl<'p, 'tcx> Witness<'p, 'tcx> { let arity = ctor.arity(pcx); let pats = self.0.drain((len - arity)..).rev(); let fields = Fields::from_iter(pcx.cx, pats); - DeconstructedPat::new(ctor.clone(), fields, pcx.ty, DUMMY_SP) + DeconstructedPat::new(ctor.clone(), fields, pcx.ty, pcx.span) }; self.0.push(pat); @@ -765,13 +766,13 @@ impl<'p, 'tcx> Witness<'p, 'tcx> { /// `is_under_guard` is used to inform if the pattern has a guard. If it /// has one it must not be inserted into the matrix. This shouldn't be /// relied on for soundness. -#[instrument(level = "debug", skip(cx, matrix, hir_id), ret)] +#[instrument(level = "debug", skip(cx, matrix, lint_root), ret)] fn is_useful<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, matrix: &Matrix<'p, 'tcx>, v: &PatStack<'p, 'tcx>, witness_preference: ArmType, - hir_id: HirId, + lint_root: HirId, is_under_guard: bool, is_top_level: bool, ) -> Usefulness<'p, 'tcx> { @@ -804,7 +805,7 @@ fn is_useful<'p, 'tcx>( for v in v.expand_or_pat() { debug!(?v); let usefulness = ensure_sufficient_stack(|| { - is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false) + is_useful(cx, &matrix, &v, witness_preference, lint_root, is_under_guard, false) }); debug!(?usefulness); ret.extend(usefulness); @@ -837,7 +838,7 @@ fn is_useful<'p, 'tcx>( pcx, matrix.heads(), matrix.column_count().unwrap_or(0), - hir_id, + lint_root, ) } // We split the head constructor of `v`. @@ -852,7 +853,15 @@ fn is_useful<'p, 'tcx>( let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor); let v = v.pop_head_constructor(pcx, &ctor); let usefulness = ensure_sufficient_stack(|| { - is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false) + is_useful( + cx, + &spec_matrix, + &v, + witness_preference, + lint_root, + is_under_guard, + false, + ) }); let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor); @@ -860,6 +869,8 @@ fn is_useful<'p, 'tcx>( // that has the potential to trigger the `non_exhaustive_omitted_patterns` lint. // To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors` if is_non_exhaustive_and_wild + // Only emit a lint on refutable patterns. + && cx.refutable // We check that the match has a wildcard pattern and that wildcard is useful, // meaning there are variants that are covered by the wildcard. Without the check // for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}` @@ -868,8 +879,6 @@ fn is_useful<'p, 'tcx>( &ctor, Constructor::Missing { nonexhaustive_enum_missing_real_variants: true } ) - // We don't want to lint patterns which are function arguments or locals - && !matches!(cx.tcx.hir().find_parent(hir_id), Some(Node::Param(_)|Node::Local(_))) { let patterns = { let mut split_wildcard = SplitWildcard::new(pcx); @@ -896,7 +905,7 @@ fn is_useful<'p, 'tcx>( // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. cx.tcx.emit_spanned_lint( NON_EXHAUSTIVE_OMITTED_PATTERNS, - hir_id, + lint_root, pcx.span, NonExhaustiveOmittedPattern { scrut_ty: pcx.ty, @@ -954,7 +963,7 @@ pub(crate) struct UsefulnessReport<'p, 'tcx> { pub(crate) fn compute_match_usefulness<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, arms: &[MatchArm<'p, 'tcx>], - scrut_hir_id: HirId, + lint_root: HirId, scrut_ty: Ty<'tcx>, ) -> UsefulnessReport<'p, 'tcx> { let mut matrix = Matrix::empty(); @@ -977,9 +986,9 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( }) .collect(); - let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty)); + let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP)); let v = PatStack::from_pattern(wild_pattern); - let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, scrut_hir_id, false, true); + let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, lint_root, false, true); let non_exhaustiveness_witnesses = match usefulness { WithWitnesses(pats) => pats.into_iter().map(|w| w.single_pattern()).collect(), NoWitnesses { .. } => bug!(), diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 8028227aafd2..ed61d6ee78b1 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -151,6 +151,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { initializer, else_block, lint_level, + span, } => { print_indented!(self, "kind: Let {", depth_lvl + 1); print_indented!( @@ -181,6 +182,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { } print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 2); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } } diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 7ef3d41ac48c..bd8ec82dffd1 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -77,10 +77,10 @@ impl Unwind { } } - fn into_option(self) -> Option { + fn into_action(self) -> UnwindAction { match self { - Unwind::To(bb) => Some(bb), - Unwind::InCleanup => None, + Unwind::To(bb) => UnwindAction::Cleanup(bb), + Unwind::InCleanup => UnwindAction::Terminate, } } @@ -236,7 +236,7 @@ where TerminatorKind::Drop { place: self.place, target: self.succ, - unwind: self.unwind.into_option(), + unwind: self.unwind.into_action(), }, ); } @@ -640,7 +640,7 @@ where args: vec![Operand::Move(Place::from(ref_place))], destination: unit_temp, target: Some(succ), - cleanup: unwind.into_option(), + unwind: unwind.into_action(), from_hir_call: true, fn_span: self.source_info.span, }, @@ -717,7 +717,7 @@ where TerminatorKind::Drop { place: tcx.mk_place_deref(ptr), target: loop_block, - unwind: unwind.into_option(), + unwind: unwind.into_action(), }, ); @@ -946,7 +946,11 @@ where args, destination: unit_temp, target: Some(target), - cleanup: None, + unwind: if unwind.is_cleanup() { + UnwindAction::Terminate + } else { + UnwindAction::Continue + }, from_hir_call: false, fn_span: self.source_info.span, }; // FIXME(#43234) @@ -959,7 +963,7 @@ where fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { let block = - TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_option() }; + TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_action() }; self.new_block(unwind, block) } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index a40c38aa4c33..c8fe1af6674c 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -1,4 +1,4 @@ -use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets}; +use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets, UnwindAction}; use rustc_middle::ty::TyCtxt; use std::ops::RangeInclusive; @@ -474,14 +474,14 @@ impl Direction for Forward { { use mir::TerminatorKind::*; match bb_data.terminator().kind { - Return | Resume | Abort | GeneratorDrop | Unreachable => {} + Return | Resume | Terminate | GeneratorDrop | Unreachable => {} Goto { target } => propagate(target, exit_state), - Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ } + Assert { target, unwind, expected: _, msg: _, cond: _ } | Drop { target, unwind, place: _ } | FalseUnwind { real_target: target, unwind } => { - if let Some(unwind) = unwind { + if let UnwindAction::Cleanup(unwind) = unwind { propagate(unwind, exit_state); } @@ -503,7 +503,7 @@ impl Direction for Forward { } Call { - cleanup, + unwind, destination, target, func: _, @@ -511,7 +511,7 @@ impl Direction for Forward { from_hir_call: _, fn_span: _, } => { - if let Some(unwind) = cleanup { + if let UnwindAction::Cleanup(unwind) = unwind { propagate(unwind, exit_state); } @@ -533,9 +533,9 @@ impl Direction for Forward { options: _, line_spans: _, destination, - cleanup, + unwind, } => { - if let Some(unwind) = cleanup { + if let UnwindAction::Cleanup(unwind) = unwind { propagate(unwind, exit_state); } diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 91c3bf0ad21f..2abdee064a68 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -15,6 +15,7 @@ use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::{self, traversal, BasicBlock}; use rustc_middle::mir::{create_dump_file, dump_enabled}; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{sym, Symbol}; @@ -285,7 +286,7 @@ where if tcx.sess.opts.unstable_opts.graphviz_dark_mode { render_opts.push(dot::RenderOption::DarkTheme); } - dot::render_opts(&graphviz, &mut buf, &render_opts)?; + with_no_trimmed_paths!(dot::render_opts(&graphviz, &mut buf, &render_opts)?); file.write_all(&buf)?; diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 96c42894b697..c188105eae89 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -6,6 +6,7 @@ use std::{io, ops, str}; use regex::Regex; use rustc_graphviz as dot; +use rustc_index::bit_set::BitSet; use rustc_middle::mir::graphviz_safe_def_name; use rustc_middle::mir::{self, BasicBlock, Body, Location}; @@ -34,6 +35,7 @@ where body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle, + reachable: BitSet, } impl<'a, 'tcx, A> Formatter<'a, 'tcx, A> @@ -41,7 +43,8 @@ where A: Analysis<'tcx>, { pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle) -> Self { - Formatter { body, results, style } + let reachable = mir::traversal::reachable_as_bitset(body); + Formatter { body, results, style, reachable } } } @@ -108,7 +111,12 @@ where type Edge = CfgEdge; fn nodes(&self) -> dot::Nodes<'_, Self::Node> { - self.body.basic_blocks.indices().collect::>().into() + self.body + .basic_blocks + .indices() + .filter(|&idx| self.reachable.contains(idx)) + .collect::>() + .into() } fn edges(&self) -> dot::Edges<'_, Self::Edge> { diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 17102454a88d..60679b17d6c4 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -39,7 +39,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { args: vec![], destination: dummy_place.clone(), target: Some(mir::START_BLOCK), - cleanup: None, + unwind: mir::UnwindAction::Continue, from_hir_call: false, fn_span: DUMMY_SP, }, @@ -53,7 +53,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { args: vec![], destination: dummy_place.clone(), target: Some(mir::START_BLOCK), - cleanup: None, + unwind: mir::UnwindAction::Continue, from_hir_call: false, fn_span: DUMMY_SP, }, diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 08fadfe68a17..92d30f254a6a 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -125,7 +125,7 @@ where } } - TerminatorKind::Abort + TerminatorKind::Terminate | TerminatorKind::Assert { .. } | TerminatorKind::Call { .. } | TerminatorKind::FalseEdge { .. } diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 99988b29e8a5..4a5d9d520108 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -200,7 +200,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc // Nothing to do for these. Match exhaustively so this fails to compile when new // variants are added. - TerminatorKind::Abort + TerminatorKind::Terminate | TerminatorKind::Assert { .. } | TerminatorKind::Drop { .. } | TerminatorKind::FalseEdge { .. } @@ -237,7 +237,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc // Nothing to do for these. Match exhaustively so this fails to compile when new // variants are added. TerminatorKind::Yield { .. } - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Assert { .. } | TerminatorKind::Drop { .. } | TerminatorKind::FalseEdge { .. } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index d9ceac1154f4..64ed7a29f6f3 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -375,7 +375,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // need recording. | TerminatorKind::Return | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } => {} @@ -398,7 +398,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { ref args, destination, target, - cleanup: _, + unwind: _, from_hir_call: _, fn_span: _, } => { @@ -417,7 +417,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { options: _, line_spans: _, destination: _, - cleanup: _, + unwind: _, } => { for op in operands { match *op { diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 33a15a8d224f..98bebc9b13bc 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -238,7 +238,7 @@ pub trait ValueAnalysis<'tcx> { TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Assert { .. } diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index 893018e0d8e7..5aed89139e2f 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -34,11 +34,6 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { return; } - // This pass only runs on functions which themselves cannot unwind, - // forcibly changing the body of the function to structurally provide - // this guarantee by aborting on an unwind. If this function can unwind, - // then there's nothing to do because it already should work correctly. - // // Here we test for this function itself whether its ABI allows // unwinding or not. let body_ty = tcx.type_of(def_id).skip_binder(); @@ -107,31 +102,14 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { } } - // For call instructions which need to be terminated, we insert a - // singular basic block which simply terminates, and then configure the - // `cleanup` attribute for all calls we found to this basic block we - // insert which means that any unwinding that happens in the functions - // will force an abort of the process. - if !calls_to_terminate.is_empty() { - let bb = BasicBlockData { - statements: Vec::new(), - is_cleanup: true, - terminator: Some(Terminator { - source_info: SourceInfo::outermost(body.span), - kind: TerminatorKind::Abort, - }), - }; - let abort_bb = body.basic_blocks_mut().push(bb); - - for bb in calls_to_terminate { - let cleanup = body.basic_blocks_mut()[bb].terminator_mut().unwind_mut().unwrap(); - *cleanup = Some(abort_bb); - } + for id in calls_to_terminate { + let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap(); + *cleanup = UnwindAction::Terminate; } for id in cleanups_to_remove { let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap(); - *cleanup = None; + *cleanup = UnwindAction::Unreachable; } // We may have invalidated some `cleanup` blocks so clean those up now. diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs index 30966d22e2f6..e1e354efa1c4 100644 --- a/compiler/rustc_mir_transform/src/add_call_guards.rs +++ b/compiler/rustc_mir_transform/src/add_call_guards.rs @@ -50,10 +50,11 @@ impl AddCallGuards { for block in body.basic_blocks_mut() { match block.terminator { Some(Terminator { - kind: TerminatorKind::Call { target: Some(ref mut destination), cleanup, .. }, + kind: TerminatorKind::Call { target: Some(ref mut destination), unwind, .. }, source_info, }) if pred_count[*destination] > 1 - && (cleanup.is_some() || self == &AllCallEdges) => + && (matches!(unwind, UnwindAction::Cleanup(_) | UnwindAction::Terminate) + || self == &AllCallEdges) => { // It's a critical edge, break it let call_guard = BasicBlockData { diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index 5815887e5bbb..8086a4557b70 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -221,7 +221,7 @@ fn insert_alignment_check<'tcx>( required: Operand::Copy(alignment), found: Operand::Copy(addr), }, - cleanup: None, + unwind: UnwindAction::Terminate, }, }); } diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index c4d058e8ecbf..d908f6b3a9b5 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -57,7 +57,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { | TerminatorKind::Assert { .. } | TerminatorKind::GeneratorDrop | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::FalseEdge { .. } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index ac55948e61b5..79a9ac7d20c1 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -24,7 +24,7 @@ use crate::MirPass; use rustc_const_eval::interpret::{ self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame, ImmTy, Immediate, InterpCx, InterpResult, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, - Scalar, StackPopCleanup, StackPopUnwind, + Scalar, StackPopCleanup, }; /// The maximum number of bytes that we'll allocate space for a local or the return value. @@ -115,10 +115,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { .predicates .iter() .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); - if traits::impossible_predicates( - tcx, - traits::elaborate_predicates(tcx, predicates).collect(), - ) { + if traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect()) { trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id); return; } @@ -209,7 +206,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _args: &[OpTy<'tcx>], _destination: &PlaceTy<'tcx>, _target: Option, - _unwind: StackPopUnwind, + _unwind: UnwindAction, ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> { Ok(None) } @@ -220,7 +217,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _args: &[OpTy<'tcx>], _destination: &PlaceTy<'tcx>, _target: Option, - _unwind: StackPopUnwind, + _unwind: UnwindAction, ) -> InterpResult<'tcx> { throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp") } @@ -228,7 +225,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> fn assert_panic( _ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: &rustc_middle::mir::AssertMessage<'tcx>, - _unwind: Option, + _unwind: rustc_middle::mir::UnwindAction, ) -> InterpResult<'tcx> { bug!("panics terminators are not evaluated in ConstProp") } @@ -959,7 +956,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { // None of these have Operands to const-propagate. TerminatorKind::Goto { .. } | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index d7696a570006..699fe44892b2 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -1,7 +1,7 @@ //! Propagates constants for early reporting of statically known //! assertion failures -use either::{Left, Right}; +use either::Left; use rustc_const_eval::interpret::Immediate; use rustc_const_eval::interpret::{ @@ -9,7 +9,7 @@ use rustc_const_eval::interpret::{ }; use rustc_hir::def::DefKind; use rustc_hir::HirId; -use rustc_index::vec::IndexSlice; +use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; @@ -91,10 +91,7 @@ impl<'tcx> MirLint<'tcx> for ConstProp { .predicates .iter() .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); - if traits::impossible_predicates( - tcx, - traits::elaborate_predicates(tcx, predicates).collect(), - ) { + if traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect()) { trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id); return; } @@ -130,11 +127,8 @@ struct ConstPropagator<'mir, 'tcx> { ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, - source_scopes: &'mir IndexSlice>, - local_decls: &'mir IndexSlice>, - // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store - // the last known `SourceInfo` here and just keep revisiting it. - source_info: Option, + worklist: Vec, + visited_blocks: BitSet, } impl<'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'_, 'tcx> { @@ -213,12 +207,19 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ecx, tcx, param_env, - source_scopes: &dummy_body.source_scopes, - local_decls: &dummy_body.local_decls, - source_info: None, + worklist: vec![START_BLOCK], + visited_blocks: BitSet::new_empty(body.basic_blocks.len()), } } + fn body(&self) -> &'mir Body<'tcx> { + self.ecx.frame().body + } + + fn local_decls(&self) -> &'mir LocalDecls<'tcx> { + &self.body().local_decls + } + fn get_const(&self, place: Place<'tcx>) -> Option> { let op = match self.ecx.eval_place_to_op(place, None) { Ok(op) => { @@ -251,15 +252,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } fn lint_root(&self, source_info: SourceInfo) -> Option { - source_info.scope.lint_root(self.source_scopes) + source_info.scope.lint_root(&self.body().source_scopes) } - fn use_ecx(&mut self, source_info: SourceInfo, f: F) -> Option + fn use_ecx(&mut self, location: Location, f: F) -> Option where F: FnOnce(&mut Self) -> InterpResult<'tcx, T>, { // Overwrite the PC -- whatever the interpreter does to it does not make any sense anyway. - self.ecx.frame_mut().loc = Right(source_info.span); + self.ecx.frame_mut().loc = Left(location); match f(self) { Ok(val) => Some(val), Err(error) => { @@ -278,51 +279,55 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } /// Returns the value, if any, of evaluating `c`. - fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option> { + fn eval_constant(&mut self, c: &Constant<'tcx>, location: Location) -> Option> { // FIXME we need to revisit this for #67176 if c.needs_subst() { return None; } - self.use_ecx(source_info, |this| this.ecx.eval_mir_constant(&c.literal, Some(c.span), None)) + // Normalization needed b/c const prop lint runs in + // `mir_drops_elaborated_and_const_checked`, which happens before + // optimized MIR. Only after optimizing the MIR can we guarantee + // that the `RevealAll` pass has happened and that the body's consts + // are normalized, so any call to resolve before that needs to be + // manually normalized. + let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.literal).ok()?; + + self.use_ecx(location, |this| this.ecx.eval_mir_constant(&val, Some(c.span), None)) } /// Returns the value, if any, of evaluating `place`. - fn eval_place(&mut self, place: Place<'tcx>, source_info: SourceInfo) -> Option> { + fn eval_place(&mut self, place: Place<'tcx>, location: Location) -> Option> { trace!("eval_place(place={:?})", place); - self.use_ecx(source_info, |this| this.ecx.eval_place_to_op(place, None)) + self.use_ecx(location, |this| this.ecx.eval_place_to_op(place, None)) } /// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant` /// or `eval_place`, depending on the variant of `Operand` used. - fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option> { + fn eval_operand(&mut self, op: &Operand<'tcx>, location: Location) -> Option> { match *op { - Operand::Constant(ref c) => self.eval_constant(c, source_info), - Operand::Move(place) | Operand::Copy(place) => self.eval_place(place, source_info), + Operand::Constant(ref c) => self.eval_constant(c, location), + Operand::Move(place) | Operand::Copy(place) => self.eval_place(place, location), } } fn report_assert_as_lint( &self, lint: &'static lint::Lint, - source_info: SourceInfo, + location: Location, message: &'static str, panic: AssertKind, ) { - if let Some(lint_root) = self.lint_root(source_info) { + let source_info = self.body().source_info(location); + if let Some(lint_root) = self.lint_root(*source_info) { self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, message, |lint| { lint.span_label(source_info.span, format!("{:?}", panic)) }); } } - fn check_unary_op( - &mut self, - op: UnOp, - arg: &Operand<'tcx>, - source_info: SourceInfo, - ) -> Option<()> { - if let (val, true) = self.use_ecx(source_info, |this| { + fn check_unary_op(&mut self, op: UnOp, arg: &Operand<'tcx>, location: Location) -> Option<()> { + if let (val, true) = self.use_ecx(location, |this| { let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?; let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, &val)?; Ok((val, overflow)) @@ -332,7 +337,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow"); self.report_assert_as_lint( lint::builtin::ARITHMETIC_OVERFLOW, - source_info, + location, "this arithmetic operation will overflow", AssertKind::OverflowNeg(val.to_const_int()), ); @@ -347,28 +352,27 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { op: BinOp, left: &Operand<'tcx>, right: &Operand<'tcx>, - source_info: SourceInfo, + location: Location, ) -> Option<()> { - let r = self.use_ecx(source_info, |this| { + let r = self.use_ecx(location, |this| { this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?) }); - let l = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?) - }); + let l = self + .use_ecx(location, |this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?)); // Check for exceeding shifts *even if* we cannot evaluate the LHS. if matches!(op, BinOp::Shr | BinOp::Shl) { let r = r.clone()?; // We need the type of the LHS. We cannot use `place_layout` as that is the type // of the result, which for checked binops is not the same! - let left_ty = left.ty(self.local_decls, self.tcx); + let left_ty = left.ty(self.local_decls(), self.tcx); let left_size = self.ecx.layout_of(left_ty).ok()?.size; let right_size = r.layout.size; let r_bits = r.to_scalar().to_bits(right_size).ok(); if r_bits.map_or(false, |b| b >= left_size.bits() as u128) { - debug!("check_binary_op: reporting assert for {:?}", source_info); + debug!("check_binary_op: reporting assert for {:?}", location); self.report_assert_as_lint( lint::builtin::ARITHMETIC_OVERFLOW, - source_info, + location, "this arithmetic operation will overflow", AssertKind::Overflow( op, @@ -390,13 +394,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if let (Some(l), Some(r)) = (l, r) { // The remaining operators are handled through `overflowing_binary_op`. - if self.use_ecx(source_info, |this| { + if self.use_ecx(location, |this| { let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, &l, &r)?; Ok(overflow) })? { self.report_assert_as_lint( lint::builtin::ARITHMETIC_OVERFLOW, - source_info, + location, "this arithmetic operation will overflow", AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()), ); @@ -406,7 +410,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Some(()) } - fn check_rvalue(&mut self, rvalue: &Rvalue<'tcx>, source_info: SourceInfo) -> Option<()> { + fn check_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) -> Option<()> { // Perform any special handling for specific Rvalue types. // Generally, checks here fall into one of two categories: // 1. Additional checking to provide useful lints to the user @@ -421,11 +425,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // lint. Rvalue::UnaryOp(op, arg) => { trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg); - self.check_unary_op(*op, arg, source_info)?; + self.check_unary_op(*op, arg, location)?; } Rvalue::BinaryOp(op, box (left, right)) => { trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); - self.check_binary_op(*op, left, right, source_info)?; + self.check_binary_op(*op, left, right, location)?; } Rvalue::CheckedBinaryOp(op, box (left, right)) => { trace!( @@ -434,7 +438,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { left, right ); - self.check_binary_op(*op, left, right, source_info)?; + self.check_binary_op(*op, left, right, location)?; } // Do not try creating references (#67862) @@ -473,10 +477,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if rvalue.needs_subst() { return None; } - if !rvalue - .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx) - .is_sized(*self.ecx.tcx, self.param_env) - { + if !rvalue.ty(self.local_decls(), self.tcx).is_sized(self.tcx, self.param_env) { // the interpreter doesn't support unsized locals (only unsized arguments), // but rustc does (in a kinda broken way), so we have to skip them here return None; @@ -485,12 +486,80 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Some(()) } + fn check_assertion( + &mut self, + expected: bool, + msg: &AssertKind>, + cond: &Operand<'tcx>, + location: Location, + ) -> Option { + let ref value = self.eval_operand(&cond, location)?; + trace!("assertion on {:?} should be {:?}", value, expected); + + let expected = Scalar::from_bool(expected); + let value_const = self.use_ecx(location, |this| this.ecx.read_scalar(&value))?; + + if expected != value_const { + // Poison all places this operand references so that further code + // doesn't use the invalid value + if let Some(place) = cond.place() { + Self::remove_const(&mut self.ecx, place.local); + } + + enum DbgVal { + Val(T), + Underscore, + } + impl std::fmt::Debug for DbgVal { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Val(val) => val.fmt(fmt), + Self::Underscore => fmt.write_str("_"), + } + } + } + let mut eval_to_int = |op| { + // This can be `None` if the lhs wasn't const propagated and we just + // triggered the assert on the value of the rhs. + self.eval_operand(op, location) + .and_then(|op| self.ecx.read_immediate(&op).ok()) + .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int())) + }; + let msg = match msg { + AssertKind::DivisionByZero(op) => AssertKind::DivisionByZero(eval_to_int(op)), + AssertKind::RemainderByZero(op) => AssertKind::RemainderByZero(eval_to_int(op)), + AssertKind::Overflow(bin_op @ (BinOp::Div | BinOp::Rem), op1, op2) => { + // Division overflow is *UB* in the MIR, and different than the + // other overflow checks. + AssertKind::Overflow(*bin_op, eval_to_int(op1), eval_to_int(op2)) + } + AssertKind::BoundsCheck { ref len, ref index } => { + let len = eval_to_int(len); + let index = eval_to_int(index); + AssertKind::BoundsCheck { len, index } + } + // Remaining overflow errors are already covered by checks on the binary operators. + AssertKind::Overflow(..) | AssertKind::OverflowNeg(_) => return None, + // Need proper const propagator for these. + _ => return None, + }; + self.report_assert_as_lint( + lint::builtin::UNCONDITIONAL_PANIC, + location, + "this operation will panic at runtime", + msg, + ); + } + + None + } + fn ensure_not_propagated(&self, local: Local) { if cfg!(debug_assertions) { assert!( self.get_const(local.into()).is_none() || self - .layout_of(self.local_decls[local].ty) + .layout_of(self.local_decls()[local].ty) .map_or(true, |layout| layout.is_zst()), "failed to remove values for `{local:?}`, value={:?}", self.get_const(local.into()), @@ -501,7 +570,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { fn visit_body(&mut self, body: &Body<'tcx>) { - for (bb, data) in body.basic_blocks.iter_enumerated() { + while let Some(bb) = self.worklist.pop() { + if !self.visited_blocks.insert(bb) { + continue; + } + + let data = &body.basic_blocks[bb]; self.visit_basic_block_data(bb, data); } } @@ -513,14 +587,13 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { trace!("visit_constant: {:?}", constant); self.super_constant(constant, location); - self.eval_constant(constant, self.source_info.unwrap()); + self.eval_constant(constant, location); } fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { self.super_assign(place, rvalue, location); - let source_info = self.source_info.unwrap(); - let Some(()) = self.check_rvalue(rvalue, source_info) else { return }; + let Some(()) = self.check_rvalue(rvalue, location) else { return }; match self.ecx.machine.can_const_prop[place.local] { // Do nothing if the place is indirect. @@ -528,7 +601,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local), ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => { if self - .use_ecx(source_info, |this| this.ecx.eval_rvalue_into_place(rvalue, *place)) + .use_ecx(location, |this| this.ecx.eval_rvalue_into_place(rvalue, *place)) .is_none() { // Const prop failed, so erase the destination, ensuring that whatever happens @@ -554,8 +627,6 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { trace!("visit_statement: {:?}", statement); - let source_info = statement.source_info; - self.source_info = Some(source_info); // We want to evaluate operands before any change to the assigned-to value, // so we recurse first. @@ -568,8 +639,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { _ if place.is_indirect() => {} ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local), ConstPropMode::FullConstProp | ConstPropMode::OnlyInsideOwnBlock => { - if self.use_ecx(source_info, |this| this.ecx.statement(statement)).is_some() - { + if self.use_ecx(location, |this| this.ecx.statement(statement)).is_some() { trace!("propped discriminant into {:?}", place); } else { Self::remove_const(&mut self.ecx, place.local); @@ -591,88 +661,29 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { } fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - let source_info = terminator.source_info; - self.source_info = Some(source_info); self.super_terminator(terminator, location); match &terminator.kind { TerminatorKind::Assert { expected, ref msg, ref cond, .. } => { - if let Some(ref value) = self.eval_operand(&cond, source_info) { - trace!("assertion on {:?} should be {:?}", value, expected); - let expected = Scalar::from_bool(*expected); - let Ok(value_const) = self.ecx.read_scalar(&value) else { - // FIXME should be used use_ecx rather than a local match... but we have - // quite a few of these read_scalar/read_immediate that need fixing. - return - }; - if expected != value_const { - enum DbgVal { - Val(T), - Underscore, - } - impl std::fmt::Debug for DbgVal { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Val(val) => val.fmt(fmt), - Self::Underscore => fmt.write_str("_"), - } - } - } - let mut eval_to_int = |op| { - // This can be `None` if the lhs wasn't const propagated and we just - // triggered the assert on the value of the rhs. - self.eval_operand(op, source_info) - .and_then(|op| self.ecx.read_immediate(&op).ok()) - .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int())) - }; - let msg = match msg { - AssertKind::DivisionByZero(op) => { - Some(AssertKind::DivisionByZero(eval_to_int(op))) - } - AssertKind::RemainderByZero(op) => { - Some(AssertKind::RemainderByZero(eval_to_int(op))) - } - AssertKind::Overflow(bin_op @ (BinOp::Div | BinOp::Rem), op1, op2) => { - // Division overflow is *UB* in the MIR, and different than the - // other overflow checks. - Some(AssertKind::Overflow( - *bin_op, - eval_to_int(op1), - eval_to_int(op2), - )) - } - AssertKind::BoundsCheck { ref len, ref index } => { - let len = eval_to_int(len); - let index = eval_to_int(index); - Some(AssertKind::BoundsCheck { len, index }) - } - // Remaining overflow errors are already covered by checks on the binary operators. - AssertKind::Overflow(..) | AssertKind::OverflowNeg(_) => None, - // Need proper const propagator for these. - _ => None, - }; - // Poison all places this operand references so that further code - // doesn't use the invalid value - match cond { - Operand::Move(ref place) | Operand::Copy(ref place) => { - Self::remove_const(&mut self.ecx, place.local); - } - Operand::Constant(_) => {} - } - if let Some(msg) = msg { - self.report_assert_as_lint( - lint::builtin::UNCONDITIONAL_PANIC, - source_info, - "this operation will panic at runtime", - msg, - ); - } - } + self.check_assertion(*expected, msg, cond, location); + } + TerminatorKind::SwitchInt { ref discr, ref targets } => { + if let Some(ref value) = self.eval_operand(&discr, location) + && let Some(value_const) = self.use_ecx(location, |this| this.ecx.read_scalar(&value)) + && let Ok(constant) = value_const.try_to_int() + && let Ok(constant) = constant.to_bits(constant.size()) + { + // We managed to evaluate the discriminant, so we know we only need to visit + // one target. + let target = targets.target_for_value(constant); + self.worklist.push(target); + return; } + // We failed to evaluate the discriminant, fallback to visiting all successors. } // None of these have Operands to const-propagate. TerminatorKind::Goto { .. } | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } @@ -680,10 +691,11 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { | TerminatorKind::GeneratorDrop | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::SwitchInt { .. } | TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => {} } + + self.worklist.extend(terminator.successors()); } fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index 0e7dc171a5d0..725883b83fa9 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -818,7 +818,7 @@ pub(super) fn term_type(kind: &TerminatorKind<'_>) -> &'static str { TerminatorKind::Goto { .. } => "Goto", TerminatorKind::SwitchInt { .. } => "SwitchInt", TerminatorKind::Resume => "Resume", - TerminatorKind::Abort => "Abort", + TerminatorKind::Terminate => "Terminate", TerminatorKind::Return => "Return", TerminatorKind::Unreachable => "Unreachable", TerminatorKind::Drop { .. } => "Drop", diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 689d6c71361d..7391a77b0a66 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -37,8 +37,7 @@ impl CoverageGraph { // `SwitchInt` to have multiple targets to the same destination `BasicBlock`, so // de-duplication is required. This is done without reordering the successors. - let bcbs_len = bcbs.len(); - let mut seen = IndexVec::from_elem_n(false, bcbs_len); + let mut seen = IndexVec::from_elem(false, &bcbs); let successors = IndexVec::from_fn_n( |bcb| { for b in seen.iter_mut() { @@ -60,7 +59,7 @@ impl CoverageGraph { bcbs.len(), ); - let mut predecessors = IndexVec::from_elem_n(Vec::new(), bcbs.len()); + let mut predecessors = IndexVec::from_elem(Vec::new(), &bcbs); for (bcb, bcb_successors) in successors.iter_enumerated() { for &successor in bcb_successors { predecessors[successor].push(bcb); @@ -123,7 +122,7 @@ impl CoverageGraph { match term.kind { TerminatorKind::Return { .. } - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Yield { .. } | TerminatorKind::SwitchInt { .. } => { // The `bb` has more than one _outgoing_ edge, or exits the function. Save the @@ -137,7 +136,7 @@ impl CoverageGraph { debug!(" because term.kind = {:?}", term.kind); // Note that this condition is based on `TerminatorKind`, even though it // theoretically boils down to `successors().len() != 1`; that is, either zero - // (e.g., `Return`, `Abort`) or multiple successors (e.g., `SwitchInt`), but + // (e.g., `Return`, `Terminate`) or multiple successors (e.g., `SwitchInt`), but // since the BCB CFG ignores things like unwind branches (which exist in the // `Terminator`s `successors()` list) checking the number of successors won't // work. diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 2f1202586594..287ae2170875 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -869,7 +869,7 @@ pub(super) fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option MockBlocks<'tcx> { args: vec![], destination: self.dummy_place.clone(), target: Some(TEMP_BLOCK), - cleanup: None, + unwind: UnwindAction::Continue, from_hir_call: false, fn_span: DUMMY_SP, }, diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 15f5df41153b..d4db7e2de403 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -567,7 +567,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi _args: &[rustc_const_eval::interpret::OpTy<'tcx, Self::Provenance>], _destination: &rustc_const_eval::interpret::PlaceTy<'tcx, Self::Provenance>, _target: Option, - _unwind: rustc_const_eval::interpret::StackPopUnwind, + _unwind: UnwindAction, ) -> interpret::InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> { unimplemented!() } @@ -578,7 +578,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi _args: &[rustc_const_eval::interpret::OpTy<'tcx, Self::Provenance>], _destination: &rustc_const_eval::interpret::PlaceTy<'tcx, Self::Provenance>, _target: Option, - _unwind: rustc_const_eval::interpret::StackPopUnwind, + _unwind: UnwindAction, ) -> interpret::InterpResult<'tcx> { unimplemented!() } @@ -586,7 +586,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi fn assert_panic( _ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: &rustc_middle::mir::AssertMessage<'tcx>, - _unwind: Option, + _unwind: UnwindAction, ) -> interpret::InterpResult<'tcx> { unimplemented!() } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 35e7efed87a9..811935aa9908 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -645,8 +645,8 @@ impl WriteInfo { } } TerminatorKind::Goto { .. } - | TerminatorKind::Resume { .. } - | TerminatorKind::Abort { .. } + | TerminatorKind::Resume + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable { .. } => (), TerminatorKind::Drop { .. } => { diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index a028d6356d50..a702113bd999 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -120,7 +120,7 @@ fn remove_dead_unwinds<'tcx>( .into_results_cursor(body); for (bb, bb_data) in body.basic_blocks.iter_enumerated() { let place = match bb_data.terminator().kind { - TerminatorKind::Drop { ref place, unwind: Some(_), .. } => { + TerminatorKind::Drop { ref place, unwind: UnwindAction::Cleanup(_), .. } => { und.derefer(place.as_ref(), body).unwrap_or(*place) } _ => continue, @@ -160,7 +160,7 @@ fn remove_dead_unwinds<'tcx>( let basic_blocks = body.basic_blocks.as_mut(); for &bb in dead_unwinds.iter() { if let Some(unwind) = basic_blocks[bb].terminator_mut().unwind_mut() { - *unwind = None; + *unwind = UnwindAction::Unreachable; } } } @@ -399,7 +399,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let loc = Location { block: bb, statement_index: data.statements.len() }; let terminator = data.terminator(); - let resume_block = self.patch.resume_block(); match terminator.kind { TerminatorKind::Drop { mut place, target, unwind } => { if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) { @@ -408,19 +407,31 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.init_data.seek_before(loc); match self.move_data().rev_lookup.find(place.as_ref()) { - LookupResult::Exact(path) => elaborate_drop( - &mut Elaborator { ctxt: self }, - terminator.source_info, - place, - path, - target, - if data.is_cleanup { + LookupResult::Exact(path) => { + let unwind = if data.is_cleanup { Unwind::InCleanup } else { - Unwind::To(Option::unwrap_or(unwind, resume_block)) - }, - bb, - ), + match unwind { + UnwindAction::Cleanup(cleanup) => Unwind::To(cleanup), + UnwindAction::Continue => Unwind::To(self.patch.resume_block()), + UnwindAction::Unreachable => { + Unwind::To(self.patch.unreachable_cleanup_block()) + } + UnwindAction::Terminate => { + Unwind::To(self.patch.terminate_block()) + } + } + }; + elaborate_drop( + &mut Elaborator { ctxt: self }, + terminator.source_info, + place, + path, + target, + unwind, + bb, + ) + } LookupResult::Parent(..) => { if !matches!( terminator.source_info.span.desugaring_kind(), @@ -474,7 +485,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { continue; } if let TerminatorKind::Call { - destination, target: Some(tgt), cleanup: Some(_), .. + destination, + target: Some(tgt), + unwind: UnwindAction::Cleanup(_), + .. } = data.terminator().kind { assert!(!self.patch.is_patched(bb)); @@ -543,8 +557,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { // There may be a critical edge after this call, // so mark the return as initialized *before* the // call. - if let TerminatorKind::Call { destination, target: Some(_), cleanup: None, .. } = - data.terminator().kind + if let TerminatorKind::Call { + destination, + target: Some(_), + unwind: UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate, + .. + } = data.terminator().kind { assert!(!self.patch.is_patched(bb)); diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 66d32b954e47..8601c1b2d71a 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -34,7 +34,7 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> { args, destination: _, target: _, - cleanup: _, + unwind: _, from_hir_call: _, fn_span: _, } = &terminator.kind diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index af6422c72464..159780319ba5 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -287,7 +287,7 @@ impl<'tcx> TransformVisitor<'tcx> { statements.push(Statement { kind: StatementKind::Assign(Box::new(( Place::return_place(), - Rvalue::Aggregate(Box::new(kind), IndexVec::from_iter([val])), + Rvalue::Aggregate(Box::new(kind), [val].into()), ))), source_info, }); @@ -1060,7 +1060,12 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let unwind = if block_data.is_cleanup { Unwind::InCleanup } else { - Unwind::To(unwind.unwrap_or_else(|| elaborator.patch.resume_block())) + Unwind::To(match *unwind { + UnwindAction::Cleanup(tgt) => tgt, + UnwindAction::Continue => elaborator.patch.resume_block(), + UnwindAction::Unreachable => elaborator.patch.unreachable_cleanup_block(), + UnwindAction::Terminate => elaborator.patch.terminate_block(), + }) }; elaborate_drop( &mut elaborator, @@ -1147,7 +1152,7 @@ fn insert_panic_block<'tcx>( expected: true, msg: message, target: assert_block, - cleanup: None, + unwind: UnwindAction::Continue, }; let source_info = SourceInfo::outermost(body.span); @@ -1189,7 +1194,7 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { // These never unwind. TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop @@ -1248,8 +1253,8 @@ fn create_generator_resume_function<'tcx>( } else if !block.is_cleanup { // Any terminators that *can* unwind but don't have an unwind target set are also // pointed at our poisoning block (unless they're part of the cleanup path). - if let Some(unwind @ None) = block.terminator_mut().unwind_mut() { - *unwind = Some(poison_block); + if let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut() { + *unwind = UnwindAction::Cleanup(poison_block); } } } @@ -1294,8 +1299,11 @@ fn create_generator_resume_function<'tcx>( fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock { let return_block = insert_term_block(body, TerminatorKind::Return); - let term = - TerminatorKind::Drop { place: Place::from(SELF_ARG), target: return_block, unwind: None }; + let term = TerminatorKind::Drop { + place: Place::from(SELF_ARG), + target: return_block, + unwind: UnwindAction::Continue, + }; let source_info = SourceInfo::outermost(body.span); // Create a block to destroy an unresumed generators. This can only destroy upvars. @@ -1670,7 +1678,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { args, destination, target: Some(_), - cleanup: _, + unwind: _, from_hir_call: _, fn_span: _, } => { @@ -1693,7 +1701,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { | TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } | TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 15b31d383944..f0cb317f449f 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -453,7 +453,7 @@ impl<'tcx> Inliner<'tcx> { // If the place doesn't actually need dropping, treat it like a regular goto. let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty); - if ty.needs_drop(tcx, self.param_env) && let Some(unwind) = unwind { + if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind { work_list.push(unwind); } } else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set @@ -500,7 +500,7 @@ impl<'tcx> Inliner<'tcx> { ) { let terminator = caller_body[callsite.block].terminator.take().unwrap(); match terminator.kind { - TerminatorKind::Call { args, destination, cleanup, .. } => { + TerminatorKind::Call { args, destination, unwind, .. } => { // If the call is something like `a[*i] = f(i)`, where // `i : &mut usize`, then just duplicating the `a[*i]` // Place could result in two different locations if `f` @@ -571,7 +571,7 @@ impl<'tcx> Inliner<'tcx> { destination: destination_local, callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(), callsite, - cleanup_block: cleanup, + cleanup_block: unwind, in_cleanup_block: false, tcx: self.tcx, expn_data, @@ -813,14 +813,14 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { let ty = self.instance.subst_mir(tcx, &place.ty(self.callee_body, tcx).ty); if ty.needs_drop(tcx, self.param_env) { self.cost += CALL_PENALTY; - if unwind.is_some() { + if let UnwindAction::Cleanup(_) = unwind { self.cost += LANDINGPAD_PENALTY; } } else { self.cost += INSTR_COST; } } - TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => { + TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => { let fn_ty = self.instance.subst_mir(tcx, &f.literal.ty()); self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) { // Don't give intrinsics the extra penalty for calls @@ -828,20 +828,20 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { } else { CALL_PENALTY }; - if cleanup.is_some() { + if let UnwindAction::Cleanup(_) = unwind { self.cost += LANDINGPAD_PENALTY; } } - TerminatorKind::Assert { cleanup, .. } => { + TerminatorKind::Assert { unwind, .. } => { self.cost += CALL_PENALTY; - if cleanup.is_some() { + if let UnwindAction::Cleanup(_) = unwind { self.cost += LANDINGPAD_PENALTY; } } TerminatorKind::Resume => self.cost += RESUME_PENALTY, - TerminatorKind::InlineAsm { cleanup, .. } => { + TerminatorKind::InlineAsm { unwind, .. } => { self.cost += INSTR_COST; - if cleanup.is_some() { + if let UnwindAction::Cleanup(_) = unwind { self.cost += LANDINGPAD_PENALTY; } } @@ -979,7 +979,7 @@ struct Integrator<'a, 'tcx> { destination: Local, callsite_scope: SourceScopeData<'tcx>, callsite: &'a CallSite<'tcx>, - cleanup_block: Option, + cleanup_block: UnwindAction, in_cleanup_block: bool, tcx: TyCtxt<'tcx>, expn_data: LocalExpnId, @@ -1014,18 +1014,21 @@ impl Integrator<'_, '_> { new } - fn map_unwind(&self, unwind: Option) -> Option { + fn map_unwind(&self, unwind: UnwindAction) -> UnwindAction { if self.in_cleanup_block { - if unwind.is_some() { - bug!("cleanup on cleanup block"); + match unwind { + UnwindAction::Cleanup(_) | UnwindAction::Continue => { + bug!("cleanup on cleanup block"); + } + UnwindAction::Unreachable | UnwindAction::Terminate => return unwind, } - return unwind; } match unwind { - Some(target) => Some(self.map_block(target)), + UnwindAction::Unreachable | UnwindAction::Terminate => unwind, + UnwindAction::Cleanup(target) => UnwindAction::Cleanup(self.map_block(target)), // Add an unwind edge to the original call's cleanup block - None => self.cleanup_block, + UnwindAction::Continue => self.cleanup_block, } } } @@ -1116,15 +1119,15 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { *target = self.map_block(*target); *unwind = self.map_unwind(*unwind); } - TerminatorKind::Call { ref mut target, ref mut cleanup, .. } => { + TerminatorKind::Call { ref mut target, ref mut unwind, .. } => { if let Some(ref mut tgt) = *target { *tgt = self.map_block(*tgt); } - *cleanup = self.map_unwind(*cleanup); + *unwind = self.map_unwind(*unwind); } - TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => { + TerminatorKind::Assert { ref mut target, ref mut unwind, .. } => { *target = self.map_block(*target); - *cleanup = self.map_unwind(*cleanup); + *unwind = self.map_unwind(*unwind); } TerminatorKind::Return => { terminator.kind = if let Some(tgt) = self.callsite.target { @@ -1134,11 +1137,14 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { } } TerminatorKind::Resume => { - if let Some(tgt) = self.cleanup_block { - terminator.kind = TerminatorKind::Goto { target: tgt } - } + terminator.kind = match self.cleanup_block { + UnwindAction::Cleanup(tgt) => TerminatorKind::Goto { target: tgt }, + UnwindAction::Continue => TerminatorKind::Resume, + UnwindAction::Unreachable => TerminatorKind::Unreachable, + UnwindAction::Terminate => TerminatorKind::Terminate, + }; } - TerminatorKind::Abort => {} + TerminatorKind::Terminate => {} TerminatorKind::Unreachable => {} TerminatorKind::FalseEdge { ref mut real_target, ref mut imaginary_target } => { *real_target = self.map_block(*real_target); @@ -1149,11 +1155,11 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { { bug!("False unwinds should have been removed before inlining") } - TerminatorKind::InlineAsm { ref mut destination, ref mut cleanup, .. } => { + TerminatorKind::InlineAsm { ref mut destination, ref mut unwind, .. } => { if let Some(ref mut tgt) = *destination { *tgt = self.map_block(*tgt); } - *cleanup = self.map_unwind(*cleanup); + *unwind = self.map_unwind(*unwind); } } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index b52de4b72c9e..2e418c1dafc4 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -159,7 +159,7 @@ fn remap_mir_for_const_eval_select<'tcx>( ref mut args, destination, target, - cleanup, + unwind, fn_span, .. } if let ty::FnDef(def_id, _) = *literal.ty().kind() @@ -196,7 +196,7 @@ fn remap_mir_for_const_eval_select<'tcx>( }; method(place) }).collect(); - terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, cleanup, from_hir_call: false, fn_span }; + terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, unwind, from_hir_call: false, fn_span }; } _ => {} } diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 101fae2f08c5..7dc5878e0470 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -54,7 +54,6 @@ fn lower_slice_len_call<'tcx>( args, destination, target: Some(bb), - cleanup: None, from_hir_call: true, .. } => { diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index e962819b6917..4941c9edce30 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -72,7 +72,7 @@ impl RemoveNoopLandingPads { TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } | TerminatorKind::Return - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Unreachable | TerminatorKind::Call { .. } | TerminatorKind::Assert { .. } @@ -103,11 +103,11 @@ impl RemoveNoopLandingPads { for bb in postorder { debug!(" processing {:?}", bb); if let Some(unwind) = body[bb].terminator_mut().unwind_mut() { - if let Some(unwind_bb) = *unwind { + if let UnwindAction::Cleanup(unwind_bb) = *unwind { if nop_landing_pads.contains(unwind_bb) { debug!(" removing noop landing pad"); landing_pads_removed += 1; - *unwind = None; + *unwind = UnwindAction::Continue; } } } diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index d76ab95faba9..ef367faf6a70 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -112,7 +112,7 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize { | TerminatorKind::Assert { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Yield { .. } - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::InlineAsm { .. } @@ -164,7 +164,7 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize { } TerminatorKind::Resume - | TerminatorKind::Abort + | TerminatorKind::Terminate | TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 9e406eba0fca..2787fe2ce42c 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -499,7 +499,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { args: vec![Operand::Move(ref_loc)], destination: dest, target: Some(next), - cleanup: Some(cleanup), + unwind: UnwindAction::Cleanup(cleanup), from_hir_call: true, fn_span: self.span, }, @@ -540,7 +540,11 @@ impl<'tcx> CloneShimBuilder<'tcx> { self.make_clone_call(dest_field, src_field, ity, next_block, unwind); self.block( vec![], - TerminatorKind::Drop { place: dest_field, target: unwind, unwind: None }, + TerminatorKind::Drop { + place: dest_field, + target: unwind, + unwind: UnwindAction::Terminate, + }, true, ); unwind = next_unwind; @@ -776,10 +780,10 @@ fn build_call_shim<'tcx>( args, destination: Place::return_place(), target: Some(BasicBlock::new(1)), - cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment { - Some(BasicBlock::new(3)) + unwind: if let Some(Adjustment::RefMut) = rcvr_adjustment { + UnwindAction::Cleanup(BasicBlock::new(3)) } else { - None + UnwindAction::Continue }, from_hir_call: true, fn_span: span, @@ -792,7 +796,11 @@ fn build_call_shim<'tcx>( block( &mut blocks, vec![], - TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(2), unwind: None }, + TerminatorKind::Drop { + place: rcvr_place(), + target: BasicBlock::new(2), + unwind: UnwindAction::Continue, + }, false, ); } @@ -803,7 +811,11 @@ fn build_call_shim<'tcx>( block( &mut blocks, vec![], - TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(4), unwind: None }, + TerminatorKind::Drop { + place: rcvr_place(), + target: BasicBlock::new(4), + unwind: UnwindAction::Terminate, + }, true, ); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index f41edff8513d..7bcff7e07fb3 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -852,7 +852,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output.push(create_fn_mono_item(tcx, instance, source)); } } - mir::TerminatorKind::Abort { .. } => { + mir::TerminatorKind::Terminate { .. } => { let instance = Instance::mono( tcx, tcx.require_lang_item(LangItem::PanicCannotUnwind, Some(source)), @@ -872,6 +872,16 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { | mir::TerminatorKind::FalseUnwind { .. } => bug!(), } + if let Some(mir::UnwindAction::Terminate) = terminator.unwind() { + let instance = Instance::mono( + tcx, + tcx.require_lang_item(LangItem::PanicCannotUnwind, Some(source)), + ); + if should_codegen_locally(tcx, &instance) { + self.output.push(create_fn_mono_item(tcx, instance, source)); + } + } + self.super_terminator(terminator, location); } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 9dbddee5a56f..e41d0f7047b3 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -175,7 +175,7 @@ impl<'a> StringReader<'a> { if !sym.can_be_raw() { self.sess.emit_err(errors::CannotBeRawIdent { span, ident: sym }); } - self.sess.raw_identifier_spans.borrow_mut().push(span); + self.sess.raw_identifier_spans.push(span); token::Ident(sym, true) } rustc_lexer::TokenKind::UnknownPrefix => { @@ -558,8 +558,8 @@ impl<'a> StringReader<'a> { } if let Some(possible_offset) = possible_offset { - let lo = start + BytePos(possible_offset as u32); - let hi = lo + BytePos(found_terminators as u32); + let lo = start + BytePos(possible_offset); + let hi = lo + BytePos(found_terminators); let span = self.mk_sp(lo, hi); err.span_suggestion( span, diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index d4f971d5bc84..1f027c08fc3b 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -336,8 +336,8 @@ const ASCII_ARRAY: &[(&str, &str, Option)] = &[ ("\"", "Quotation Mark", None), ]; -pub(super) fn check_for_substitution<'a>( - reader: &StringReader<'a>, +pub(super) fn check_for_substitution( + reader: &StringReader<'_>, pos: BytePos, ch: char, count: usize, diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 5210b8fe69d6..e03ce5d71205 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -423,11 +423,11 @@ impl<'a> Parser<'a> { if let token::Literal(Lit { kind: token::LitKind::Integer | token::LitKind::Float, symbol, - suffix, + suffix: Some(suffix), // no suffix makes it a valid literal }) = self.token.kind && rustc_ast::MetaItemLit::from_token(&self.token).is_none() { - Some((symbol.as_str().len(), suffix.unwrap())) + Some((symbol.as_str().len(), suffix)) } else { None } diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 8d0f168e09d7..f8ef1307c988 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -53,7 +53,7 @@ impl<'a> Parser<'a> { let snapshot = self.create_snapshot_for_diagnostic(); match self.parse_ty() { Ok(p) => { - if let TyKind::ImplTrait(_, bounds) = &(*p).kind { + if let TyKind::ImplTrait(_, bounds) = &p.kind { let span = impl_span.to(self.token.span.shrink_to_lo()); let mut err = self.struct_span_err( span, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index ae8fe90e9d61..6422b8ac1ba4 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -3,6 +3,7 @@ use crate::errors; use super::diagnostics::{dummy_arg, ConsumeClosingDelim}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken}; +use ast::StaticItem; use rustc_ast::ast::*; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, TokenKind}; @@ -227,7 +228,7 @@ impl<'a> Parser<'a> { self.bump(); // `static` let m = self.parse_mutability(); let (ident, ty, expr) = self.parse_item_global(Some(m))?; - (ident, ItemKind::Static(ty, m, expr)) + (ident, ItemKind::Static(Box::new(StaticItem { ty, mutability: m, expr }))) } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM if self.token.is_keyword(kw::Impl) { @@ -236,7 +237,7 @@ impl<'a> Parser<'a> { } else { self.recover_const_mut(const_span); let (ident, ty, expr) = self.parse_item_global(None)?; - (ident, ItemKind::Const(def_(), ty, expr)) + (ident, ItemKind::Const(Box::new(ConstItem { defaultness: def_(), ty, expr }))) } } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() { // TRAIT ITEM @@ -862,9 +863,13 @@ impl<'a> Parser<'a> { let kind = match AssocItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Static(a, _, b) => { + ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { self.sess.emit_err(errors::AssociatedStaticItemNotAllowed { span }); - AssocItemKind::Const(Defaultness::Final, a, b) + AssocItemKind::Const(Box::new(ConstItem { + defaultness: Defaultness::Final, + ty, + expr, + })) } _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"), }, @@ -1114,12 +1119,12 @@ impl<'a> Parser<'a> { let kind = match ForeignItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Const(_, a, b) => { + ItemKind::Const(box ConstItem { ty, expr, .. }) => { self.sess.emit_err(errors::ExternItemCannotBeConst { ident_span: ident.span, const_span: span.with_hi(ident.span.lo()), }); - ForeignItemKind::Static(a, Mutability::Not, b) + ForeignItemKind::Static(ty, Mutability::Not, expr) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), }, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 53c25a80c4bf..aa57b804779b 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -29,6 +29,7 @@ use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutab use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Ordering; use rustc_errors::PResult; use rustc_errors::{ Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, IntoDiagnostic, MultiSpan, @@ -1540,8 +1541,10 @@ pub(crate) fn make_unclosed_delims_error( } pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, sess: &ParseSess) { - *sess.reached_eof.borrow_mut() |= - unclosed_delims.iter().any(|unmatched_delim| unmatched_delim.found_delim.is_none()); + let _ = sess.reached_eof.fetch_or( + unclosed_delims.iter().any(|unmatched_delim| unmatched_delim.found_delim.is_none()), + Ordering::Relaxed, + ); for unmatched in unclosed_delims.drain(..) { if let Some(mut e) = make_unclosed_delims_error(unmatched, sess) { e.emit(); diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 8c3dff23b272..e3e4b73efa32 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -187,7 +187,7 @@ fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 { fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) { let sp = tcx.def_span(CRATE_DEF_ID); - if *tcx.sess.parse_sess.reached_eof.borrow() { + if tcx.sess.parse_sess.reached_eof.load(rustc_data_structures::sync::Ordering::Relaxed) { // There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about // the missing `fn main()` then as it might have been hidden inside an unclosed block. tcx.sess.delay_span_bug(sp, "`main` not found, but expected unclosed brace error"); diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 4a1ba19c9206..4a35c6794663 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -530,7 +530,7 @@ struct MissingStabilityAnnotations<'tcx> { impl<'tcx> MissingStabilityAnnotations<'tcx> { fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { let stab = self.tcx.stability().local_stability(def_id); - if !self.tcx.sess.opts.test + if !self.tcx.sess.is_test_crate() && stab.is_none() && self.effective_visibilities.is_reachable(def_id) { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d27505d1ac84..089e043d61c3 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -515,16 +515,12 @@ impl<'tcx> EmbargoVisitor<'tcx> { let vis = self.tcx.local_visibility(item_id.owner_id.def_id); self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod); } - if let Some(exports) = self.tcx.module_reexports(module_def_id) { - for export in exports { - if export.vis.is_accessible_from(defining_mod, self.tcx) { - if let Res::Def(def_kind, def_id) = export.res { - if let Some(def_id) = def_id.as_local() { - let vis = self.tcx.local_visibility(def_id); - self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod); - } - } - } + for export in self.tcx.module_reexports(module_def_id) { + if export.vis.is_accessible_from(defining_mod, self.tcx) + && let Res::Def(def_kind, def_id) = export.res + && let Some(def_id) = def_id.as_local() { + let vis = self.tcx.local_visibility(def_id); + self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod); } } } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 021a67c9513c..7001a1eed57e 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -18,19 +18,21 @@ extern crate rustc_middle; use rustc_data_structures::sync::AtomicU64; use rustc_middle::arena::Arena; -use rustc_middle::dep_graph::{self, DepKindStruct}; +use rustc_middle::dep_graph::{self, DepKind, DepKindStruct}; +use rustc_middle::query::erase::{erase, restore, Erase}; use rustc_middle::query::AsLocalKey; use rustc_middle::ty::query::{ query_keys, query_provided, query_provided_to_value, query_storage, query_values, }; use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine}; use rustc_middle::ty::TyCtxt; +use rustc_query_system::dep_graph::SerializedDepNodeIndex; +use rustc_query_system::Value; use rustc_span::Span; #[macro_use] mod plumbing; pub use plumbing::QueryCtxt; -use rustc_query_system::dep_graph::SerializedDepNodeIndex; use rustc_query_system::query::*; #[cfg(parallel_compiler)] pub use rustc_query_system::query::{deadlock, QueryContext}; @@ -43,6 +45,13 @@ pub use on_disk_cache::OnDiskCache; mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; +/// This is implemented per query and restoring query values from their erased state. +trait QueryConfigRestored<'tcx>: QueryConfig> + Default { + type RestoredValue; + + fn restore(value: >>::Value) -> Self::RestoredValue; +} + rustc_query_append! { define_queries! } impl<'tcx> Queries<'tcx> { diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 35b7e5919e42..30477c7bd442 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -1046,8 +1046,6 @@ impl<'a, 'tcx> Encoder for CacheEncoder<'a, 'tcx> { emit_i8(i8); emit_bool(bool); - emit_f64(f64); - emit_f32(f32); emit_char(char); emit_str(&str); emit_raw_bytes(&[u8]); @@ -1064,14 +1062,14 @@ impl<'a, 'tcx> Encodable> for [u8] { } } -pub fn encode_query_results<'a, 'tcx, Q>( +pub(crate) fn encode_query_results<'a, 'tcx, Q>( query: Q, qcx: QueryCtxt<'tcx>, encoder: &mut CacheEncoder<'a, 'tcx>, query_result_index: &mut EncodedDepNodeIndex, ) where - Q: super::QueryConfig>, - Q::Value: Encodable>, + Q: super::QueryConfigRestored<'tcx>, + Q::RestoredValue: Encodable>, { let _timer = qcx .tcx @@ -1089,7 +1087,7 @@ pub fn encode_query_results<'a, 'tcx, Q>( // Encode the type check tables with the `SerializedDepNodeIndex` // as tag. - encoder.encode_tagged(dep_node, value); + encoder.encode_tagged(dep_node, &Q::restore(*value)); } }); } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 9bba26cc8e84..afbead7d1ae9 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -263,14 +263,14 @@ macro_rules! feedable { } macro_rules! hash_result { - ([]) => {{ - Some(dep_graph::hash_result) + ([][$V:ty]) => {{ + Some(|hcx, result| dep_graph::hash_result(hcx, &restore::<$V>(*result))) }}; - ([(no_hash) $($rest:tt)*]) => {{ + ([(no_hash) $($rest:tt)*][$V:ty]) => {{ None }}; - ([$other:tt $($modifiers:tt)*]) => { - hash_result!([$($modifiers)*]) + ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { + hash_result!([$($modifiers)*][$($args)*]) }; } @@ -479,13 +479,18 @@ macro_rules! define_queries { $(impl<'tcx> QueryConfig> for queries::$name<'tcx> { type Key = query_keys::$name<'tcx>; - type Value = query_values::$name<'tcx>; + type Value = Erase>; #[inline(always)] fn name(self) -> &'static str { stringify!($name) } + #[inline] + fn format_value(self) -> fn(&Self::Value) -> String { + |value| format!("{:?}", restore::>(*value)) + } + #[inline] fn cache_on_disk(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool { ::rustc_middle::query::cached::$name(tcx, key) @@ -508,7 +513,7 @@ macro_rules! define_queries { } fn execute_query(self, tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value { - tcx.$name(key) + erase(tcx.$name(key)) } #[inline] @@ -558,6 +563,16 @@ macro_rules! define_queries { }) } + #[inline] + fn value_from_cycle_error( + self, + tcx: TyCtxt<'tcx>, + cycle: &[QueryInfo], + ) -> Self::Value { + let result: query_values::$name<'tcx> = Value::from_cycle_error(tcx, cycle); + erase(result) + } + #[inline(always)] fn anon(self) -> bool { is_anon!([$($modifiers)*]) @@ -590,7 +605,16 @@ macro_rules! define_queries { #[inline(always)] fn hash_result(self) -> rustc_query_system::query::HashResult { - hash_result!([$($modifiers)*]) + hash_result!([$($modifiers)*][query_values::$name<'tcx>]) + } + })* + + $(impl<'tcx> QueryConfigRestored<'tcx> for queries::$name<'tcx> { + type RestoredValue = query_values::$name<'tcx>; + + #[inline(always)] + fn restore(value: >>::Value) -> Self::RestoredValue { + restore::>(value) } })* @@ -708,7 +732,7 @@ macro_rules! define_queries { ) }, encode_query_results: expand_if_cached!([$($modifiers)*], |qcx, encoder, query_result_index| - $crate::on_disk_cache::encode_query_results( + $crate::on_disk_cache::encode_query_results::>( super::queries::$name::default(), qcx, encoder, @@ -793,14 +817,14 @@ macro_rules! define_queries_struct { $($(#[$attr])* #[inline(always)] - #[tracing::instrument(level = "trace", skip(self, tcx), ret)] + #[tracing::instrument(level = "trace", skip(self, tcx))] fn $name( &'tcx self, tcx: TyCtxt<'tcx>, span: Span, - key: as QueryConfig>>::Key, + key: query_keys::$name<'tcx>, mode: QueryMode, - ) -> Option> { + ) -> Option>> { let qcx = QueryCtxt { tcx, queries: self }; get_query( queries::$name::default(), diff --git a/compiler/rustc_query_system/src/cache.rs b/compiler/rustc_query_system/src/cache.rs index 7cc885be2ba6..6e862db0b254 100644 --- a/compiler/rustc_query_system/src/cache.rs +++ b/compiler/rustc_query_system/src/cache.rs @@ -7,11 +7,16 @@ use rustc_data_structures::sync::Lock; use std::hash::Hash; -#[derive(Clone)] pub struct Cache { hashmap: Lock>>, } +impl Clone for Cache { + fn clone(&self) -> Self { + Self { hashmap: Lock::new(self.hashmap.borrow().clone()) } + } +} + impl Default for Cache { fn default() -> Self { Self { hashmap: Default::default() } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 2ff7de8cb9ef..534d13b1ae0f 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -538,7 +538,14 @@ impl DepGraph { if let Some(prev_index) = data.previous.node_to_index_opt(&node) { let dep_node_index = data.current.prev_index_to_index.lock()[prev_index]; if let Some(dep_node_index) = dep_node_index { - crate::query::incremental_verify_ich(cx, data, result, prev_index, hash_result); + crate::query::incremental_verify_ich( + cx, + data, + result, + prev_index, + hash_result, + |value| format!("{:?}", value), + ); #[cfg(debug_assertions)] if hash_result.is_some() { diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index d3efc22a1945..29f6a07e81be 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -18,7 +18,7 @@ pub trait CacheSelector<'tcx, V> { pub trait QueryCache: Sized { type Key: Hash + Eq + Copy + Debug; - type Value: Copy + Debug; + type Value: Copy; /// Checks if the query is already computed and in the cache. fn lookup(&self, key: &Self::Key) -> Option<(Self::Value, DepNodeIndex)>; @@ -52,7 +52,7 @@ impl Default for DefaultCache { impl QueryCache for DefaultCache where K: Eq + Hash + Copy + Debug, - V: Copy + Debug, + V: Copy, { type Key = K; type Value = V; @@ -120,7 +120,7 @@ impl Default for SingleCache { impl QueryCache for SingleCache where - V: Copy + Debug, + V: Copy, { type Key = (); type Value = V; @@ -136,7 +136,9 @@ where } fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { - self.cache.lock().as_ref().map(|value| f(&(), &value.0, value.1)); + if let Some(value) = self.cache.lock().as_ref() { + f(&(), &value.0, value.1) + } } } @@ -164,7 +166,7 @@ impl Default for VecCache { impl QueryCache for VecCache where K: Eq + Idx + Copy + Debug, - V: Copy + Debug, + V: Copy, { type Key = K; type Value = V; diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index a0aeb812af96..c8d779385108 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -4,7 +4,7 @@ use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex}; use crate::error::HandleCycleError; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; -use crate::query::{QueryContext, QueryState}; +use crate::query::{QueryContext, QueryInfo, QueryState}; use rustc_data_structures::fingerprint::Fingerprint; use std::fmt::Debug; @@ -20,10 +20,12 @@ pub trait QueryConfig: Copy { // `Key` and `Value` are `Copy` instead of `Clone` to ensure copying them stays cheap, // but it isn't necessary. type Key: DepNodeParams + Eq + Hash + Copy + Debug; - type Value: Debug + Copy; + type Value: Copy; type Cache: QueryCache; + fn format_value(self) -> fn(&Self::Value) -> String; + // Don't use this method to access query results, instead use the methods on TyCtxt fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState where @@ -45,6 +47,13 @@ pub trait QueryConfig: Copy { fn loadable_from_disk(self, qcx: Qcx, key: &Self::Key, idx: SerializedDepNodeIndex) -> bool; + /// Synthesize an error value to let compilation continue after a cycle. + fn value_from_cycle_error( + self, + tcx: Qcx::DepContext, + cycle: &[QueryInfo], + ) -> Self::Value; + fn anon(self) -> bool; fn eval_always(self) -> bool; fn depth_limit(self) -> bool; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 519ea5ffed18..20310483d7e8 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -11,7 +11,6 @@ use crate::query::job::QueryLatch; use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo}; use crate::query::SerializedDepNodeIndex; use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame}; -use crate::values::Value; use crate::HandleCycleError; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -120,43 +119,45 @@ where #[cold] #[inline(never)] -fn mk_cycle( +fn mk_cycle( + query: Q, qcx: Qcx, - cycle_error: CycleError, + cycle_error: CycleError, handler: HandleCycleError, -) -> R +) -> Q::Value where - Qcx: QueryContext + HasDepContext, - R: std::fmt::Debug + Value, + Q: QueryConfig, + Qcx: QueryContext, { let error = report_cycle(qcx.dep_context().sess(), &cycle_error); - handle_cycle_error(*qcx.dep_context(), &cycle_error, error, handler) + handle_cycle_error(query, qcx, &cycle_error, error, handler) } -fn handle_cycle_error( - tcx: Tcx, - cycle_error: &CycleError, +fn handle_cycle_error( + query: Q, + qcx: Qcx, + cycle_error: &CycleError, mut error: DiagnosticBuilder<'_, ErrorGuaranteed>, handler: HandleCycleError, -) -> V +) -> Q::Value where - Tcx: DepContext, - V: Value, + Q: QueryConfig, + Qcx: QueryContext, { use HandleCycleError::*; match handler { Error => { error.emit(); - Value::from_cycle_error(tcx, &cycle_error.cycle) + query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) } Fatal => { error.emit(); - tcx.sess().abort_if_errors(); + qcx.dep_context().sess().abort_if_errors(); unreachable!() } DelayBug => { error.delay_as_bug(); - Value::from_cycle_error(tcx, &cycle_error.cycle) + query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) } } } @@ -269,7 +270,7 @@ where &qcx.current_query_job(), span, ); - (mk_cycle(qcx, error, query.handle_cycle_error()), None) + (mk_cycle(query, qcx, error, query.handle_cycle_error()), None) } #[inline(always)] @@ -306,7 +307,7 @@ where (v, Some(index)) } - Err(cycle) => (mk_cycle(qcx, cycle, query.handle_cycle_error()), None), + Err(cycle) => (mk_cycle(query, qcx, cycle, query.handle_cycle_error()), None), } } @@ -410,7 +411,8 @@ where // get evaluated first, and re-feed the query. if let Some((cached_result, _)) = cache.lookup(&key) { panic!( - "fed query later has its value computed. The already cached value: {cached_result:?}" + "fed query later has its value computed. The already cached value: {}", + (query.format_value())(&cached_result) ); } } @@ -581,6 +583,7 @@ where &result, prev_dep_node_index, query.hash_result(), + query.format_value(), ); } @@ -626,19 +629,21 @@ where &result, prev_dep_node_index, query.hash_result(), + query.format_value(), ); Some((result, dep_node_index)) } #[inline] -#[instrument(skip(tcx, dep_graph_data, result, hash_result), level = "debug")] -pub(crate) fn incremental_verify_ich( +#[instrument(skip(tcx, dep_graph_data, result, hash_result, format_value), level = "debug")] +pub(crate) fn incremental_verify_ich( tcx: Tcx, dep_graph_data: &DepGraphData, result: &V, prev_index: SerializedDepNodeIndex, hash_result: Option, &V) -> Fingerprint>, + format_value: fn(&V) -> String, ) where Tcx: DepContext, { @@ -653,7 +658,7 @@ pub(crate) fn incremental_verify_ich( let old_hash = dep_graph_data.prev_fingerprint_of(prev_index); if new_hash != old_hash { - incremental_verify_ich_failed(tcx, prev_index, result); + incremental_verify_ich_failed(tcx, prev_index, &|| format_value(&result)); } } @@ -677,7 +682,7 @@ where fn incremental_verify_ich_failed( tcx: Tcx, prev_index: SerializedDepNodeIndex, - result: &dyn Debug, + result: &dyn Fn() -> String, ) where Tcx: DepContext, { @@ -707,7 +712,7 @@ fn incremental_verify_ich_failed( run_cmd, dep_node: format!("{dep_node:?}"), }); - panic!("Found unstable fingerprints for {dep_node:?}: {result:?}"); + panic!("Found unstable fingerprints for {dep_node:?}: {}", result()); } INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic)); diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 817bb83ed786..2199ceee5326 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -207,5 +207,9 @@ resolve_expected_found = resolve_indeterminate = cannot determine resolution for the visibility +resolve_tool_module_imported = + cannot use a tool module through an import + .note = the tool module imported here + resolve_module_only = visibility must resolve to a module diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 19ccb3a6484a..1f2a90829ec7 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -688,8 +688,8 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } // These items live in the value namespace. - ItemKind::Static(_, mt, _) => { - let res = Res::Def(DefKind::Static(mt), def_id); + ItemKind::Static(box ast::StaticItem { mutability, .. }) => { + let res = Res::Def(DefKind::Static(mutability), def_id); self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); } ItemKind::Const(..) => { @@ -931,7 +931,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { /// Builds the reduced graph for a single item in an external crate. fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) { let parent = self.parent_scope.module; - let ModChild { ident, res, vis, span, macro_rules } = child; + let ModChild { ident, res, vis, span, macro_rules, .. } = child; let res = res.expect_non_local(); let expansion = self.parent_scope.expansion; // Record primary definitions. diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index dbf6cec788b5..ae3fd0ede6cf 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -393,7 +393,7 @@ impl Resolver<'_, '_> { // If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]` // attribute; however, if not, suggest adding the attribute. There is no way to // retrieve attributes here because we do not have a `TyCtxt` yet. - let test_module_span = if tcx.sess.opts.test { + let test_module_span = if tcx.sess.is_test_crate() { None } else { let parent_module = visitor.r.get_nearest_non_block_module( diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e69a9d0aecaf..0c9d306081eb 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1607,7 +1607,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut err = struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident); err.span_label(ident.span, &format!("private {}", descr)); - if let Some(span) = ctor_fields_span { + + let mut non_exhaustive = None; + // If an ADT is foreign and marked as `non_exhaustive`, then that's + // probably why we have the privacy error. + // Otherwise, point out if the struct has any private fields. + if let Some(def_id) = res.opt_def_id() + && !def_id.is_local() + && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive) + { + non_exhaustive = Some(attr.span); + } else if let Some(span) = ctor_fields_span { err.span_label(span, "a constructor is private if any of the fields is private"); if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) { err.multipart_suggestion_verbose( @@ -1656,6 +1666,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !first && binding.vis.is_public() { note_span.push_span_label(def_span, "consider importing it directly"); } + // Final step in the import chain, point out if the ADT is `non_exhaustive` + // which is probably why this privacy violation occurred. + if next_binding.is_none() && let Some(span) = non_exhaustive { + note_span.push_span_label( + span, + format!("cannot be constructed because it is `#[non_exhaustive]`"), + ); + } err.span_note(note_span, &msg); } diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 3673f603d167..bed579f6b925 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -155,10 +155,6 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { } } - fn cheap_private_vis(&self, parent_id: ParentId<'_>) -> Option { - matches!(parent_id, ParentId::Def(_)).then_some(self.current_private_vis) - } - fn effective_vis_or_private(&mut self, parent_id: ParentId<'a>) -> EffectiveVisibility { // Private nodes are only added to the table for caching, they could be added or removed at // any moment without consequences, so we don't set `changed` to true when adding them. @@ -172,15 +168,39 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { } } + /// All effective visibilities for a node are larger or equal than private visibility + /// for that node (see `check_invariants` in middle/privacy.rs). + /// So if either parent or nominal visibility is the same as private visibility, then + /// `min(parent_vis, nominal_vis) <= private_vis`, and the update logic is guaranteed + /// to not update anything and we can skip it. + /// + /// We are checking this condition only if the correct value of private visibility is + /// cheaply available, otherwise it does't make sense performance-wise. + /// + /// `None` is returned if the update can be skipped, + /// and cheap private visibility is returned otherwise. + fn may_update( + &self, + nominal_vis: Visibility, + parent_id: ParentId<'_>, + ) -> Option> { + match parent_id { + ParentId::Def(def_id) => (nominal_vis != self.current_private_vis + && self.r.visibilities[&def_id] != self.current_private_vis) + .then_some(Some(self.current_private_vis)), + ParentId::Import(_) => Some(None), + } + } + fn update_import(&mut self, binding: ImportId<'a>, parent_id: ParentId<'a>) { let nominal_vis = binding.vis.expect_local(); - let private_vis = self.cheap_private_vis(parent_id); + let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); let tcx = self.r.tcx; self.changed |= self.import_effective_visibilities.update( binding, nominal_vis, - || private_vis.unwrap_or_else(|| self.r.private_vis_import(binding)), + || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_import(binding)), inherited_eff_vis, parent_id.level(), tcx, @@ -188,13 +208,13 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { } fn update_def(&mut self, def_id: LocalDefId, nominal_vis: Visibility, parent_id: ParentId<'a>) { - let private_vis = self.cheap_private_vis(parent_id); + let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); let tcx = self.r.tcx; self.changed |= self.def_effective_visibilities.update( def_id, nominal_vis, - || private_vis.unwrap_or_else(|| self.r.private_vis_def(def_id)), + || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_def(def_id)), inherited_eff_vis, parent_id.level(), tcx, diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 867363f4246a..07aaaa1eb7f6 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -469,6 +469,15 @@ pub(crate) struct ExpectedFound { #[diag(resolve_indeterminate, code = "E0578")] pub(crate) struct Indeterminate(#[primary_span] pub(crate) Span); +#[derive(Diagnostic)] +#[diag(resolve_tool_module_imported)] +pub(crate) struct ToolModuleImported { + #[primary_span] + pub(crate) span: Span, + #[note] + pub(crate) import: Span, +} + #[derive(Diagnostic)] #[diag(resolve_module_only)] pub(crate) struct ModuleOnly(#[primary_span] pub(crate) Span); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 06206efb9abd..5a56d7b99a97 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -17,7 +17,7 @@ use crate::late::{ ConstantHasGenerics, ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind, }; use crate::macros::{sub_namespace_match, MacroRulesScope}; -use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; +use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; use crate::{Import, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res}; use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak}; @@ -869,17 +869,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let resolution = self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. - if let Some(Finalize { path_span, report_private, .. }) = finalize { - // If the primary binding is unusable, search further and return the shadowed glob - // binding if it exists. What we really want here is having two separate scopes in - // a module - one for non-globs and one for globs, but until that's done use this - // hack to avoid inconsistent resolution ICEs during import validation. - let binding = [resolution.binding, resolution.shadowed_glob].into_iter().find_map( - |binding| match (binding, ignore_binding) { + // If the primary binding is unusable, search further and return the shadowed glob + // binding if it exists. What we really want here is having two separate scopes in + // a module - one for non-globs and one for globs, but until that's done use this + // hack to avoid inconsistent resolution ICEs during import validation. + let binding = + [resolution.binding, resolution.shadowed_glob].into_iter().find_map(|binding| { + match (binding, ignore_binding) { (Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None, _ => binding, - }, - ); + } + }); + + if let Some(Finalize { path_span, report_private, .. }) = finalize { let Some(binding) = binding else { return Err((Determined, Weak::No)); }; @@ -927,15 +929,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| { - if let Some(ignored) = ignore_binding && ptr::eq(binding, ignored) { - return Err((Determined, Weak::No)); - } let usable = this.is_accessible_from(binding.vis, parent_scope.module); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; // Items and single imports are not shadowable, if we have one, then it's determined. - if let Some(binding) = resolution.binding { + if let Some(binding) = binding { if !binding.is_glob_import() { return check_usable(self, binding); } @@ -952,6 +951,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !self.is_accessible_from(import_vis, parent_scope.module) { continue; } + if let Some(ignored) = ignore_binding && + let NameBindingKind::Import { import, .. } = ignored.kind && + ptr::eq(import, &**single_import) { + // Ignore not just the binding itself, but if it has a shadowed_glob, + // ignore that, too, because this loop is supposed to only process + // named imports. + continue; + } let Some(module) = single_import.imported_module.get() else { return Err((Undetermined, Weak::No)); }; @@ -989,7 +996,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted // shadowing is enabled, see `macro_expanded_macro_export_errors`). let unexpanded_macros = !module.unexpanded_invocations.borrow().is_empty(); - if let Some(binding) = resolution.binding { + if let Some(binding) = binding { if !unexpanded_macros || ns == MacroNS || restricted_shadowing { return check_usable(self, binding); } else { @@ -1357,7 +1364,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } }; - let is_last = i == path.len() - 1; + let is_last = i + 1 == path.len(); let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; let name = ident.name; @@ -1494,16 +1501,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(next_module) = binding.module() { module = Some(ModuleOrUniformRoot::Module(next_module)); record_segment_res(self, res); - } else if res == Res::ToolMod && i + 1 != path.len() { + } else if res == Res::ToolMod && !is_last && opt_ns.is_some() { if binding.is_import() { - self.tcx - .sess - .struct_span_err( - ident.span, - "cannot use a tool module through an import", - ) - .span_note(binding.span, "the tool module imported here") - .emit(); + self.tcx.sess.emit_err(errors::ToolModuleImported { + span: ident.span, + import: binding.span, + }); } let res = Res::NonMacroAttr(NonMacroAttrKind::Tool); return PathResult::NonModule(PartialRes::new(res)); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index bc17ce571a7c..77bfcb659de1 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -17,6 +17,7 @@ use rustc_data_structures::intern::Interned; use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_middle::metadata::ModChild; +use rustc_middle::metadata::Reexport; use rustc_middle::span_bug; use rustc_middle::ty; use rustc_session::lint::builtin::{ @@ -27,6 +28,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::LocalExpnId; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; +use smallvec::SmallVec; use std::cell::Cell; use std::{mem, ptr}; @@ -190,6 +192,17 @@ impl<'a> Import<'a> { ImportKind::MacroUse | ImportKind::MacroExport => None, } } + + fn simplify(&self, r: &Resolver<'_, '_>) -> Reexport { + let to_def_id = |id| r.local_def_id(id).to_def_id(); + match self.kind { + ImportKind::Single { id, .. } => Reexport::Single(to_def_id(id)), + ImportKind::Glob { id, .. } => Reexport::Glob(to_def_id(id)), + ImportKind::ExternCrate { id, .. } => Reexport::ExternCrate(to_def_id(id)), + ImportKind::MacroUse => Reexport::MacroUse, + ImportKind::MacroExport => Reexport::MacroExport, + } + } } /// Records information about the resolution of a name in a namespace of a module. @@ -1252,12 +1265,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { module.for_each_child(self, |this, ident, _, binding| { if let Some(res) = this.is_reexport(binding) { + let mut reexport_chain = SmallVec::new(); + let mut next_binding = binding; + while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { + reexport_chain.push(import.simplify(this)); + next_binding = binding; + } + reexports.push(ModChild { ident, res, vis: binding.vis, span: binding.span, macro_rules: false, + reexport_chain, }); } }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b82b07bcf0cc..31ac3f1c151e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -122,6 +122,12 @@ pub(crate) enum ConstantItemKind { Static, } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum RecordPartialRes { + Yes, + No, +} + /// The rib kind restricts certain accesses, /// e.g. to a `Res::Local` of an outer item. #[derive(Copy, Clone, Debug)] @@ -1218,7 +1224,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { lifetime_ribs: Vec::new(), lifetime_elision_candidates: None, current_trait_ref: None, - diagnostic_metadata: Box::new(DiagnosticMetadata::default()), + diagnostic_metadata: Default::default(), // errors at module scope should always be reported in_func_body: false, lifetime_uses: Default::default(), @@ -2346,7 +2352,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { }); } - ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => { + ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) + | ItemKind::Const(box ast::ConstItem { ref ty, ref expr, .. }) => { self.with_static_rib(|this| { this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { this.visit_ty(ty); @@ -2624,11 +2631,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { for item in trait_items { self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); match &item.kind { - AssocItemKind::Const(_, ty, default) => { + AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => { self.visit_ty(ty); // Only impose the restrictions of `ConstRibKind` for an // actual constant expression in a provided default. - if let Some(expr) = default { + if let Some(expr) = expr { // We allow arbitrary const expressions inside of associated consts, // even if they are potentially not const evaluatable. // @@ -2681,6 +2688,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { &path, PathSource::Trait(AliasPossibility::No), Finalize::new(trait_ref.ref_id, trait_ref.path.span), + RecordPartialRes::Yes, ); self.diagnostic_metadata.currently_processing_impl_trait = None; if let Some(def_id) = res.expect_full_res().opt_def_id() { @@ -2799,7 +2807,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { use crate::ResolutionError::*; self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis))); match &item.kind { - AssocItemKind::Const(_, ty, default) => { + AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => { debug!("resolve_implementation AssocItemKind::Const"); // If this is a trait impl, ensure the const // exists in trait @@ -2814,7 +2822,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ); self.visit_ty(ty); - if let Some(expr) = default { + if let Some(expr) = expr { // We allow arbitrary const expressions inside of associated consts, // even if they are potentially not const evaluatable. // @@ -3419,6 +3427,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { &Segment::from_path(path), source, Finalize::new(id, path.span), + RecordPartialRes::Yes, ); } @@ -3429,6 +3438,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { path: &[Segment], source: PathSource<'ast>, finalize: Finalize, + record_partial_res: RecordPartialRes, ) -> PartialRes { let ns = source.namespace(); @@ -3457,8 +3467,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { sugg.to_string(), Applicability::MaybeIncorrect, )) - } else if res.is_none() && matches!(source, PathSource::Type) { - this.report_missing_type_error(path) + } else if res.is_none() && let PathSource::Type | PathSource::Expr(_) = source { + this.suggest_adding_generic_parameter(path, source) } else { None }; @@ -3635,7 +3645,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { _ => report_errors(self, None), }; - if !matches!(source, PathSource::TraitItem(..)) { + if record_partial_res == RecordPartialRes::Yes { // Avoid recording definition of `A::B` in `::B::C`. self.r.record_partial_res(node_id, partial_res); self.resolve_elided_lifetimes_in_path(node_id, partial_res, path, source, path_span); @@ -3739,7 +3749,25 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ))); } - // Make sure `A::B` in `::C` is a trait item. + let num_privacy_errors = self.r.privacy_errors.len(); + // Make sure that `A` in `::B::C` is a trait. + let trait_res = self.smart_resolve_path_fragment( + &None, + &path[..qself.position], + PathSource::Trait(AliasPossibility::No), + Finalize::new(finalize.node_id, qself.path_span), + RecordPartialRes::No, + ); + + if trait_res.expect_full_res() == Res::Err { + return Ok(Some(trait_res)); + } + + // Truncate additional privacy errors reported above, + // because they'll be recomputed below. + self.r.privacy_errors.truncate(num_privacy_errors); + + // Make sure `A::B` in `::B::C` is a trait item. // // Currently, `path` names the full item (`A::B::C`, in // our example). so we extract the prefix of that that is @@ -3752,6 +3780,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { &path[..=qself.position], PathSource::TraitItem(ns), Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span), + RecordPartialRes::No, ); // The remaining segments (the `C` in our example) will diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index df7681dc4267..37fbfad2de63 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2110,9 +2110,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } - pub(crate) fn report_missing_type_error( + pub(crate) fn suggest_adding_generic_parameter( &self, path: &[Segment], + source: PathSource<'_>, ) -> Option<(Span, &'static str, String, Applicability)> { let (ident, span) = match path { [segment] @@ -2148,7 +2149,6 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // Without the 2nd `true`, we'd suggest `impl ` for `impl T` when a type `T` isn't found | (Some(Item { kind: kind @ ItemKind::Impl(..), .. }), true, true) | (Some(Item { kind, .. }), false, _) => { - // Likely missing type parameter. if let Some(generics) = kind.generics() { if span.overlaps(generics.span) { // Avoid the following: @@ -2161,7 +2161,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // | not found in this scope return None; } - let msg = "you might be missing a type parameter"; + + let (msg, sugg) = match source { + PathSource::Type => ("you might be missing a type parameter", ident), + PathSource::Expr(_) => ("you might be missing a const parameter", format!("const {ident}: /* Type */")), + _ => return None, + }; let (span, sugg) = if let [.., param] = &generics.params[..] { let span = if let [.., bound] = ¶m.bounds[..] { bound.span() @@ -2172,9 +2177,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } else { param.ident.span }; - (span, format!(", {}", ident)) + (span, format!(", {sugg}")) } else { - (generics.span, format!("<{}>", ident)) + (generics.span, format!("<{sugg}>")) }; // Do not suggest if this is coming from macro expansion. if span.can_be_used_for_suggestions() { diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 0e0ebc79eb2e..53e5c8967365 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -122,18 +122,6 @@ impl Encoder for MemEncoder { self.emit_u8(if v { 1 } else { 0 }); } - #[inline] - fn emit_f64(&mut self, v: f64) { - let as_u64: u64 = v.to_bits(); - self.emit_u64(as_u64); - } - - #[inline] - fn emit_f32(&mut self, v: f32) { - let as_u32: u32 = v.to_bits(); - self.emit_u32(as_u32); - } - #[inline] fn emit_char(&mut self, v: char) { self.emit_u32(v as u32); @@ -500,18 +488,6 @@ impl Encoder for FileEncoder { self.emit_u8(if v { 1 } else { 0 }); } - #[inline] - fn emit_f64(&mut self, v: f64) { - let as_u64: u64 = v.to_bits(); - self.emit_u64(as_u64); - } - - #[inline] - fn emit_f32(&mut self, v: f32) { - let as_u32: u32 = v.to_bits(); - self.emit_u32(as_u32); - } - #[inline] fn emit_char(&mut self, v: char) { self.emit_u32(v as u32); @@ -642,18 +618,6 @@ impl<'a> Decoder for MemDecoder<'a> { value != 0 } - #[inline] - fn read_f64(&mut self) -> f64 { - let bits = self.read_u64(); - f64::from_bits(bits) - } - - #[inline] - fn read_f32(&mut self) -> f32 { - let bits = self.read_u32(); - f32::from_bits(bits) - } - #[inline] fn read_char(&mut self) -> char { let bits = self.read_u32(); diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index 567fe06109b7..527abc237271 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -22,6 +22,11 @@ use std::sync::Arc; /// be processed or ignored, whichever is appropriate. Then they should provide /// a `finish` method that finishes up encoding. If the encoder is fallible, /// `finish` should return a `Result` that indicates success or failure. +/// +/// This current does not support `f32` nor `f64`, as they're not needed in any +/// serialized data structures. That could be changed, but consider whether it +/// really makes sense to store floating-point values at all. +/// (If you need it, revert .) pub trait Encoder { // Primitive types: fn emit_usize(&mut self, v: usize); @@ -37,8 +42,6 @@ pub trait Encoder { fn emit_i16(&mut self, v: i16); fn emit_i8(&mut self, v: i8); fn emit_bool(&mut self, v: bool); - fn emit_f64(&mut self, v: f64); - fn emit_f32(&mut self, v: f32); fn emit_char(&mut self, v: char); fn emit_str(&mut self, v: &str); fn emit_raw_bytes(&mut self, s: &[u8]); @@ -58,6 +61,11 @@ pub trait Encoder { // top-level invocation would also just panic on failure. Switching to // infallibility made things faster and lots of code a little simpler and more // concise. +/// +/// This current does not support `f32` nor `f64`, as they're not needed in any +/// serialized data structures. That could be changed, but consider whether it +/// really makes sense to store floating-point values at all. +/// (If you need it, revert .) pub trait Decoder { // Primitive types: fn read_usize(&mut self) -> usize; @@ -73,8 +81,6 @@ pub trait Decoder { fn read_i16(&mut self) -> i16; fn read_i8(&mut self) -> i8; fn read_bool(&mut self) -> bool; - fn read_f64(&mut self) -> f64; - fn read_f32(&mut self) -> f32; fn read_char(&mut self) -> char; fn read_str(&mut self) -> &str; fn read_raw_bytes(&mut self, len: usize) -> &[u8]; @@ -143,8 +149,6 @@ direct_serialize_impls! { i64 emit_i64 read_i64, i128 emit_i128 read_i128, - f32 emit_f32 read_f32, - f64 emit_f64 read_f64, bool emit_bool read_bool, char emit_char read_char } diff --git a/compiler/rustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs index 3a695d0714ee..5e7dd18aa840 100644 --- a/compiler/rustc_serialize/tests/opaque.rs +++ b/compiler/rustc_serialize/tests/opaque.rs @@ -22,8 +22,6 @@ struct Struct { l: char, m: String, - n: f32, - o: f64, p: bool, q: Option, } @@ -119,24 +117,6 @@ fn test_bool() { check_round_trip(vec![false, true, true, false, false]); } -#[test] -fn test_f32() { - let mut vec = vec![]; - for i in -100..100 { - vec.push((i as f32) / 3.0); - } - check_round_trip(vec); -} - -#[test] -fn test_f64() { - let mut vec = vec![]; - for i in -100..100 { - vec.push((i as f64) / 3.0); - } - check_round_trip(vec); -} - #[test] fn test_char() { let vec = vec!['a', 'b', 'c', 'd', 'A', 'X', ' ', '#', 'Ö', 'Ä', 'µ', '€']; @@ -200,8 +180,6 @@ fn test_struct() { l: 'x', m: "abc".to_string(), - n: 20.5, - o: 21.5, p: false, q: None, }]); @@ -222,8 +200,6 @@ fn test_struct() { l: 'y', m: "def".to_string(), - n: -20.5, - o: -21.5, p: true, q: Some(1234567), }]); @@ -232,7 +208,7 @@ fn test_struct() { #[derive(PartialEq, Clone, Debug, Encodable, Decodable)] enum Enum { Variant1, - Variant2(usize, f32), + Variant2(usize, u32), Variant3 { a: i32, b: char, c: bool }, } @@ -240,7 +216,7 @@ enum Enum { fn test_enum() { check_round_trip(vec![ Enum::Variant1, - Enum::Variant2(1, 2.5), + Enum::Variant2(1, 25), Enum::Variant3 { a: 3, b: 'b', c: false }, Enum::Variant3 { a: -4, b: 'f', c: true }, ]); @@ -269,8 +245,8 @@ fn test_hash_map() { #[test] fn test_tuples() { - check_round_trip(vec![('x', (), false, 0.5f32)]); - check_round_trip(vec![(9i8, 10u16, 1.5f64)]); + check_round_trip(vec![('x', (), false, 5u32)]); + check_round_trip(vec![(9i8, 10u16, 15i64)]); check_round_trip(vec![(-12i16, 11u8, 12usize)]); check_round_trip(vec![(1234567isize, 100000000000000u64, 99999999999999i64)]); check_round_trip(vec![(String::new(), "some string".to_string())]); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 485c3f554625..acfb36c97d0c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -260,6 +260,8 @@ pub enum SymbolManglingVersion { #[derive(Clone, Copy, Debug, PartialEq, Hash)] pub enum DebugInfo { None, + LineDirectivesOnly, + LineTablesOnly, Limited, Full, } @@ -580,6 +582,7 @@ pub enum PrintRequest { CodeModels, TlsModels, TargetSpec, + AllTargetSpecs, NativeStaticLibs, StackProtectorStrategies, LinkArgs, @@ -1255,7 +1258,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo // some default and generated configuration items. let default_cfg = default_configuration(sess); // If the user wants a test runner, then add the test cfg. - if sess.opts.test { + if sess.is_test_crate() { user_cfg.insert((sym::test, None)); } user_cfg.extend(default_cfg.iter().cloned()); @@ -1423,7 +1426,7 @@ pub fn rustc_short_optgroups() -> Vec { opt::opt_s( "", "edition", - &*EDITION_STRING, + &EDITION_STRING, EDITION_NAME_LIST, ), opt::multi_s( @@ -1439,8 +1442,8 @@ pub fn rustc_short_optgroups() -> Vec { "Compiler information to print on stdout", "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\ target-list|target-cpus|target-features|relocation-models|code-models|\ - tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\ - link-args]", + tls-models|target-spec-json|all-target-specs-json|native-static-libs|\ + stack-protector-strategies|link-args]", ), opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"), opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"), @@ -1887,6 +1890,7 @@ fn collect_print_requests( ("native-static-libs", PrintRequest::NativeStaticLibs), ("stack-protector-strategies", PrintRequest::StackProtectorStrategies), ("target-spec-json", PrintRequest::TargetSpec), + ("all-target-specs-json", PrintRequest::AllTargetSpecs), ("link-args", PrintRequest::LinkArgs), ("split-debuginfo", PrintRequest::SplitDebuginfo), ]; @@ -1900,7 +1904,18 @@ fn collect_print_requests( early_error( error_format, "the `-Z unstable-options` flag must also be passed to \ - enable the target-spec-json print option", + enable the target-spec-json print option", + ); + } + } + Some((_, PrintRequest::AllTargetSpecs)) => { + if unstable_opts.unstable_options { + PrintRequest::AllTargetSpecs + } else { + early_error( + error_format, + "the `-Z unstable-options` flag must also be passed to \ + enable the all-target-specs-json print option", ); } } @@ -1979,11 +1994,7 @@ fn parse_opt_level( } } -fn select_debuginfo( - matches: &getopts::Matches, - cg: &CodegenOptions, - error_format: ErrorOutputType, -) -> DebugInfo { +fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInfo { let max_g = matches.opt_positions("g").into_iter().max(); let max_c = matches .opt_strs_pos("C") @@ -1993,24 +2004,7 @@ fn select_debuginfo( if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None } }) .max(); - if max_g > max_c { - DebugInfo::Full - } else { - match cg.debuginfo { - 0 => DebugInfo::None, - 1 => DebugInfo::Limited, - 2 => DebugInfo::Full, - arg => { - early_error( - error_format, - &format!( - "debug info level needs to be between \ - 0-2 (instead was `{arg}`)" - ), - ); - } - } - } + if max_g > max_c { DebugInfo::Full } else { cg.debuginfo } } pub(crate) fn parse_assert_incr_state( @@ -2498,7 +2492,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`) // for more details. let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No); - let debuginfo = select_debuginfo(matches, &cg, error_format); + let debuginfo = select_debuginfo(matches, &cg); let mut search_paths = vec![]; for s in &matches.opt_strs("L") { diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index a262c06d91f0..dd1721801f37 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -6,7 +6,7 @@ use crate::search_paths::PathKind; use crate::utils::NativeLibKind; use crate::Session; use rustc_ast as ast; -use rustc_data_structures::sync::{self, AppendOnlyVec, MetadataRef, RwLock}; +use rustc_data_structures::sync::{self, AppendOnlyIndexVec, MetadataRef, RwLock}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; use rustc_span::hygiene::{ExpnHash, ExpnId}; @@ -257,6 +257,6 @@ pub type CrateStoreDyn = dyn CrateStore + sync::Sync + sync::Send; pub struct Untracked { pub cstore: RwLock>, /// Reference span for definitions. - pub source_span: AppendOnlyVec, + pub source_span: AppendOnlyIndexVec, pub definitions: RwLock, } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index be5d4fca7a00..631dd0a2146e 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -377,6 +377,7 @@ mod desc { pub const parse_cfguard: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)"; + pub const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`"; pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; @@ -767,6 +768,18 @@ mod parse { true } + pub(crate) fn parse_debuginfo(slot: &mut DebugInfo, v: Option<&str>) -> bool { + match v { + Some("0") | Some("none") => *slot = DebugInfo::None, + Some("line-directives-only") => *slot = DebugInfo::LineDirectivesOnly, + Some("line-tables-only") => *slot = DebugInfo::LineTablesOnly, + Some("1") | Some("limited") => *slot = DebugInfo::Limited, + Some("2") | Some("full") => *slot = DebugInfo::Full, + _ => return false, + } + true + } + pub(crate) fn parse_linker_flavor(slot: &mut Option, v: Option<&str>) -> bool { match v.and_then(LinkerFlavorCli::from_str) { Some(lf) => *slot = Some(lf), @@ -1217,9 +1230,9 @@ options! { "use Windows Control Flow Guard (default: no)"), debug_assertions: Option = (None, parse_opt_bool, [TRACKED], "explicitly enable the `cfg(debug_assertions)` directive"), - debuginfo: usize = (0, parse_number, [TRACKED], - "debug info emission level (0 = no debug info, 1 = line tables only, \ - 2 = full debug info with variable and type information; default: 0)"), + debuginfo: DebugInfo = (DebugInfo::None, parse_debuginfo, [TRACKED], + "debug info emission level (0-2, none, line-directives-only, \ + line-tables-only, limited, or full; default: 0)"), default_linker_libraries: bool = (false, parse_bool, [UNTRACKED], "allow the linker to link its default libraries (default: no)"), embed_bitcode: bool = (true, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 4e8c3f73e29c..15e27952cf50 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -8,7 +8,7 @@ use crate::lint::{ }; use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_data_structures::sync::{Lock, Lrc}; +use rustc_data_structures::sync::{AppendOnlyVec, AtomicBool, Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{ fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, @@ -84,12 +84,12 @@ impl SymbolGallery { /// Construct a diagnostic for a language feature error due to the given `span`. /// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`. -pub fn feature_err<'a>( - sess: &'a ParseSess, +pub fn feature_err( + sess: &ParseSess, feature: Symbol, span: impl Into, explain: impl Into, -) -> DiagnosticBuilder<'a, ErrorGuaranteed> { +) -> DiagnosticBuilder<'_, ErrorGuaranteed> { feature_err_issue(sess, feature, span, GateIssue::Language, explain) } @@ -98,20 +98,21 @@ pub fn feature_err<'a>( /// This variant allows you to control whether it is a library or language feature. /// Almost always, you want to use this for a language feature. If so, prefer `feature_err`. #[track_caller] -pub fn feature_err_issue<'a>( - sess: &'a ParseSess, +pub fn feature_err_issue( + sess: &ParseSess, feature: Symbol, span: impl Into, issue: GateIssue, explain: impl Into, -) -> DiagnosticBuilder<'a, ErrorGuaranteed> { +) -> DiagnosticBuilder<'_, ErrorGuaranteed> { let span = span.into(); // Cancel an earlier warning for this same error, if it exists. if let Some(span) = span.primary_span() { - sess.span_diagnostic - .steal_diagnostic(span, StashKey::EarlySyntaxWarning) - .map(|err| err.cancel()); + if let Some(err) = sess.span_diagnostic.steal_diagnostic(span, StashKey::EarlySyntaxWarning) + { + err.cancel() + } } let mut err = sess.create_err(FeatureGateError { span, explain: explain.into() }); @@ -194,7 +195,7 @@ pub struct ParseSess { pub edition: Edition, /// Places where raw identifiers were used. This is used to avoid complaining about idents /// clashing with keywords in new editions. - pub raw_identifier_spans: Lock>, + pub raw_identifier_spans: AppendOnlyVec, /// Places where identifiers that contain invalid Unicode codepoints but that look like they /// should be. Useful to avoid bad tokenization when encountering emoji. We group them to /// provide a single error per unique incorrect identifier. @@ -208,7 +209,7 @@ pub struct ParseSess { pub gated_spans: GatedSpans, pub symbol_gallery: SymbolGallery, /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors. - pub reached_eof: Lock, + pub reached_eof: AtomicBool, /// Environment variables accessed during the build and their values when they exist. pub env_depinfo: Lock)>>, /// File paths accessed during the build. @@ -219,7 +220,7 @@ pub struct ParseSess { pub assume_incomplete_release: bool, /// Spans passed to `proc_macro::quote_span`. Each span has a numerical /// identifier represented by its position in the vector. - pub proc_macro_quoted_spans: Lock>, + pub proc_macro_quoted_spans: AppendOnlyVec, /// Used to generate new `AttrId`s. Every `AttrId` is unique. pub attr_id_generator: AttrIdGenerator, } @@ -247,14 +248,14 @@ impl ParseSess { config: FxIndexSet::default(), check_config: CrateCheckConfig::default(), edition: ExpnId::root().expn_data().edition, - raw_identifier_spans: Lock::new(Vec::new()), + raw_identifier_spans: Default::default(), bad_unicode_identifiers: Lock::new(Default::default()), source_map, buffered_lints: Lock::new(vec![]), ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), gated_spans: GatedSpans::default(), symbol_gallery: SymbolGallery::default(), - reached_eof: Lock::new(false), + reached_eof: AtomicBool::new(false), env_depinfo: Default::default(), file_depinfo: Default::default(), type_ascription_path_suggestions: Default::default(), @@ -324,13 +325,13 @@ impl ParseSess { } pub fn save_proc_macro_span(&self, span: Span) -> usize { - let mut spans = self.proc_macro_quoted_spans.lock(); - spans.push(span); - return spans.len() - 1; + self.proc_macro_quoted_spans.push(span) } - pub fn proc_macro_quoted_spans(&self) -> Vec { - self.proc_macro_quoted_spans.lock().clone() + pub fn proc_macro_quoted_spans(&self) -> impl Iterator + '_ { + // This is equivalent to `.iter().copied().enumerate()`, but that isn't possible for + // AppendOnlyVec, so we resort to this scheme. + self.proc_macro_quoted_spans.iter_enumerated() } #[track_caller] diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 5730df9d5c6b..340bb158e179 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -294,6 +294,11 @@ impl Session { self.crate_types.get().unwrap().as_slice() } + /// Returns true if the crate is a testing one. + pub fn is_test_crate(&self) -> bool { + self.opts.test + } + pub fn needs_crate_hash(&self) -> bool { // Why is the crate hash needed for these configurations? // - debug_assertions: for the "fingerprint the result" check in diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 86e30dd0f6a2..0befff894ef3 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -143,7 +143,7 @@ fn rustc_terminator_to_terminator( otherwise: targets.otherwise().as_usize(), }, Resume => Terminator::Resume, - Abort => Terminator::Abort, + Terminate => Terminator::Abort, Return => Terminator::Return, Unreachable => Terminator::Unreachable, Drop { .. } => todo!(), diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 89f0386e3e97..9fe9e3a7a5fd 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -174,10 +174,10 @@ pub fn find_best_match_for_name( fn find_best_match_for_name_impl( use_substring_score: bool, candidates: &[Symbol], - lookup: Symbol, + lookup_symbol: Symbol, dist: Option, ) -> Option { - let lookup = lookup.as_str(); + let lookup = lookup_symbol.as_str(); let lookup_uppercase = lookup.to_uppercase(); // Priority of matches: @@ -190,6 +190,8 @@ fn find_best_match_for_name_impl( let mut dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3); let mut best = None; + // store the candidates with the same distance, only for `use_substring_score` current. + let mut next_candidates = vec![]; for c in candidates { match if use_substring_score { edit_distance_with_substrings(lookup, c.as_str(), dist) @@ -198,12 +200,36 @@ fn find_best_match_for_name_impl( } { Some(0) => return Some(*c), Some(d) => { - dist = d - 1; + if use_substring_score { + if d < dist { + dist = d; + next_candidates.clear(); + } else { + // `d == dist` here, we need to store the candidates with the same distance + // so we won't decrease the distance in the next loop. + } + next_candidates.push(*c); + } else { + dist = d - 1; + } best = Some(*c); } None => {} } } + + // We have a tie among several candidates, try to select the best among them ignoring substrings. + // For example, the candidates list `force_capture`, `capture`, and user inputed `forced_capture`, + // we select `force_capture` with a extra round of edit distance calculation. + if next_candidates.len() > 1 { + debug_assert!(use_substring_score); + best = find_best_match_for_name_impl( + false, + &next_candidates, + lookup_symbol, + Some(lookup.len()), + ); + } if best.is_some() { return best; } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index e14760aa0188..aa8859ed1a35 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1318,7 +1318,6 @@ pub struct SourceFileDiffs { } /// A single source in the [`SourceMap`]. -#[derive(Clone)] pub struct SourceFile { /// The name of the file that the source came from. Source that doesn't /// originate from files has names between angle brackets by convention @@ -1349,6 +1348,25 @@ pub struct SourceFile { pub cnum: CrateNum, } +impl Clone for SourceFile { + fn clone(&self) -> Self { + Self { + name: self.name.clone(), + src: self.src.clone(), + src_hash: self.src_hash, + external_src: Lock::new(self.external_src.borrow().clone()), + start_pos: self.start_pos, + end_pos: self.end_pos, + lines: Lock::new(self.lines.borrow().clone()), + multibyte_chars: self.multibyte_chars.clone(), + non_narrow_chars: self.non_narrow_chars.clone(), + normalized_pos: self.normalized_pos.clone(), + name_hash: self.name_hash, + cnum: self.cnum, + } + } +} + impl Encodable for SourceFile { fn encode(&self, s: &mut S) { self.name.encode(s); @@ -2033,13 +2051,13 @@ pub type FileLinesResult = Result; #[derive(Clone, PartialEq, Eq, Debug)] pub enum SpanLinesError { - DistinctSources(DistinctSources), + DistinctSources(Box), } #[derive(Clone, PartialEq, Eq, Debug)] pub enum SpanSnippetError { IllFormedSpan(Span), - DistinctSources(DistinctSources), + DistinctSources(Box), MalformedForSourcemap(MalformedSourceMapPositions), SourceNotAvailable { filename: FileName }, } diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index ee895f53eba9..88e3674f8994 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -542,10 +542,10 @@ impl SourceMap { let hi = self.lookup_char_pos(sp.hi()); trace!(?hi); if lo.file.start_pos != hi.file.start_pos { - return Err(SpanLinesError::DistinctSources(DistinctSources { + return Err(SpanLinesError::DistinctSources(Box::new(DistinctSources { begin: (lo.file.name.clone(), lo.file.start_pos), end: (hi.file.name.clone(), hi.file.start_pos), - })); + }))); } Ok((lo, hi)) } @@ -603,10 +603,10 @@ impl SourceMap { let local_end = self.lookup_byte_offset(sp.hi()); if local_begin.sf.start_pos != local_end.sf.start_pos { - Err(SpanSnippetError::DistinctSources(DistinctSources { + Err(SpanSnippetError::DistinctSources(Box::new(DistinctSources { begin: (local_begin.sf.name.clone(), local_begin.sf.start_pos), end: (local_end.sf.name.clone(), local_end.sf.start_pos), - })) + }))) } else { self.ensure_source_file_source_present(local_begin.sf.clone()); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0e55e81143de..7affad9aa017 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1496,6 +1496,7 @@ symbols! { trait_alias, trait_upcasting, transmute, + transmute_generic_consts, transmute_opts, transmute_trait, transparent, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index cac7ff72267d..ee883285531d 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -1,5 +1,5 @@ use rustc_data_structures::base_n; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; use rustc_hir as hir; use rustc_hir::def::CtorKind; @@ -81,9 +81,9 @@ pub(super) fn mangle_typeid_for_trait_ref<'tcx>( struct BinderLevel { /// The range of distances from the root of what's /// being printed, to the lifetimes in a binder. - /// Specifically, a `BrAnon(i)` lifetime has depth - /// `lifetime_depths.start + i`, going away from the - /// the root and towards its use site, as `i` increases. + /// Specifically, a `BrAnon` lifetime has depth + /// `lifetime_depths.start + index`, going away from the + /// the root and towards its use site, as the var index increases. /// This is used to flatten rustc's pairing of `BrAnon` /// (intra-binder disambiguation) with a `DebruijnIndex` /// (binder addressing), to "true" de Bruijn indices, @@ -208,24 +208,15 @@ impl<'tcx> SymbolMangler<'tcx> { where T: TypeVisitable>, { - // FIXME(non-lifetime-binders): What to do here? - let regions = if value.has_late_bound_regions() { - self.tcx.collect_referenced_late_bound_regions(value) - } else { - FxHashSet::default() - }; - let mut lifetime_depths = self.binders.last().map(|b| b.lifetime_depths.end).map_or(0..0, |i| i..i); - let lifetimes = regions - .into_iter() - .map(|br| match br { - ty::BrAnon(i, _) => i, - _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value), - }) - .max() - .map_or(0, |max| max + 1); + // FIXME(non-lifetime-binders): What to do here? + let lifetimes = value + .bound_vars() + .iter() + .filter(|var| matches!(var, ty::BoundVariableKind::Region(..))) + .count() as u32; self.push_opt_integer_62("G", lifetimes as u64); lifetime_depths.end += lifetimes; @@ -338,9 +329,9 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { // Late-bound lifetimes use indices starting at 1, // see `BinderLevel` for more details. - ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i, _), .. }) => { + ty::ReLateBound(debruijn, ty::BoundRegion { var, kind: ty::BrAnon(_) }) => { let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; - let depth = binder.lifetime_depths.start + i; + let depth = binder.lifetime_depths.start + var.as_u32(); 1 + (self.binders.last().unwrap().lifetime_depths.end - 1 - depth) } diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_ohos.rs index 0a5e654cf0d0..bf1b089f657b 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_ohos.rs @@ -18,6 +18,7 @@ pub fn target() -> Target { features: "+reserve-x18".into(), mcount: "\u{1}_mcount".into(), force_emulated_tls: true, + has_thread_local: false, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_nto_qnx_710.rs b/compiler/rustc_target/src/spec/aarch64_unknown_nto_qnx_710.rs index 8c1126ae6d1c..630642dcd33a 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_nto_qnx_710.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_nto_qnx_710.rs @@ -23,6 +23,7 @@ pub fn target() -> Target { LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Vgcc_ntoaarch64le_cxx"], ), + env: "nto71".into(), ..nto_qnx_base::opts() }, } diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs index d4f7ed31b895..5582d909f6b1 100644 --- a/compiler/rustc_target/src/spec/abi.rs +++ b/compiler/rustc_target/src/spec/abi.rs @@ -324,8 +324,6 @@ impl Abi { impl fmt::Display for Abi { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - abi => write!(f, "\"{}\"", abi.name()), - } + write!(f, "\"{}\"", self.name()) } } diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_ohos.rs index a64f3a4f0493..16da24533677 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_ohos.rs @@ -21,6 +21,7 @@ pub fn target() -> Target { crt_static_default: false, mcount: "\u{1}mcount".into(), force_emulated_tls: true, + has_thread_local: false, ..super::linux_musl_base::opts() }, } diff --git a/compiler/rustc_target/src/spec/i586_pc_nto_qnx700.rs b/compiler/rustc_target/src/spec/i586_pc_nto_qnx700.rs new file mode 100644 index 000000000000..68afa7fe4012 --- /dev/null +++ b/compiler/rustc_target/src/spec/i586_pc_nto_qnx700.rs @@ -0,0 +1,24 @@ +use super::nto_qnx_base; +use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "i586-pc-unknown".into(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ + f64:32:64-f80:32-n8:16:32-S128" + .into(), + arch: "x86".into(), + options: TargetOptions { + cpu: "pentium4".into(), + max_atomic_width: Some(64), + pre_link_args: TargetOptions::link_args( + LinkerFlavor::Gnu(Cc::Yes, Lld::No), + &["-Vgcc_ntox86_cxx"], + ), + env: "nto70".into(), + stack_probes: StackProbeType::X86, + ..nto_qnx_base::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index bb45fb125b24..62c58c204e09 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1261,6 +1261,7 @@ supported_targets! { ("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx_710), ("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710), + ("i586-pc-nto-qnx700", i586_pc_nto_qnx700), ("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos), ("armv7-unknown-linux-ohos", armv7_unknown_linux_ohos), diff --git a/compiler/rustc_target/src/spec/nto_qnx_base.rs b/compiler/rustc_target/src/spec/nto_qnx_base.rs index 6fb581ef5ce3..f1405e9b4466 100644 --- a/compiler/rustc_target/src/spec/nto_qnx_base.rs +++ b/compiler/rustc_target/src/spec/nto_qnx_base.rs @@ -4,7 +4,6 @@ pub fn opts() -> TargetOptions { TargetOptions { crt_static_respected: true, dynamic_linking: true, - env: "nto71".into(), executables: true, families: cvs!["unix"], has_rpath: true, diff --git a/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs index e9b3acee2e7f..6fb2dfd807a0 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_nto_qnx710.rs @@ -15,6 +15,7 @@ pub fn target() -> Target { LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Vgcc_ntox86_64_cxx"], ), + env: "nto71".into(), ..nto_qnx_base::opts() }, } diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs similarity index 90% rename from compiler/rustc_trait_selection/src/solve/assembly.rs rename to compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 856b1c08b723..12ee80b6722b 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -1,21 +1,21 @@ //! Code shared by trait and projection goals for candidate assembly. use super::search_graph::OverflowHandler; -#[cfg(doc)] -use super::trait_goals::structural_traits::*; use super::{EvalCtxt, SolverMode}; +use crate::solve::CanonicalResponseExt; use crate::traits::coherence; -use itertools::Itertools; use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::util::elaborate_predicates; +use rustc_infer::traits::util::elaborate; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult}; use rustc_middle::ty::fast_reject::TreatProjections; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use std::fmt::Debug; +pub(super) mod structural_traits; + /// A candidate is a possible way to prove a goal. /// /// It consists of both the `source`, which describes how that goal would be proven, @@ -270,6 +270,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// To deal with this, we first try to normalize the self type and add the candidates for the normalized /// self type to the list of candidates in case that succeeds. We also have to consider candidates with the /// projection as a self type as well + #[instrument(level = "debug", skip_all)] fn assemble_candidates_after_normalizing_self_ty>( &mut self, goal: Goal<'tcx, G>, @@ -315,6 +316,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + #[instrument(level = "debug", skip_all)] fn assemble_impl_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -333,6 +335,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ); } + #[instrument(level = "debug", skip_all)] fn assemble_builtin_impl_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -390,6 +393,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + #[instrument(level = "debug", skip_all)] fn assemble_param_env_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -405,6 +409,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + #[instrument(level = "debug", skip_all)] fn assemble_alias_bound_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -452,6 +457,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + #[instrument(level = "debug", skip_all)] fn assemble_object_bound_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -492,7 +498,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let tcx = self.tcx(); let own_bounds: FxIndexSet<_> = bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)).collect(); - for assumption in elaborate_predicates(tcx, own_bounds.iter().copied()) { + for assumption in elaborate(tcx, own_bounds.iter().copied()) { // FIXME: Predicates are fully elaborated in the object type's existential bounds // list. We want to only consider these pre-elaborated projections, and not other // projection predicates that we reach by elaborating the principal trait ref, @@ -514,6 +520,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + #[instrument(level = "debug", skip_all)] fn assemble_coherence_unknowable_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -540,61 +547,41 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + /// If there are multiple ways to prove a trait or projection goal, we have + /// to somehow try to merge the candidates into one. If that fails, we return + /// ambiguity. #[instrument(level = "debug", skip(self), ret)] pub(super) fn merge_candidates( &mut self, mut candidates: Vec>, ) -> QueryResult<'tcx> { - match candidates.len() { - 0 => return Err(NoSolution), - 1 => return Ok(candidates.pop().unwrap().result), - _ => {} + // First try merging all candidates. This is complete and fully sound. + let responses = candidates.iter().map(|c| c.result).collect::>(); + if let Some(result) = self.try_merge_responses(&responses) { + return Ok(result); } - if candidates.len() > 1 { - let mut i = 0; - 'outer: while i < candidates.len() { - for j in (0..candidates.len()).filter(|&j| i != j) { - if self.candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j]) - { - debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len()); - candidates.swap_remove(i); - continue 'outer; + // We then check whether we should prioritize `ParamEnv` candidates. + // + // Doing so is incomplete and would therefore be unsound during coherence. + match self.solver_mode() { + SolverMode::Coherence => (), + // Prioritize `ParamEnv` candidates only if they do not guide inference. + // + // This is still incomplete as we may add incorrect region bounds. + SolverMode::Normal => { + let param_env_responses = candidates + .iter() + .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) + .map(|c| c.result) + .collect::>(); + if let Some(result) = self.try_merge_responses(¶m_env_responses) { + if result.has_only_region_constraints() { + return Ok(result); } } - - debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len()); - i += 1; - } - - // If there are *STILL* multiple candidates that have *different* response - // results, give up and report ambiguity. - if candidates.len() > 1 && !candidates.iter().map(|cand| cand.result).all_equal() { - let certainty = if candidates.iter().all(|x| { - matches!(x.result.value.certainty, Certainty::Maybe(MaybeCause::Overflow)) - }) { - Certainty::Maybe(MaybeCause::Overflow) - } else { - Certainty::AMBIGUOUS - }; - return self.evaluate_added_goals_and_make_canonical_response(certainty); } } - - Ok(candidates.pop().unwrap().result) - } - - fn candidate_should_be_dropped_in_favor_of( - &self, - candidate: &Candidate<'tcx>, - other: &Candidate<'tcx>, - ) -> bool { - // FIXME: implement this - match (candidate.source, other.source) { - (CandidateSource::Impl(_), _) - | (CandidateSource::ParamEnv(_), _) - | (CandidateSource::AliasBound, _) - | (CandidateSource::BuiltinImpl, _) => false, - } + self.flounder(&responses) } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs similarity index 84% rename from compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs rename to compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index fcb965dd725a..cbec39d82856 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -1,7 +1,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::{def_id::DefId, Movability, Mutability}; use rustc_infer::traits::query::NoSolution; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, +}; use crate::solve::EvalCtxt; @@ -9,7 +11,7 @@ use crate::solve::EvalCtxt; // // For types with an "existential" binder, i.e. generator witnesses, we also // instantiate the binder with placeholders eagerly. -pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( +pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, ) -> Result>, NoSolution> { @@ -60,7 +62,16 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ty::GeneratorWitness(types) => Ok(ecx.instantiate_binder_with_placeholders(types).to_vec()), - ty::GeneratorWitnessMIR(..) => todo!(), + ty::GeneratorWitnessMIR(def_id, substs) => Ok(ecx + .tcx() + .generator_hidden_types(def_id) + .map(|bty| { + ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars( + tcx, + bty.subst(tcx, substs), + )) + }) + .collect()), // For `PhantomData`, we pass `T`. ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]), @@ -76,7 +87,28 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( } } -pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( +pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> ty::Binder<'tcx, Ty<'tcx>> { + debug_assert!(!ty.has_late_bound_regions()); + let mut counter = 0; + let ty = tcx.fold_regions(ty, |mut r, current_depth| { + if let ty::ReErased = r.kind() { + let br = + ty::BoundRegion { var: ty::BoundVar::from_u32(counter), kind: ty::BrAnon(None) }; + counter += 1; + r = tcx.mk_re_late_bound(current_depth, br); + } + r + }); + let bound_vars = tcx.mk_bound_variable_kinds_from_iter( + (0..counter).map(|_| ty::BoundVariableKind::Region(ty::BrAnon(None))), + ); + ty::Binder::bind_with_vars(ty, bound_vars) +} + +pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, ) -> Result>, NoSolution> { @@ -126,7 +158,7 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( } } -pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( +pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, ) -> Result>, NoSolution> { @@ -178,12 +210,21 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::GeneratorWitness(types) => Ok(ecx.instantiate_binder_with_placeholders(types).to_vec()), - ty::GeneratorWitnessMIR(..) => todo!(), + ty::GeneratorWitnessMIR(def_id, substs) => Ok(ecx + .tcx() + .generator_hidden_types(def_id) + .map(|bty| { + ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars( + ecx.tcx(), + bty.subst(ecx.tcx(), substs), + )) + }) + .collect()), } } // Returns a binder of the tupled inputs types and output type from a builtin callable type. -pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( +pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>, goal_kind: ty::ClosureKind, @@ -296,7 +337,13 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( /// additional step of eagerly folding the associated types in the where /// clauses of the impl. In this example, that means replacing /// `::Bar` with `Ty` in the first impl. -pub(crate) fn predicates_for_object_candidate<'tcx>( +/// +// FIXME: This is only necessary as `::Assoc: ItemBound` +// bounds in impls are trivially proven using the item bound candidates. +// This is unsound in general and once that is fixed, we don't need to +// normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9 +// for more details. +pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, trait_ref: ty::TraitRef<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs index 2e5a8b7debc5..55025e2e72b9 100644 --- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs @@ -257,7 +257,7 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { self.primitive_var_infos.push(CanonicalVarInfo { kind }); var }); - let br = ty::BoundRegion { var, kind: BrAnon(var.as_u32(), None) }; + let br = ty::BoundRegion { var, kind: BrAnon(None) }; self.interner().mk_re_late_bound(self.binder_index, br) } @@ -300,14 +300,20 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { ty::Placeholder(placeholder) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: placeholder.universe, - name: BoundTyKind::Anon(self.variables.len() as u32), + bound: ty::BoundTy { + var: ty::BoundVar::from_usize(self.variables.len()), + kind: ty::BoundTyKind::Anon, + }, }), CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder), }, ty::Param(_) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: ty::UniverseIndex::ROOT, - name: ty::BoundTyKind::Anon(self.variables.len() as u32), + bound: ty::BoundTy { + var: ty::BoundVar::from_usize(self.variables.len()), + kind: ty::BoundTyKind::Anon, + }, }), CanonicalizeMode::Response { .. } => bug!("param ty in response: {t:?}"), }, @@ -345,7 +351,7 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { var }), ); - let bt = ty::BoundTy { var, kind: BoundTyKind::Anon(var.index() as u32) }; + let bt = ty::BoundTy { var, kind: BoundTyKind::Anon }; self.interner().mk_bound(self.binder_index, bt) } @@ -373,7 +379,7 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( ty::Placeholder { universe: placeholder.universe, - name: ty::BoundVar::from(self.variables.len()), + bound: ty::BoundVar::from(self.variables.len()), }, c.ty(), ), @@ -385,7 +391,7 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( ty::Placeholder { universe: ty::UniverseIndex::ROOT, - name: ty::BoundVar::from(self.variables.len()), + bound: ty::BoundVar::from(self.variables.len()), }, c.ty(), ), diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 705e79aebd8c..28aca76cceb6 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -106,7 +106,7 @@ pub trait InferCtxtEvalExt<'tcx> { } impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn evaluate_root_goal( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, @@ -357,7 +357,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // deal with `has_changed` in the next iteration. new_goals.normalizes_to_hack_goal = Some(this.resolve_vars_if_possible(goal)); - has_changed = has_changed.map_err(|c| c.unify_and(certainty)); + has_changed = has_changed.map_err(|c| c.unify_with(certainty)); } } } @@ -378,7 +378,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { Certainty::Yes => {} Certainty::Maybe(_) => { new_goals.goals.push(goal); - has_changed = has_changed.map_err(|c| c.unify_and(certainty)); + has_changed = has_changed.map_err(|c| c.unify_with(certainty)); } } } @@ -552,7 +552,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// /// If possible, try using `eq` instead which automatically handles nested /// goals correctly. - #[instrument(level = "debug", skip(self, param_env), ret)] + #[instrument(level = "trace", skip(self, param_env), ret)] pub(super) fn eq_and_get_goals>( &self, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index ee90488730a6..861fa0a305ac 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -50,7 +50,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { certainty: Certainty, ) -> QueryResult<'tcx> { let goals_certainty = self.try_evaluate_added_goals()?; - let certainty = certainty.unify_and(goals_certainty); + let certainty = certainty.unify_with(goals_certainty); let external_constraints = self.compute_external_query_constraints()?; @@ -188,7 +188,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } else { // For placeholders which were already part of the input, we simply map this // universal bound variable back the placeholder of the input. - original_values[info.expect_anon_placeholder() as usize] + original_values[info.expect_placeholder_index()] } }, )); diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index a96ec2c60f09..19bcbd461447 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -46,6 +46,8 @@ enum SolverMode { trait CanonicalResponseExt { fn has_no_inference_or_external_constraints(&self) -> bool; + + fn has_only_region_constraints(&self) -> bool; } impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { @@ -54,6 +56,11 @@ impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { && self.value.var_values.is_identity() && self.value.external_constraints.opaque_types.is_empty() } + + fn has_only_region_constraints(&self) -> bool { + self.value.var_values.is_identity_modulo_regions() + && self.value.external_constraints.opaque_types.is_empty() + } } impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { @@ -153,13 +160,22 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ) -> QueryResult<'tcx> { let tcx = self.tcx(); // We may need to invert the alias relation direction if dealing an alias on the RHS. + #[derive(Debug)] enum Invert { No, Yes, } let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other, direction, invert| { - debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other); + let span = tracing::span!( + tracing::Level::DEBUG, + "compute_alias_relate_goal(evaluate_normalizes_to)", + ?alias, + ?other, + ?direction, + ?invert + ); + let _enter = span.enter(); let result = ecx.probe(|ecx| { let other = match direction { // This is purely an optimization. @@ -184,7 +200,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { )); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }); - debug!("evaluate_normalizes_to({alias}, {other}, {direction:?}) -> {result:?}"); + debug!(?result); result }; @@ -210,18 +226,28 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } (Some(alias_lhs), Some(alias_rhs)) => { - debug!("compute_alias_relate_goal: both sides are aliases"); + debug!("both sides are aliases"); - let candidates = vec![ - // LHS normalizes-to RHS - evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No), - // RHS normalizes-to RHS - evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes), - // Relate via substs + let mut candidates = Vec::new(); + // LHS normalizes-to RHS + candidates.extend( + evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No).ok(), + ); + // RHS normalizes-to RHS + candidates.extend( + evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes).ok(), + ); + // Relate via substs + candidates.extend( self.probe(|ecx| { - debug!( - "compute_alias_relate_goal: alias defids are equal, equating substs" + let span = tracing::span!( + tracing::Level::DEBUG, + "compute_alias_relate_goal(relate_via_substs)", + ?alias_lhs, + ?alias_rhs, + ?direction ); + let _enter = span.enter(); match direction { ty::AliasRelationDirection::Equate => { @@ -233,11 +259,16 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }), - ]; + }) + .ok(), + ); debug!(?candidates); - self.try_merge_responses(candidates.into_iter()) + if let Some(merged) = self.try_merge_responses(&candidates) { + Ok(merged) + } else { + self.flounder(&candidates) + } } } } @@ -275,41 +306,51 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { debug!("added_goals={:?}", &self.nested_goals.goals[current_len..]); } + /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`. + /// + /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`. + #[instrument(level = "debug", skip(self), ret)] fn try_merge_responses( &mut self, - responses: impl Iterator>, - ) -> QueryResult<'tcx> { - let candidates = responses.into_iter().flatten().collect::>(); - - if candidates.is_empty() { - return Err(NoSolution); + responses: &[CanonicalResponse<'tcx>], + ) -> Option> { + if responses.is_empty() { + return None; } // FIXME(-Ztrait-solver=next): We should instead try to find a `Certainty::Yes` response with // a subset of the constraints that all the other responses have. - let one = candidates[0]; - if candidates[1..].iter().all(|resp| resp == &one) { - return Ok(one); + let one = responses[0]; + if responses[1..].iter().all(|&resp| resp == one) { + return Some(one); } - if let Some(response) = candidates.iter().find(|response| { - response.value.certainty == Certainty::Yes - && response.has_no_inference_or_external_constraints() - }) { - return Ok(*response); - } + responses + .iter() + .find(|response| { + response.value.certainty == Certainty::Yes + && response.has_no_inference_or_external_constraints() + }) + .copied() + } - let certainty = candidates.iter().fold(Certainty::AMBIGUOUS, |certainty, response| { - certainty.unify_and(response.value.certainty) + /// If we fail to merge responses we flounder and return overflow or ambiguity. + #[instrument(level = "debug", skip(self), ret)] + fn flounder(&mut self, responses: &[CanonicalResponse<'tcx>]) -> QueryResult<'tcx> { + if responses.is_empty() { + return Err(NoSolution); + } + let certainty = responses.iter().fold(Certainty::AMBIGUOUS, |certainty, response| { + certainty.unify_with(response.value.certainty) }); - // FIXME(-Ztrait-solver=next): We should take the intersection of the constraints on all the - // responses and use that for the constraints of this ambiguous response. - let response = self.evaluate_added_goals_and_make_canonical_response(certainty); - if let Ok(response) = &response { - assert!(response.has_no_inference_or_external_constraints()); - } - response + let response = self.evaluate_added_goals_and_make_canonical_response(certainty); + if let Ok(response) = response { + assert!(response.has_no_inference_or_external_constraints()); + Ok(response) + } else { + bug!("failed to make floundered response: {responses:?}"); + } } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index e0a69438dec0..2a47da81ec76 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -1,7 +1,6 @@ use crate::traits::specialization_graph; -use super::assembly; -use super::trait_goals::structural_traits; +use super::assembly::{self, structural_traits}; use super::EvalCtxt; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index aeb676660352..42c28686f5c1 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -209,6 +209,7 @@ impl<'tcx> SearchGraph<'tcx> { ) -> QueryResult<'tcx> { if self.should_use_global_cache() { if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_goal, tcx) { + debug!(?canonical_goal, ?result, "cache hit"); return result; } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index ce3db83d33dd..81f89fd950c8 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -1,6 +1,7 @@ //! Dealing with trait goals, i.e. `T: Trait<'a, U>`. -use super::{assembly, EvalCtxt, SolverMode}; +use super::assembly::{self, structural_traits}; +use super::{EvalCtxt, SolverMode}; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; use rustc_infer::traits::query::NoSolution; @@ -11,8 +12,6 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_middle::ty::{TraitPredicate, TypeVisitableExt}; use rustc_span::DUMMY_SP; -pub mod structural_traits; - impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn self_ty(self) -> Ty<'tcx> { self.self_ty() @@ -221,8 +220,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let self_ty = tcx.erase_regions(goal.predicate.self_ty()); if let Ok(layout) = tcx.layout_of(goal.param_env.and(self_ty)) - && layout.layout.size() == tcx.data_layout.pointer_size - && layout.layout.align().abi == tcx.data_layout.pointer_align.abi + && layout.layout.is_pointer_like(&tcx.data_layout) { // FIXME: We could make this faster by making a no-constraints response ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 878c502655cf..a53d414be9e7 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -234,7 +234,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { /// constructed once for a given type. As part of the construction process, the `ParamEnv` will /// have any supertrait bounds normalized -- e.g., if we have a type `struct Foo`, the /// `ParamEnv` will contain `T: Copy` and `T: Clone`, since `Copy: Clone`. When we construct our - /// own `ParamEnv`, we need to do this ourselves, through `traits::elaborate_predicates`, or + /// own `ParamEnv`, we need to do this ourselves, through `traits::elaborate`, or /// else `SelectionContext` will choke on the missing predicates. However, this should never /// show up in the final synthesized generics: we don't want our generated docs page to contain /// something like `T: Copy + Clone`, as that's redundant. Therefore, we keep track of a @@ -346,10 +346,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { _ => panic!("Unexpected error for '{:?}': {:?}", ty, result), }; - let normalized_preds = elaborate_predicates( - tcx, - computed_preds.clone().chain(user_computed_preds.iter().cloned()), - ); + let normalized_preds = + elaborate(tcx, computed_preds.clone().chain(user_computed_preds.iter().cloned())); new_env = ty::ParamEnv::new( tcx.mk_predicates_from_iter(normalized_preds), param_env.reveal(), diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index d360158fdf81..53d4f95e9e30 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -368,7 +368,7 @@ fn negative_impl_exists<'tcx>( } // Try to prove a negative obligation exists for super predicates - for pred in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) { + for pred in util::elaborate(infcx.tcx, iter::once(o.predicate)) { if resolve_negative_obligation(infcx.fork(), &o.with(infcx.tcx, pred), body_def_id) { return true; } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index 672b3365ff4a..0475f24d87c7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -1,6 +1,6 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime}; -use rustc_infer::traits::util::elaborate_predicates_with_span; +use rustc_infer::traits::util::elaborate; use rustc_infer::traits::{Obligation, ObligationCause, TraitObligation}; use rustc_middle::ty; use rustc_span::{Span, DUMMY_SP}; @@ -82,7 +82,7 @@ pub fn recompute_applicable_impls<'tcx>( let predicates = tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx); - for (pred, span) in elaborate_predicates_with_span(tcx, predicates.into_iter()) { + for (pred, span) in elaborate(tcx, predicates.into_iter()) { let kind = pred.kind(); if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder() && param_env_candidate_may_apply(kind.rebind(trait_pred)) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs index 13607b9079a7..7e1dba4ed262 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs @@ -21,10 +21,6 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> { self.infcx.tcx } - fn intercrate(&self) -> bool { - false - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } @@ -33,10 +29,6 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> { true } - fn mark_ambiguous(&mut self) { - bug!() - } - fn relate_with_variance>( &mut self, _: ty::Variance, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index c19798213b70..6ebf056f0e83 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1624,7 +1624,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } }; - for pred in super::elaborate_predicates(self.tcx, std::iter::once(cond)) { + for pred in super::elaborate(self.tcx, std::iter::once(cond)) { let bound_predicate = pred.kind(); if let ty::PredicateKind::Clause(ty::Clause::Trait(implication)) = bound_predicate.skip_binder() diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 8d831dca6e30..8a203dec86ba 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -58,10 +58,7 @@ pub use self::specialize::{specialization_graph, translate_substs, OverlapError} pub use self::structural_match::{ search_for_adt_const_param_violation, search_for_structural_match_violation, }; -pub use self::util::{ - elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span, - elaborate_trait_ref, elaborate_trait_refs, -}; +pub use self::util::elaborate; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; pub use self::util::{ @@ -267,7 +264,7 @@ pub fn normalize_param_env_or_error<'tcx>( // and errors will get reported then; so outside of type inference we // can be sure that no errors should occur. let mut predicates: Vec<_> = - util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter()).collect(); + util::elaborate(tcx, unnormalized_env.caller_bounds().into_iter()).collect(); debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index dbf6b78572a1..b8ad1925e4ea 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -8,7 +8,7 @@ //! - not reference the erased type `Self` except for in this receiver; //! - not have generic type parameters. -use super::{elaborate_predicates, elaborate_trait_ref}; +use super::elaborate; use crate::infer::TyCtxtInferExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -379,7 +379,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { // Search for a predicate like `Self : Sized` amongst the trait bounds. let predicates = tcx.predicates_of(def_id); let predicates = predicates.instantiate_identity(tcx).predicates; - elaborate_predicates(tcx, predicates.into_iter()).any(|pred| match pred.kind().skip_binder() { + elaborate(tcx, predicates.into_iter()).any(|pred| match pred.kind().skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(ref trait_pred)) => { trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0) } @@ -666,7 +666,8 @@ fn object_ty_for_trait<'tcx>( }); debug!(?trait_predicate); - let mut elaborated_predicates: Vec<_> = elaborate_trait_ref(tcx, trait_ref) + let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx); + let mut elaborated_predicates: Vec<_> = elaborate(tcx, [pred]) .filter_map(|pred| { debug!(?pred); let pred = pred.to_opt_poly_projection_pred()?; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index b8d9cff9c489..826fc63ca065 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -772,7 +772,7 @@ impl<'tcx> TypeFolder> for BoundVarReplacer<'_, 'tcx> { } ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => { let universe = self.universe_for(debruijn); - let p = ty::PlaceholderRegion { universe, name: br.kind }; + let p = ty::PlaceholderRegion { universe, bound: br }; self.mapped_regions.insert(p, br); self.infcx.tcx.mk_re_placeholder(p) } @@ -790,7 +790,7 @@ impl<'tcx> TypeFolder> for BoundVarReplacer<'_, 'tcx> { } ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { let universe = self.universe_for(debruijn); - let p = ty::PlaceholderType { universe, name: bound_ty.kind }; + let p = ty::PlaceholderType { universe, bound: bound_ty }; self.mapped_types.insert(p, bound_ty); self.infcx.tcx.mk_placeholder(p) } @@ -809,7 +809,7 @@ impl<'tcx> TypeFolder> for BoundVarReplacer<'_, 'tcx> { } ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => { let universe = self.universe_for(debruijn); - let p = ty::PlaceholderConst { universe, name: bound_const }; + let p = ty::PlaceholderConst { universe, bound: bound_const }; self.mapped_consts.insert(p, bound_const); self.infcx.tcx.mk_const(p, ct.ty()) } 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 090312338e00..a794d20d683f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -97,7 +97,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else if lang_items.tuple_trait() == Some(def_id) { self.assemble_candidate_for_tuple(obligation, &mut candidates); } else if lang_items.pointer_like() == Some(def_id) { - self.assemble_candidate_for_ptr_sized(obligation, &mut candidates); + self.assemble_candidate_for_pointer_like(obligation, &mut candidates); } else if lang_items.fn_ptr_trait() == Some(def_id) { self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); } else { @@ -942,15 +942,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - fn assemble_candidate_for_ptr_sized( + fn assemble_candidate_for_pointer_like( &mut self, obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { // The regions of a type don't affect the size of the type - let self_ty = self - .tcx() - .erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate.self_ty())); + let tcx = self.tcx(); + let self_ty = + tcx.erase_regions(tcx.erase_late_bound_regions(obligation.predicate.self_ty())); // But if there are inference variables, we have to wait until it's resolved. if self_ty.has_non_region_infer() { @@ -958,9 +958,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - if let Ok(layout) = self.tcx().layout_of(obligation.param_env.and(self_ty)) - && layout.layout.size() == self.tcx().data_layout.pointer_size - && layout.layout.align().abi == self.tcx().data_layout.pointer_align.abi + if let Ok(layout) = tcx.layout_of(obligation.param_env.and(self_ty)) + && layout.layout.is_pointer_like(&tcx.data_layout) { candidates.vec.push(BuiltinCandidate { has_nested: false }); } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b58e62536d60..6bb53418beab 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2,12 +2,6 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection -// FIXME: The `map` field in ProvisionalEvaluationCache should be changed to -// a `FxIndexMap` to avoid query instability, but right now it causes a perf regression. This would be -// fixed or at least lightened by the addition of the `drain_filter` method to `FxIndexMap` -// Relevant: https://github.com/rust-lang/rust/pull/103723 and https://github.com/bluss/indexmap/issues/242 -#![allow(rustc::potential_query_instability)] - use self::EvaluationResult::*; use self::SelectionCandidate::*; @@ -32,8 +26,7 @@ use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; use crate::traits::Unimplemented; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::Diagnostic; use rustc_hir as hir; @@ -2782,7 +2775,7 @@ struct ProvisionalEvaluationCache<'tcx> { /// - then we determine that `E` is in error -- we will then clear /// all cache values whose DFN is >= 4 -- in this case, that /// means the cached value for `F`. - map: RefCell, ProvisionalEvaluation>>, + map: RefCell, ProvisionalEvaluation>>, /// The stack of args that we assume to be true because a `WF(arg)` predicate /// is on the stack above (and because of wellformedness is coinductive). @@ -2930,12 +2923,13 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { /// have a performance impact in practice. fn on_completion(&self, dfn: usize) { debug!(?dfn, "on_completion"); - - for (fresh_trait_pred, eval) in - self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn) - { - debug!(?fresh_trait_pred, ?eval, "on_completion"); - } + self.map.borrow_mut().retain(|fresh_trait_pred, eval| { + if eval.from_dfn >= dfn { + debug!(?fresh_trait_pred, ?eval, "on_completion"); + return false; + } + true + }); } } @@ -3017,7 +3011,7 @@ fn bind_generator_hidden_types_above<'tcx>( if let ty::ReErased = r.kind() { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(counter), - kind: ty::BrAnon(counter, None), + kind: ty::BrAnon(None), }; counter += 1; r = tcx.mk_re_late_bound(current_depth, br); @@ -3033,7 +3027,7 @@ fn bind_generator_hidden_types_above<'tcx>( debug_assert!(!hidden_types.has_erased_regions()); } let bound_vars = tcx.mk_bound_variable_kinds_from_iter(bound_vars.iter().chain( - (num_bound_variables..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))), + (num_bound_variables..counter).map(|_| ty::BoundVariableKind::Region(ty::BrAnon(None))), )); ty::Binder::bind_with_vars(hidden_types, bound_vars) } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 156674e33c33..3d026506a5a8 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -364,7 +364,7 @@ impl<'tcx> WfPredicates<'tcx> { }; if let Elaborate::All = elaborate { - let implied_obligations = traits::util::elaborate_obligations(tcx, obligations); + let implied_obligations = traits::util::elaborate(tcx, obligations); let implied_obligations = implied_obligations.map(extend); self.out.extend(implied_obligations); } else { @@ -920,7 +920,7 @@ pub(crate) fn required_region_bounds<'tcx>( ) -> Vec> { assert!(!erased_self_ty.has_escaping_bound_vars()); - traits::elaborate_predicates(tcx, predicates) + traits::elaborate(tcx, predicates) .filter_map(|pred| { debug!(?pred); match pred.kind().skip_binder() { diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index f8c8f744e6d5..9683e48478ed 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -730,7 +730,7 @@ fn bound_vars_for_item(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> { ty::GenericParamDefKind::Lifetime => { let br = ty::BoundRegion { var: ty::BoundVar::from_usize(substs.len()), - kind: ty::BrAnon(substs.len() as u32, None), + kind: ty::BrAnon(None), }; tcx.mk_re_late_bound(ty::INNERMOST, br).into() } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 527f6013a151..2be72879b7b1 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -376,7 +376,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { ty::Placeholder(_placeholder) => { chalk_ir::TyKind::Placeholder(chalk_ir::PlaceholderIndex { ui: chalk_ir::UniverseIndex { counter: _placeholder.universe.as_usize() }, - idx: _placeholder.name.expect_anon() as usize, + idx: _placeholder.bound.var.as_usize(), }) } ty::Infer(_infer) => unimplemented!(), @@ -479,12 +479,15 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty> { ty::DebruijnIndex::from_usize(bound.debruijn.depth() as usize), ty::BoundTy { var: ty::BoundVar::from_usize(bound.index), - kind: ty::BoundTyKind::Anon(bound.index as u32), + kind: ty::BoundTyKind::Anon, }, ), TyKind::Placeholder(placeholder) => ty::Placeholder(ty::Placeholder { universe: ty::UniverseIndex::from_usize(placeholder.ui.counter), - name: ty::BoundTyKind::Anon(placeholder.idx as u32), + bound: ty::BoundTy { + var: ty::BoundVar::from_usize(placeholder.idx), + kind: ty::BoundTyKind::Anon, + }, }), TyKind::InferenceVar(_, _) => unimplemented!(), TyKind::Dyn(_) => unimplemented!(), @@ -530,13 +533,16 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime unimplemented!(), chalk_ir::LifetimeData::Placeholder(p) => tcx.mk_re_placeholder(ty::Placeholder { universe: ty::UniverseIndex::from_usize(p.ui.counter), - name: ty::BoundRegionKind::BrAnon(p.idx as u32, None), + bound: ty::BoundRegion { + var: ty::BoundVar::from_usize(p.idx), + kind: ty::BoundRegionKind::BrAnon(None), + }, }), chalk_ir::LifetimeData::Static => tcx.lifetimes.re_static, chalk_ir::LifetimeData::Erased => tcx.lifetimes.re_erased, @@ -685,7 +691,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders TypeVisitor> for BoundVarsCollector<'tcx> { } } - ty::BoundRegionKind::BrAnon(var, _) => match self.parameters.entry(var) { + ty::BoundRegionKind::BrAnon(_) => match self.parameters.entry(br.var.as_u32()) { Entry::Vacant(entry) => { entry.insert(chalk_ir::VariableKind::Lifetime); } @@ -1030,8 +1036,8 @@ impl<'a, 'tcx> TypeFolder> for NamedBoundVarSubstitutor<'a, 'tcx> { match *r { ty::ReLateBound(index, br) if index == self.binder_index => match br.kind { ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) { - Some(idx) => { - let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx, None) }; + Some(_) => { + let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(None) }; return self.tcx.mk_re_late_bound(index, new_br); } None => panic!("Missing `BrNamed`."), @@ -1090,7 +1096,10 @@ impl<'tcx> TypeFolder> for ParamsSubstitutor<'tcx> { ty::Param(param) => match self.list.iter().position(|r| r == ¶m) { Some(idx) => self.tcx.mk_placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::from_usize(0), - name: ty::BoundTyKind::Anon(idx as u32), + bound: ty::BoundTy { + var: ty::BoundVar::from_usize(idx), + kind: ty::BoundTyKind::Anon, + }, }), None => { self.list.push(param); @@ -1098,7 +1107,10 @@ impl<'tcx> TypeFolder> for ParamsSubstitutor<'tcx> { self.params.insert(idx as u32, param); self.tcx.mk_placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::from_usize(0), - name: ty::BoundTyKind::Anon(idx as u32), + bound: ty::BoundTy { + var: ty::BoundVar::from_usize(idx), + kind: ty::BoundTyKind::Anon, + }, }) } }, @@ -1115,7 +1127,7 @@ impl<'tcx> TypeFolder> for ParamsSubstitutor<'tcx> { Some(idx) => { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(*idx), - kind: ty::BrAnon(*idx, None), + kind: ty::BrAnon(None), }; self.tcx.mk_re_late_bound(self.binder_index, br) } @@ -1123,7 +1135,7 @@ impl<'tcx> TypeFolder> for ParamsSubstitutor<'tcx> { let idx = self.named_regions.len() as u32; let br = ty::BoundRegion { var: ty::BoundVar::from_u32(idx), - kind: ty::BrAnon(idx, None), + kind: ty::BrAnon(None), }; self.named_regions.insert(_re.def_id, idx); self.tcx.mk_re_late_bound(self.binder_index, br) @@ -1156,8 +1168,8 @@ impl<'tcx> TypeFolder> for ReverseParamsSubstitutor<'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match *t.kind() { - ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, name }) => { - match self.params.get(&name.expect_anon()) { + ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, bound }) => { + match self.params.get(&bound.var.as_u32()) { Some(&ty::ParamTy { index, name }) => self.tcx.mk_ty_param(index, name), None => t, } @@ -1189,8 +1201,7 @@ impl<'tcx> TypeVisitor> for PlaceholdersCollector { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { ty::Placeholder(p) if p.universe == self.universe_index => { - self.next_ty_placeholder = - self.next_ty_placeholder.max(p.name.expect_anon() as usize + 1); + self.next_ty_placeholder = self.next_ty_placeholder.max(p.bound.var.as_usize() + 1); } _ => (), @@ -1202,8 +1213,9 @@ impl<'tcx> TypeVisitor> for PlaceholdersCollector { fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow { match *r { ty::RePlaceholder(p) if p.universe == self.universe_index => { - if let ty::BoundRegionKind::BrAnon(anon, _) = p.name { - self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon); + if let ty::BoundRegionKind::BrAnon(_) = p.bound.kind { + self.next_anon_region_placeholder = + self.next_anon_region_placeholder.max(p.bound.var.as_u32()); } // FIXME: This doesn't seem to handle BrNamed at all? } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 4b4a8ebd079f..a93a42987ed5 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -149,7 +149,7 @@ mod rustc { .iter() .enumerate() .find(|(_, field_def)| name == field_def.name) - .expect(&format!("There were no fields named `{name}`.")); + .unwrap_or_else(|| panic!("There were no fields named `{name}`.")); fields[field_idx].unwrap_leaf() == ScalarInt::TRUE }; diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl index abe65a0e3fef..a1e97bb95bc6 100644 --- a/compiler/rustc_ty_utils/messages.ftl +++ b/compiler/rustc_ty_utils/messages.ftl @@ -45,3 +45,13 @@ ty_utils_control_flow_not_supported = control flow is not supported in generic c ty_utils_inline_asm_not_supported = assembly is not supported in generic constants ty_utils_operation_not_supported = unsupported operation in generic constants + +ty_utils_unexpected_fnptr_associated_item = `FnPtr` trait with unexpected associated item + +ty_utils_zero_length_simd_type = monomorphising SIMD type `{$ty}` of zero length + +ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with more than one array field + +ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes} + +ty_utils_non_primative_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}` diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index ab3e62f04845..3db3c98e9e28 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -67,3 +67,36 @@ pub enum GenericConstantTooComplexSub { #[label(ty_utils_operation_not_supported)] OperationNotSupported(#[primary_span] Span), } + +#[derive(Diagnostic)] +#[diag(ty_utils_unexpected_fnptr_associated_item)] +pub struct UnexpectedFnPtrAssociatedItem { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ty_utils_zero_length_simd_type)] +pub struct ZeroLengthSimdType<'tcx> { + pub ty: Ty<'tcx>, +} + +#[derive(Diagnostic)] +#[diag(ty_utils_multiple_array_fields_simd_type)] +pub struct MultipleArrayFieldsSimdType<'tcx> { + pub ty: Ty<'tcx>, +} + +#[derive(Diagnostic)] +#[diag(ty_utils_oversized_simd_type)] +pub struct OversizedSimdType<'tcx> { + pub ty: Ty<'tcx>, + pub max_lanes: u64, +} + +#[derive(Diagnostic)] +#[diag(ty_utils_non_primative_simd_type)] +pub struct NonPrimitiveSimdType<'tcx> { + pub ty: Ty<'tcx>, + pub e_ty: Ty<'tcx>, +} diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index ad70154c98ef..0a6c118093e5 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -8,6 +8,8 @@ use rustc_span::sym; use rustc_trait_selection::traits; use traits::{translate_substs, Reveal}; +use crate::errors::UnexpectedFnPtrAssociatedItem; + fn resolve_instance<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>, @@ -282,10 +284,9 @@ fn resolve_associated_item<'tcx>( substs: rcvr_substs, }) } else { - tcx.sess.span_fatal( - tcx.def_span(trait_item_id), - "`FnPtrAddr` trait with unexpected assoc item", - ) + tcx.sess.emit_fatal(UnexpectedFnPtrAssociatedItem { + span: tcx.def_span(trait_item_id), + }) } } else { None diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 73f86f74d14f..63eb34f7d552 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -1,7 +1,7 @@ use hir::def_id::DefId; use rustc_hir as hir; use rustc_index::bit_set::BitSet; -use rustc_index::vec::IndexVec; +use rustc_index::vec::{IndexSlice, IndexVec}; use rustc_middle::mir::{GeneratorLayout, GeneratorSavedLocal}; use rustc_middle::ty::layout::{ IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES, @@ -17,6 +17,9 @@ use rustc_target::abi::*; use std::fmt::Debug; use std::iter; +use crate::errors::{ + MultipleArrayFieldsSimdType, NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType, +}; use crate::layout_sanity_check::sanity_check_layout; pub fn provide(providers: &mut ty::query::Providers) { @@ -62,23 +65,10 @@ fn layout_of<'tcx>( Ok(layout) } -// Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`. -// This is used to go between `memory_index` (source field order to memory order) -// and `inverse_memory_index` (memory order to source field order). -// See also `FieldsShape::Arbitrary::memory_index` for more details. -// FIXME(eddyb) build a better abstraction for permutations, if possible. -fn invert_mapping(map: &[u32]) -> Vec { - let mut inverse = vec![0; map.len()]; - for i in 0..map.len() { - inverse[map[i] as usize] = i as u32; - } - inverse -} - fn univariant_uninterned<'tcx>( cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, ty: Ty<'tcx>, - fields: &[Layout<'_>], + fields: &IndexSlice>, repr: &ReprOptions, kind: StructKind, ) -> Result> { @@ -106,7 +96,7 @@ fn layout_of_uncached<'tcx>( }; let scalar = |value: Primitive| tcx.mk_layout(LayoutS::scalar(cx, scalar_unit(value))); - let univariant = |fields: &[Layout<'_>], repr: &ReprOptions, kind| { + let univariant = |fields: &IndexSlice>, repr: &ReprOptions, kind| { Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?)) }; debug_assert!(!ty.has_non_region_infer()); @@ -256,12 +246,14 @@ fn layout_of_uncached<'tcx>( }), // Odd unit types. - ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?, + ty::FnDef(..) => { + univariant(IndexSlice::empty(), &ReprOptions::default(), StructKind::AlwaysSized)? + } ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => { let mut unit = univariant_uninterned( cx, ty, - &[], + IndexSlice::empty(), &ReprOptions::default(), StructKind::AlwaysSized, )?; @@ -277,7 +269,7 @@ fn layout_of_uncached<'tcx>( ty::Closure(_, ref substs) => { let tys = substs.as_closure().upvar_tys(); univariant( - &tys.map(|ty| Ok(cx.layout_of(ty)?.layout)).collect::, _>>()?, + &tys.map(|ty| Ok(cx.layout_of(ty)?.layout)).try_collect::>()?, &ReprOptions::default(), StructKind::AlwaysSized, )? @@ -288,7 +280,7 @@ fn layout_of_uncached<'tcx>( if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; univariant( - &tys.iter().map(|k| Ok(cx.layout_of(k)?.layout)).collect::, _>>()?, + &tys.iter().map(|k| Ok(cx.layout_of(k)?.layout)).try_collect::>()?, &ReprOptions::default(), kind, )? @@ -305,6 +297,8 @@ fn layout_of_uncached<'tcx>( return Err(LayoutError::Unknown(ty)); } + let fields = &def.non_enum_variant().fields; + // Supported SIMD vectors are homogeneous ADTs with at least one field: // // * #[repr(simd)] struct S(T, T, T, T); @@ -315,18 +309,22 @@ fn layout_of_uncached<'tcx>( // SIMD vectors with zero fields are not supported. // (should be caught by typeck) - if def.non_enum_variant().fields.is_empty() { - tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty)); + if fields.is_empty() { + tcx.sess.emit_fatal(ZeroLengthSimdType { ty }) } // Type of the first ADT field: - let f0_ty = def.non_enum_variant().fields[FieldIdx::from_u32(0)].ty(tcx, substs); + let f0_ty = fields[FieldIdx::from_u32(0)].ty(tcx, substs); // Heterogeneous SIMD vectors are not supported: // (should be caught by typeck) - for fi in &def.non_enum_variant().fields { + for fi in fields { if fi.ty(tcx, substs) != f0_ty { - tcx.sess.fatal(&format!("monomorphising heterogeneous SIMD type `{}`", ty)); + tcx.sess.delay_span_bug( + DUMMY_SP, + "#[repr(simd)] was applied to an ADT with hetrogeneous field type", + ); + return Err(LayoutError::Unknown(ty)); } } @@ -341,12 +339,9 @@ fn layout_of_uncached<'tcx>( // First ADT field is an array: // SIMD vectors with multiple array fields are not supported: - // (should be caught by typeck) + // Can't be caught by typeck with a generic simd type. if def.non_enum_variant().fields.len() != 1 { - tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` with more than one array field", - ty - )); + tcx.sess.emit_fatal(MultipleArrayFieldsSimdType { ty }); } // Extract the number of elements from the layout of the array field: @@ -366,12 +361,9 @@ fn layout_of_uncached<'tcx>( // // Can't be caught in typeck if the array length is generic. if e_len == 0 { - tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty)); + tcx.sess.emit_fatal(ZeroLengthSimdType { ty }); } else if e_len > MAX_SIMD_LANES { - tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` of length greater than {}", - ty, MAX_SIMD_LANES, - )); + tcx.sess.emit_fatal(OversizedSimdType { ty, max_lanes: MAX_SIMD_LANES }); } // Compute the ABI of the element type: @@ -379,11 +371,7 @@ fn layout_of_uncached<'tcx>( let Abi::Scalar(e_abi) = e_ly.abi else { // This error isn't caught in typeck, e.g., if // the element type of the vector is generic. - tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` with a non-primitive-scalar \ - (integer/float/pointer) element type `{}`", - ty, e_ty - )) + tcx.sess.emit_fatal(NonPrimitiveSimdType { ty, e_ty }); }; // Compute the size and alignment of the vector: @@ -393,7 +381,7 @@ fn layout_of_uncached<'tcx>( // Compute the placement of the vector fields: let fields = if is_array { - FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0] } + FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() } } else { FieldsShape::Array { stride: e_ly.size, count: e_len } }; @@ -418,9 +406,9 @@ fn layout_of_uncached<'tcx>( v.fields .iter() .map(|field| Ok(cx.layout_of(field.ty(tcx, substs))?.layout)) - .collect::, _>>() + .try_collect::>() }) - .collect::, _>>()?; + .try_collect::>()?; if def.is_union() { if def.repr().pack.is_some() && def.repr().align.is_some() { @@ -492,8 +480,7 @@ fn layout_of_uncached<'tcx>( enum SavedLocalEligibility { Unassigned, Assigned(VariantIdx), - // FIXME: Use newtype_index so we aren't wasting bytes - Ineligible(Option), + Ineligible(Option), } // When laying out generators, we divide our saved local fields into two @@ -522,7 +509,7 @@ fn generator_saved_local_eligibility( use SavedLocalEligibility::*; let mut assignments: IndexVec = - IndexVec::from_elem_n(Unassigned, info.field_tys.len()); + IndexVec::from_elem(Unassigned, &info.field_tys); // The saved locals not eligible for overlap. These will get // "promoted" to the prefix of our generator. @@ -605,7 +592,7 @@ fn generator_saved_local_eligibility( // Write down the order of our locals that will be promoted to the prefix. { for (idx, local) in ineligible_locals.iter().enumerate() { - assignments[local] = Ineligible(Some(idx as u32)); + assignments[local] = Ineligible(Some(FieldIdx::from_usize(idx))); } } debug!("generator saved local assignments: {:?}", assignments); @@ -654,7 +641,7 @@ fn generator_layout<'tcx>( .map(|ty| Ok(cx.layout_of(ty)?.layout)) .chain(iter::once(Ok(tag_layout))) .chain(promoted_layouts) - .collect::, _>>()?; + .try_collect::>()?; let prefix = univariant_uninterned( cx, ty, @@ -672,26 +659,28 @@ fn generator_layout<'tcx>( debug!("prefix = {:#?}", prefix); let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields { FieldsShape::Arbitrary { mut offsets, memory_index } => { - let mut inverse_memory_index = invert_mapping(&memory_index); + let mut inverse_memory_index = memory_index.invert_bijective_mapping(); // "a" (`0..b_start`) and "b" (`b_start..`) correspond to // "outer" and "promoted" fields respectively. - let b_start = (tag_index + 1) as u32; - let offsets_b = offsets.split_off(b_start as usize); + let b_start = FieldIdx::from_usize(tag_index + 1); + let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.as_usize())); let offsets_a = offsets; // Disentangle the "a" and "b" components of `inverse_memory_index` // by preserving the order but keeping only one disjoint "half" each. // FIXME(eddyb) build a better abstraction for permutations, if possible. - let inverse_memory_index_b: Vec<_> = - inverse_memory_index.iter().filter_map(|&i| i.checked_sub(b_start)).collect(); - inverse_memory_index.retain(|&i| i < b_start); + let inverse_memory_index_b: IndexVec = inverse_memory_index + .iter() + .filter_map(|&i| i.as_u32().checked_sub(b_start.as_u32()).map(FieldIdx::from_u32)) + .collect(); + inverse_memory_index.raw.retain(|&i| i < b_start); let inverse_memory_index_a = inverse_memory_index; // Since `inverse_memory_index_{a,b}` each only refer to their // respective fields, they can be safely inverted - let memory_index_a = invert_mapping(&inverse_memory_index_a); - let memory_index_b = invert_mapping(&inverse_memory_index_b); + let memory_index_a = inverse_memory_index_a.invert_bijective_mapping(); + let memory_index_b = inverse_memory_index_b.invert_bijective_mapping(); let outer_fields = FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a }; @@ -722,7 +711,7 @@ fn generator_layout<'tcx>( ty, &variant_only_tys .map(|ty| Ok(cx.layout_of(ty)?.layout)) - .collect::, _>>()?, + .try_collect::>()?, &ReprOptions::default(), StructKind::Prefixed(prefix_size, prefix_align.abi), )?; @@ -741,13 +730,16 @@ fn generator_layout<'tcx>( // promoted fields were being used, but leave the elements not in the // subset as `INVALID_FIELD_IDX`, which we can filter out later to // obtain a valid (bijective) mapping. - const INVALID_FIELD_IDX: u32 = !0; - let mut combined_inverse_memory_index = - vec![INVALID_FIELD_IDX; promoted_memory_index.len() + memory_index.len()]; + const INVALID_FIELD_IDX: FieldIdx = FieldIdx::MAX; + debug_assert!(variant_fields.next_index() <= INVALID_FIELD_IDX); + + let mut combined_inverse_memory_index = IndexVec::from_elem_n( + INVALID_FIELD_IDX, + promoted_memory_index.len() + memory_index.len(), + ); let mut offsets_and_memory_index = iter::zip(offsets, memory_index); let combined_offsets = variant_fields - .iter() - .enumerate() + .iter_enumerated() .map(|(i, local)| { let (offset, memory_index) = match assignments[*local] { Unassigned => bug!(), @@ -756,19 +748,19 @@ fn generator_layout<'tcx>( (offset, promoted_memory_index.len() as u32 + memory_index) } Ineligible(field_idx) => { - let field_idx = field_idx.unwrap() as usize; + let field_idx = field_idx.unwrap(); (promoted_offsets[field_idx], promoted_memory_index[field_idx]) } }; - combined_inverse_memory_index[memory_index as usize] = i as u32; + combined_inverse_memory_index[memory_index] = i; offset }) .collect(); // Remove the unused slots and invert the mapping to obtain the // combined `memory_index` (also see previous comment). - combined_inverse_memory_index.retain(|&i| i != INVALID_FIELD_IDX); - let combined_memory_index = invert_mapping(&combined_inverse_memory_index); + combined_inverse_memory_index.raw.retain(|&i| i != INVALID_FIELD_IDX); + let combined_memory_index = combined_inverse_memory_index.invert_bijective_mapping(); variant.fields = FieldsShape::Arbitrary { offsets: combined_offsets, @@ -779,7 +771,7 @@ fn generator_layout<'tcx>( align = align.max(variant.align); Ok(variant) }) - .collect::, _>>()?; + .try_collect::>()?; size = size.align_to(align.abi); diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 3865a8f32236..2613445f39be 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -5,10 +5,13 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(iterator_try_collect)] #![feature(let_chains)] #![feature(never_type)] #![feature(box_patterns)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_middle; diff --git a/config.example.toml b/config.example.toml index 5ef83760aed2..b27a34e61c54 100644 --- a/config.example.toml +++ b/config.example.toml @@ -16,7 +16,7 @@ # Use different pre-set defaults than the global defaults. # # See `src/bootstrap/defaults` for more information. -# Note that this has no default value (x.py uses the defaults in `config.toml.example`). +# Note that this has no default value (x.py uses the defaults in `config.example.toml`). #profile = # Keeps track of the last version of `x.py` used. @@ -585,7 +585,7 @@ changelog-seen = 2 # Having the git information can cause a lot of rebuilds during development. # # FIXME(#76720): this can causes bugs if different compilers reuse the same metadata cache. -#ignore-git = if rust.channel == "dev" { true } else { false } +#omit-git-hash = if rust.channel == "dev" { true } else { false } # Whether to create a source tarball by default when running `x dist`. # diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index c7e7ed3e95e0..c1cd3c74ab67 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -359,7 +359,7 @@ use crate::vec::Vec; /// [Deref]: core::ops::Deref "ops::Deref" /// [`Deref`]: core::ops::Deref "ops::Deref" /// [`as_str()`]: String::as_str -#[derive(PartialOrd, Eq, Ord)] +#[derive(PartialEq, PartialOrd, Eq, Ord)] #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), lang = "String")] pub struct String { @@ -2207,14 +2207,6 @@ impl<'a, 'b> Pattern<'a> for &'b String { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for String { - #[inline] - fn eq(&self, other: &String) -> bool { - PartialEq::eq(&self[..], &other[..]) - } -} - macro_rules! impl_eq { ($lhs:ty, $rhs: ty) => { #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 8a8d4caf96f3..5888e2960bb7 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -764,6 +764,7 @@ where { type Error = U::Error; + #[inline] fn try_into(self) -> Result { U::try_from(self) } @@ -779,6 +780,7 @@ where { type Error = Infallible; + #[inline] fn try_from(value: U) -> Result { Ok(U::into(value)) } diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 1cd71193bd77..37db074293d8 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -1,5 +1,4 @@ use crate::convert::TryFrom; -use crate::marker::Destruct; use crate::mem; use crate::num::NonZeroUsize; use crate::ops::{self, Try}; @@ -22,8 +21,7 @@ unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usi /// The *successor* operation moves towards values that compare greater. /// The *predecessor* operation moves towards values that compare lesser. #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] -#[const_trait] -pub trait Step: ~const Clone + ~const PartialOrd + Sized { +pub trait Step: Clone + PartialOrd + Sized { /// Returns the number of *successor* steps required to get from `start` to `end`. /// /// Returns `None` if the number of steps would overflow `usize` @@ -237,8 +235,7 @@ macro_rules! step_integer_impls { $( #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - #[rustc_const_unstable(feature = "const_iter", issue = "92476")] - impl const Step for $u_narrower { + impl Step for $u_narrower { step_identical_methods!(); #[inline] @@ -270,8 +267,7 @@ macro_rules! step_integer_impls { #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - #[rustc_const_unstable(feature = "const_iter", issue = "92476")] - impl const Step for $i_narrower { + impl Step for $i_narrower { step_identical_methods!(); #[inline] @@ -335,8 +331,7 @@ macro_rules! step_integer_impls { $( #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - #[rustc_const_unstable(feature = "const_iter", issue = "92476")] - impl const Step for $u_wider { + impl Step for $u_wider { step_identical_methods!(); #[inline] @@ -361,8 +356,7 @@ macro_rules! step_integer_impls { #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - #[rustc_const_unstable(feature = "const_iter", issue = "92476")] - impl const Step for $i_wider { + impl Step for $i_wider { step_identical_methods!(); #[inline] @@ -412,8 +406,7 @@ step_integer_impls! { } #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] -#[rustc_const_unstable(feature = "const_iter", issue = "92476")] -impl const Step for char { +impl Step for char { #[inline] fn steps_between(&start: &char, &end: &char) -> Option { let start = start as u32; @@ -431,7 +424,6 @@ impl const Step for char { } #[inline] - #[rustc_allow_const_fn_unstable(const_try)] fn forward_checked(start: char, count: usize) -> Option { let start = start as u32; let mut res = Step::forward_checked(start, count)?; @@ -448,7 +440,6 @@ impl const Step for char { } #[inline] - #[rustc_allow_const_fn_unstable(const_try)] fn backward_checked(start: char, count: usize) -> Option { let start = start as u32; let mut res = Step::backward_checked(start, count)?; @@ -524,7 +515,6 @@ macro_rules! range_incl_exact_iter_impl { } /// Specialization implementations for `Range`. -#[const_trait] trait RangeIteratorImpl { type Item; @@ -539,7 +529,7 @@ trait RangeIteratorImpl { fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize>; } -impl const RangeIteratorImpl for ops::Range { +impl RangeIteratorImpl for ops::Range { type Item = A; #[inline] @@ -625,7 +615,7 @@ impl const RangeIteratorImpl for ops::Range } } -impl const RangeIteratorImpl for ops::Range { +impl RangeIteratorImpl for ops::Range { #[inline] fn spec_next(&mut self) -> Option { if self.start < self.end { @@ -713,8 +703,7 @@ impl const RangeIteratorImpl for ops::R } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_iter", issue = "92476")] -impl const Iterator for ops::Range { +impl Iterator for ops::Range { type Item = A; #[inline] @@ -824,8 +813,7 @@ range_incl_exact_iter_impl! { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_iter", issue = "92476")] -impl const DoubleEndedIterator for ops::Range { +impl DoubleEndedIterator for ops::Range { #[inline] fn next_back(&mut self) -> Option { self.spec_next_back() diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index d82ecb698dd0..182d9f758adc 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -1,4 +1,3 @@ -use crate::marker::Destruct; use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; @@ -39,7 +38,6 @@ use crate::ops::{ControlFlow, Try}; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "DoubleEndedIterator")] -#[const_trait] pub trait DoubleEndedIterator: Iterator { /// Removes and returns an element from the end of the iterator. /// @@ -136,10 +134,7 @@ pub trait DoubleEndedIterator: Iterator { /// [`Err(k)`]: Err #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> - where - Self::Item: ~const Destruct, - { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { for i in 0..n { if self.next_back().is_none() { // SAFETY: `i` is always less than `n`. @@ -192,7 +187,6 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_nth_back", since = "1.37.0")] - #[rustc_do_not_const_check] fn nth_back(&mut self, n: usize) -> Option { if self.advance_back_by(n).is_err() { return None; @@ -232,7 +226,6 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] - #[rustc_do_not_const_check] fn try_rfold(&mut self, init: B, mut f: F) -> R where Self: Sized, @@ -304,7 +297,6 @@ pub trait DoubleEndedIterator: Iterator { #[doc(alias = "foldr")] #[inline] #[stable(feature = "iter_rfold", since = "1.27.0")] - #[rustc_do_not_const_check] fn rfold(mut self, init: B, mut f: F) -> B where Self: Sized, @@ -360,7 +352,6 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_rfind", since = "1.27.0")] - #[rustc_do_not_const_check] fn rfind

(&mut self, predicate: P) -> Option where Self: Sized, diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 36cf7defd6de..f3d1e45f4fb6 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1,6 +1,5 @@ use crate::array; use crate::cmp::{self, Ordering}; -use crate::marker::Destruct; use crate::num::NonZeroUsize; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; @@ -340,10 +339,8 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> - where - Self::Item: ~const Destruct, - { + #[rustc_do_not_const_check] + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { for i in 0..n { if self.next().is_none() { // SAFETY: `i` is always less than `n`. @@ -394,10 +391,8 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn nth(&mut self, n: usize) -> Option - where - Self::Item: ~const Destruct, - { + #[rustc_do_not_const_check] + fn nth(&mut self, n: usize) -> Option { self.advance_by(n).ok()?; self.next() } diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index c8f60defff77..af02848233d9 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -86,5 +86,4 @@ pub unsafe trait InPlaceIterable: Iterator {} /// for details. Consumers are free to rely on the invariants in unsafe code. #[unstable(feature = "trusted_step", issue = "85731")] #[rustc_specialization_trait] -#[const_trait] -pub unsafe trait TrustedStep: ~const Step {} +pub unsafe trait TrustedStep: Step {} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index a6b9acb576eb..4fd5a4bfc65f 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -123,11 +123,9 @@ #![feature(const_index_range_slice_index)] #![feature(const_inherent_unchecked_arith)] #![feature(const_int_unchecked_arith)] -#![feature(const_intoiterator_identity)] #![feature(const_intrinsic_forget)] #![feature(const_ipv4)] #![feature(const_ipv6)] -#![feature(const_iter)] #![feature(const_likely)] #![feature(const_maybe_uninit_uninit_array)] #![feature(const_maybe_uninit_as_mut_ptr)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 74e9c55396d1..62064f1aa6cb 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -879,7 +879,7 @@ pub trait Tuple {} #[unstable(feature = "pointer_like_trait", issue = "none")] #[lang = "pointer_like"] #[rustc_on_unimplemented( - message = "`{Self}` needs to have the same alignment and size as a pointer", + message = "`{Self}` needs to have the same ABI as a pointer", label = "`{Self}` needs to be a pointer-like type" )] pub trait PointerLike {} diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 3f491836551d..9c6d48675a6b 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1241,13 +1241,9 @@ impl MaybeUninit { /// ``` #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] pub fn slice_as_bytes(this: &[MaybeUninit]) -> &[MaybeUninit] { + let bytes = mem::size_of_val(this); // SAFETY: MaybeUninit is always valid, even for padding bytes - unsafe { - slice::from_raw_parts( - this.as_ptr() as *const MaybeUninit, - this.len() * mem::size_of::(), - ) - } + unsafe { slice::from_raw_parts(this.as_ptr() as *const MaybeUninit, bytes) } } /// Returns the contents of this mutable slice of `MaybeUninit` as a mutable slice of @@ -1274,13 +1270,9 @@ impl MaybeUninit { /// ``` #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] pub fn slice_as_bytes_mut(this: &mut [MaybeUninit]) -> &mut [MaybeUninit] { + let bytes = mem::size_of_val(this); // SAFETY: MaybeUninit is always valid, even for padding bytes - unsafe { - slice::from_raw_parts_mut( - this.as_mut_ptr() as *mut MaybeUninit, - this.len() * mem::size_of::(), - ) - } + unsafe { slice::from_raw_parts_mut(this.as_mut_ptr() as *mut MaybeUninit, bytes) } } } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 06d22d84aedc..ecfb735fad14 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -34,6 +34,13 @@ macro_rules! nonzero_integers { /// use std::mem::size_of; #[doc = concat!("assert_eq!(size_of::>(), size_of::<", stringify!($Int), ">());")] /// ``` + /// + /// # Layout + /// + #[doc = concat!("`", stringify!($Ty), "` is guaranteed to have the same layout and bit validity as `", stringify!($Int), "`")] + /// with the exception that `0` is not a valid instance. + #[doc = concat!("`Option<", stringify!($Ty), ">` is guaranteed to be compatible with `", stringify!($Int), "`,")] + /// including in FFI. #[$stability] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(transparent)] diff --git a/library/core/src/num/shells/u16.rs b/library/core/src/num/shells/u16.rs index b203806f4600..7394977e5078 100644 --- a/library/core/src/num/shells/u16.rs +++ b/library/core/src/num/shells/u16.rs @@ -1,4 +1,4 @@ -//! Redundant constants module for the [`i16` primitive type][i16]. +//! Redundant constants module for the [`u16` primitive type][u16]. //! //! New code should use the associated constants directly on the primitive type. diff --git a/library/core/src/option.rs b/library/core/src/option.rs index fcf9707b74d4..057053297cd2 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -605,8 +605,6 @@ impl Option { /// # Examples /// /// ``` - /// #![feature(is_some_and)] - /// /// let x: Option = Some(2); /// assert_eq!(x.is_some_and(|x| x > 1), true); /// @@ -618,7 +616,7 @@ impl Option { /// ``` #[must_use] #[inline] - #[unstable(feature = "is_some_and", issue = "93050")] + #[stable(feature = "is_some_and", since = "CURRENT_RUSTC_VERSION")] pub fn is_some_and(self, f: impl FnOnce(T) -> bool) -> bool { match self { None => false, diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index bf8339335dd7..51e6947a9c25 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1362,6 +1362,7 @@ mod prim_usize {} /// * [`Hash`] /// * [`ToSocketAddrs`] /// * [`Send`] \(`&T` references also require T: [Sync]) +/// * [`Sync`] /// /// [`std::fmt`]: fmt /// [`Hash`]: hash::Hash diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 76d9b0385d0f..241602c0e18f 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -545,8 +545,6 @@ impl Result { /// # Examples /// /// ``` - /// #![feature(is_some_and)] - /// /// let x: Result = Ok(2); /// assert_eq!(x.is_ok_and(|x| x > 1), true); /// @@ -558,7 +556,7 @@ impl Result { /// ``` #[must_use] #[inline] - #[unstable(feature = "is_some_and", issue = "93050")] + #[stable(feature = "is_some_and", since = "CURRENT_RUSTC_VERSION")] pub fn is_ok_and(self, f: impl FnOnce(T) -> bool) -> bool { match self { Err(_) => false, @@ -590,7 +588,6 @@ impl Result { /// # Examples /// /// ``` - /// #![feature(is_some_and)] /// use std::io::{Error, ErrorKind}; /// /// let x: Result = Err(Error::new(ErrorKind::NotFound, "!")); @@ -604,7 +601,7 @@ impl Result { /// ``` #[must_use] #[inline] - #[unstable(feature = "is_some_and", issue = "93050")] + #[stable(feature = "is_some_and", since = "CURRENT_RUSTC_VERSION")] pub fn is_err_and(self, f: impl FnOnce(E) -> bool) -> bool { match self { Ok(_) => false, diff --git a/library/core/tests/iter/consts.rs b/library/core/tests/iter/consts.rs deleted file mode 100644 index d56687e48c96..000000000000 --- a/library/core/tests/iter/consts.rs +++ /dev/null @@ -1,36 +0,0 @@ -#[test] -fn const_manual_iter() { - struct S(bool); - - impl const Iterator for S { - type Item = (); - - fn next(&mut self) -> Option { - if self.0 == false { - self.0 = true; - Some(()) - } else { - None - } - } - } - const { - let mut val = S(false); - assert!(val.next().is_some()); - assert!(val.next().is_none()); - assert!(val.next().is_none()); - } -} - -#[test] -fn const_range() { - const { - let mut arr = [0; 3]; - for i in 0..arr.len() { - arr[i] = i; - } - assert!(arr[0] == 0); - assert!(arr[1] == 1); - assert!(arr[2] == 2); - } -} diff --git a/library/core/tests/iter/mod.rs b/library/core/tests/iter/mod.rs index cbb18e79e2d4..770b6f7601fa 100644 --- a/library/core/tests/iter/mod.rs +++ b/library/core/tests/iter/mod.rs @@ -20,8 +20,6 @@ mod range; mod sources; mod traits; -mod consts; - use core::cell::Cell; use core::convert::TryFrom; use core::iter::*; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 344f0b61754e..6cdafa411d00 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -12,11 +12,8 @@ #![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_convert)] -#![feature(const_for)] #![feature(const_hash)] #![feature(const_heap)] -#![feature(const_intoiterator_identity)] -#![feature(const_iter)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_assume_init_read)] #![feature(const_nonnull_new)] diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs index ae2baba09e68..575f56ff4df2 100644 --- a/library/std/src/collections/mod.rs +++ b/library/std/src/collections/mod.rs @@ -416,8 +416,10 @@ pub use alloc_crate::collections::{BTreeMap, BTreeSet, BinaryHeap}; pub use alloc_crate::collections::{LinkedList, VecDeque}; #[stable(feature = "rust1", since = "1.0.0")] +#[doc(inline)] pub use self::hash_map::HashMap; #[stable(feature = "rust1", since = "1.0.0")] +#[doc(inline)] pub use self::hash_set::HashSet; #[stable(feature = "try_reserve", since = "1.57.0")] diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 6acb937e7847..14c455d4fa3c 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -339,7 +339,7 @@ impl BufWriter { let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) }; // SAFETY: forget(self) prevents double dropping inner - let inner = unsafe { ptr::read(&mut self.inner) }; + let inner = unsafe { ptr::read(&self.inner) }; mem::forget(self); (inner, buf) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 8c118b95b0a7..736b3c0497c4 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -289,7 +289,6 @@ #![feature(hashmap_internals)] #![feature(ip)] #![feature(ip_in_core)] -#![feature(is_some_and)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_write_slice)] #![feature(panic_can_unwind)] diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 3982d3636614..4b42ad65ee6b 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -869,7 +869,7 @@ impl TcpListener { /// use std::net::{TcpListener, TcpStream}; /// /// fn listen_on(port: u16) -> impl Iterator { - /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); + /// let listener = TcpListener::bind(("127.0.0.1", port)).unwrap(); /// listener.into_incoming() /// .filter_map(Result::ok) /* Ignore failed connections */ /// } diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index bf8339335dd7..51e6947a9c25 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -1362,6 +1362,7 @@ mod prim_usize {} /// * [`Hash`] /// * [`ToSocketAddrs`] /// * [`Send`] \(`&T` references also require T: [Sync]) +/// * [`Sync`] /// /// [`std::fmt`]: fmt /// [`Hash`]: hash::Hash diff --git a/library/std/src/sys/common/thread_local/os_local.rs b/library/std/src/sys/common/thread_local/os_local.rs index ce74ad3486e1..1442a397e767 100644 --- a/library/std/src/sys/common/thread_local/os_local.rs +++ b/library/std/src/sys/common/thread_local/os_local.rs @@ -49,7 +49,9 @@ macro_rules! __thread_local_inner { #[inline] fn __init() -> $t { $init } - #[cfg_attr(not(bootstrap), inline)] + // `#[inline] does not work on windows-gnu due to linking errors around dllimports. + // See https://github.com/rust-lang/rust/issues/109797. + #[cfg_attr(not(windows), inline)] unsafe fn __getit( init: $crate::option::Option<&mut $crate::option::Option<$t>>, ) -> $crate::option::Option<&'static $t> { diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 373157bd9e83..956db577d537 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -1403,24 +1403,40 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> { opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS); let f = File::open(junction, &opts)?; let h = f.as_inner().as_raw_handle(); - unsafe { let mut data = Align8([MaybeUninit::::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); let data_ptr = data.0.as_mut_ptr(); + let data_end = data_ptr.add(c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE); let db = data_ptr.cast::(); // Zero the header to ensure it's fully initialized, including reserved parameters. *db = mem::zeroed(); - let buf = ptr::addr_of_mut!((*db).ReparseTarget).cast::(); - let mut i = 0; + let reparse_target_slice = { + let buf_start = ptr::addr_of_mut!((*db).ReparseTarget).cast::(); + // Compute offset in bytes and then divide so that we round down + // rather than hit any UB (admittedly this arithmetic should work + // out so that this isn't necessary) + let buf_len_bytes = usize::try_from(data_end.byte_offset_from(buf_start)).unwrap(); + let buf_len_wchars = buf_len_bytes / core::mem::size_of::(); + core::slice::from_raw_parts_mut(buf_start, buf_len_wchars) + }; + // FIXME: this conversion is very hacky - let v = br"\??\"; - let v = v.iter().map(|x| *x as u16); - for c in v.chain(original.as_os_str().encode_wide()) { - *buf.add(i) = c; + let iter = br"\??\" + .iter() + .map(|x| *x as u16) + .chain(original.as_os_str().encode_wide()) + .chain(core::iter::once(0)); + let mut i = 0; + for c in iter { + if i >= reparse_target_slice.len() { + return Err(crate::io::const_io_error!( + crate::io::ErrorKind::InvalidFilename, + "Input filename is too long" + )); + } + reparse_target_slice[i] = c; i += 1; } - *buf.add(i) = 0; - i += 1; (*db).ReparseTag = c::IO_REPARSE_TAG_MOUNT_POINT; (*db).ReparseTargetMaximumLength = (i * 2) as c::WORD; (*db).ReparseTargetLength = ((i - 1) * 2) as c::WORD; diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md index 654e03d0c3c7..74dd22df9e06 100644 --- a/src/bootstrap/CHANGELOG.md +++ b/src/bootstrap/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - `remote-test-server`'s `remote` argument has been removed in favor of the `--bind` flag. Use `--bind 0.0.0.0:12345` to replicate the behavior of the `remote` argument. - `x.py fmt` now formats only files modified between the merge-base of HEAD and the last commit in the master branch of the rust-lang repository and the current working directory. To restore old behaviour, use `x.py fmt .`. The check mode is not affected by this change. [#105702](https://github.com/rust-lang/rust/pull/105702) - The `llvm.version-check` config option has been removed. Older versions were never supported. If you still need to support older versions (e.g. you are applying custom patches), patch `check_llvm_version` in bootstrap to change the minimum version. [#108619](https://github.com/rust-lang/rust/pull/108619) +- The `rust.ignore-git` option has been renamed to `rust.omit-git-hash`. [#110059](https://github.com/rust-lang/rust/pull/110059) ### Non-breaking changes diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 965dfa5f3986..a158d1f718e2 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -45,6 +45,7 @@ dependencies = [ "hex", "ignore", "is-terminal", + "junction", "libc", "object", "once_cell", @@ -349,6 +350,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +[[package]] +name = "junction" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca39ef0d69b18e6a2fd14c2f0a1d593200f4a4ed949b240b5917ab51fac754cb" +dependencies = [ + "scopeguard", + "winapi", +] + [[package]] name = "lazy_static" version = "1.4.0" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 2fbe7aa57aa5..eeda6d7c121f 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -61,6 +61,9 @@ sysinfo = { version = "0.26.0", optional = true } [target.'cfg(not(target_os = "solaris"))'.dependencies] fd-lock = "3.0.8" +[target.'cfg(windows)'.dependencies.junction] +version = "1.0.0" + [target.'cfg(windows)'.dependencies.windows] version = "0.46.0" features = [ diff --git a/src/bootstrap/bolt.rs b/src/bootstrap/bolt.rs index 973dc4f602b2..10e6d2e7d6d0 100644 --- a/src/bootstrap/bolt.rs +++ b/src/bootstrap/bolt.rs @@ -45,8 +45,6 @@ pub fn optimize_with_bolt(path: &Path, profile_path: &Path, output_path: &Path) .arg("-split-all-cold") // Move jump tables to a separate section .arg("-jump-tables=move") - // Use GNU_STACK program header for new segment (workaround for issues with strip/objcopy) - .arg("-use-gnu-stack") // Fold functions with identical code .arg("-icf=1") // Update DWARF debug info in the final binary diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 4d528a767e43..ade8fa4c74dc 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -4,8 +4,9 @@ use std::collections::BTreeSet; use std::env; use std::ffi::OsStr; use std::fmt::{Debug, Write}; -use std::fs::{self}; +use std::fs::{self, File}; use std::hash::Hash; +use std::io::{BufRead, BufReader}; use std::ops::Deref; use std::path::{Component, Path, PathBuf}; use std::process::Command; @@ -28,8 +29,11 @@ use crate::{clean, dist}; use crate::{Build, CLang, DocTests, GitRepo, Mode}; pub use crate::Compiler; -// FIXME: replace with std::lazy after it gets stabilized and reaches beta -use once_cell::sync::Lazy; +// FIXME: +// - use std::lazy for `Lazy` +// - use std::cell for `OnceCell` +// Once they get stabilized and reach beta. +use once_cell::sync::{Lazy, OnceCell}; pub struct Builder<'a> { pub build: &'a Build, @@ -484,17 +488,43 @@ impl<'a> ShouldRun<'a> { // multiple aliases for the same job pub fn paths(mut self, paths: &[&str]) -> Self { + static SUBMODULES_PATHS: OnceCell> = OnceCell::new(); + + let init_submodules_paths = |src: &PathBuf| { + let file = File::open(src.join(".gitmodules")).unwrap(); + + let mut submodules_paths = vec![]; + for line in BufReader::new(file).lines() { + if let Ok(line) = line { + let line = line.trim(); + + if line.starts_with("path") { + let actual_path = + line.split(' ').last().expect("Couldn't get value of path"); + submodules_paths.push(actual_path.to_owned()); + } + } + } + + submodules_paths + }; + + let submodules_paths = + SUBMODULES_PATHS.get_or_init(|| init_submodules_paths(&self.builder.src)); + self.paths.insert(PathSet::Set( paths .iter() .map(|p| { - // FIXME(#96188): make sure this is actually a path. - // This currently breaks for paths within submodules. - //assert!( - // self.builder.src.join(p).exists(), - // "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}", - // p - //); + // assert only if `p` isn't submodule + if !submodules_paths.iter().find(|sm_p| p.contains(*sm_p)).is_some() { + assert!( + self.builder.src.join(p).exists(), + "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}", + p + ); + } + TaskPath { path: p.into(), kind: Some(self.kind) } }) .collect(), diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index eae81b9fc69c..390047f6fdce 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -19,7 +19,7 @@ pub enum GitInfo { #[default] Absent, /// This is a git repository. - /// If the info should be used (`ignore_git` is false), this will be + /// If the info should be used (`omit_git_hash` is false), this will be /// `Some`, otherwise it will be `None`. Present(Option), /// This is not a git repostory, but the info can be fetched from the @@ -35,7 +35,7 @@ pub struct Info { } impl GitInfo { - pub fn new(ignore_git: bool, dir: &Path) -> GitInfo { + pub fn new(omit_git_hash: bool, dir: &Path) -> GitInfo { // See if this even begins to look like a git dir if !dir.join(".git").exists() { match read_commit_info_file(dir) { @@ -52,7 +52,7 @@ impl GitInfo { // If we're ignoring the git info, we don't actually need to collect it, just make sure this // was a git repo in the first place. - if ignore_git { + if omit_git_hash { return GitInfo::Present(None); } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index cd19667139ab..f9387a0fc80b 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -271,9 +271,17 @@ impl Step for Rustc { false, ); - let libdir = builder.sysroot_libdir(compiler, target); - let hostdir = builder.sysroot_libdir(compiler, compiler.host); - add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target)); + // HACK: This avoids putting the newly built artifacts in the sysroot if we're using + // `download-rustc`, to avoid "multiple candidates for `rmeta`" errors. Technically, that's + // not quite right: people can set `download-rustc = true` to download even if there are + // changes to the compiler, and in that case ideally we would put the *new* artifacts in the + // sysroot, in case there are API changes that should be used by tools. In practice, + // though, that should be very uncommon, and people can still disable download-rustc. + if !builder.download_rustc() { + let libdir = builder.sysroot_libdir(compiler, target); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target)); + } } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index b8b6b7b2d4e9..dd65dc91c0cd 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -77,7 +77,7 @@ pub struct Config { pub tools: Option>, pub sanitizers: bool, pub profiler: bool, - pub ignore_git: bool, + pub omit_git_hash: bool, pub exclude: Vec, pub include_default_paths: bool, pub rustc_error_format: Option, @@ -227,25 +227,34 @@ pub struct Config { pub reuse: Option, pub cargo_native_static: bool, pub configure_args: Vec, + pub out: PathBuf, + pub rust_info: channel::GitInfo, // These are either the stage0 downloaded binaries or the locally installed ones. pub initial_cargo: PathBuf, pub initial_rustc: PathBuf, + #[cfg(not(test))] initial_rustfmt: RefCell, #[cfg(test)] pub initial_rustfmt: RefCell, - pub out: PathBuf, - pub rust_info: channel::GitInfo, } #[derive(Default, Deserialize)] #[cfg_attr(test, derive(Clone))] pub struct Stage0Metadata { + pub compiler: CompilerMetadata, pub config: Stage0Config, pub checksums_sha256: HashMap, pub rustfmt: Option, } +#[derive(Default, Deserialize)] +#[cfg_attr(test, derive(Clone))] +pub struct CompilerMetadata { + pub date: String, + pub version: String, +} + #[derive(Default, Deserialize)] #[cfg_attr(test, derive(Clone))] pub struct Stage0Config { @@ -755,7 +764,7 @@ define_config! { verbose_tests: Option = "verbose-tests", optimize_tests: Option = "optimize-tests", codegen_tests: Option = "codegen-tests", - ignore_git: Option = "ignore-git", + omit_git_hash: Option = "omit-git-hash", dist_src: Option = "dist-src", save_toolstates: Option = "save-toolstates", codegen_backends: Option> = "codegen-backends", @@ -1000,10 +1009,10 @@ impl Config { config.out = crate::util::absolute(&config.out); } - config.initial_rustc = build - .rustc - .map(PathBuf::from) - .unwrap_or_else(|| config.out.join(config.build.triple).join("stage0/bin/rustc")); + config.initial_rustc = build.rustc.map(PathBuf::from).unwrap_or_else(|| { + config.download_beta_toolchain(); + config.out.join(config.build.triple).join("stage0/bin/rustc") + }); config.initial_cargo = build .cargo .map(PathBuf::from) @@ -1088,7 +1097,7 @@ impl Config { let mut debuginfo_level_tools = None; let mut debuginfo_level_tests = None; let mut optimize = None; - let mut ignore_git = None; + let mut omit_git_hash = None; if let Some(rust) = toml.rust { debug = rust.debug; @@ -1109,7 +1118,7 @@ impl Config { .map(|v| v.expect("invalid value for rust.split_debuginfo")) .unwrap_or(SplitDebuginfo::default_for_platform(&config.build.triple)); optimize = rust.optimize; - ignore_git = rust.ignore_git; + omit_git_hash = rust.omit_git_hash; config.rust_new_symbol_mangling = rust.new_symbol_mangling; set(&mut config.rust_optimize_tests, rust.optimize_tests); set(&mut config.codegen_tests, rust.codegen_tests); @@ -1166,8 +1175,8 @@ impl Config { // rust_info must be set before is_ci_llvm_available() is called. let default = config.channel == "dev"; - config.ignore_git = ignore_git.unwrap_or(default); - config.rust_info = GitInfo::new(config.ignore_git, &config.src); + config.omit_git_hash = omit_git_hash.unwrap_or(default); + config.rust_info = GitInfo::new(config.omit_git_hash, &config.src); if let Some(llvm) = toml.llvm { match llvm.ccache { diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs index 5cea143e0a78..50569eb4f373 100644 --- a/src/bootstrap/config/tests.rs +++ b/src/bootstrap/config/tests.rs @@ -33,35 +33,58 @@ fn download_ci_llvm() { )); } +// FIXME(ozkanonur): extend scope of the test +// refs: +// - https://github.com/rust-lang/rust/issues/109120 +// - https://github.com/rust-lang/rust/pull/109162#issuecomment-1496782487 #[test] fn detect_src_and_out() { - let cfg = parse(""); + fn test(cfg: Config, build_dir: Option<&str>) { + // This will bring absolute form of `src/bootstrap` path + let current_dir = std::env::current_dir().unwrap(); - // This will bring absolute form of `src/bootstrap` path - let current_dir = std::env::current_dir().unwrap(); + // get `src` by moving into project root path + let expected_src = current_dir.ancestors().nth(2).unwrap(); + assert_eq!(&cfg.src, expected_src); - // get `src` by moving into project root path - let expected_src = current_dir.ancestors().nth(2).unwrap(); + // Sanity check for `src` + let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); + let expected_src = manifest_dir.ancestors().nth(2).unwrap(); + assert_eq!(&cfg.src, expected_src); - assert_eq!(&cfg.src, expected_src); + // test if build-dir was manually given in config.toml + if let Some(custom_build_dir) = build_dir { + assert_eq!(&cfg.out, Path::new(custom_build_dir)); + } + // test the native bootstrap way + else { + // This should bring output path of bootstrap in absolute form + let cargo_target_dir = env::var_os("CARGO_TARGET_DIR").expect( + "CARGO_TARGET_DIR must been provided for the test environment from bootstrap", + ); - // This should bring output path of bootstrap in absolute form - let cargo_target_dir = env::var_os("CARGO_TARGET_DIR") - .expect("CARGO_TARGET_DIR must been provided for the test environment from bootstrap"); + // Move to `build` from `build/bootstrap` + let expected_out = Path::new(&cargo_target_dir).parent().unwrap(); + assert_eq!(&cfg.out, expected_out); - // Move to `build` from `build/bootstrap` - let expected_out = Path::new(&cargo_target_dir).parent().unwrap(); - assert_eq!(&cfg.out, expected_out); + let args: Vec = env::args().collect(); - let args: Vec = env::args().collect(); + // Another test for `out` as a sanity check + // + // This will bring something similar to: + // `{build-dir}/bootstrap/debug/deps/bootstrap-c7ee91d5661e2804` + // `{build-dir}` can be anywhere, not just in the rust project directory. + let dep = Path::new(args.first().unwrap()); + let expected_out = dep.ancestors().nth(4).unwrap(); - // Another test for `out` as a sanity check - // - // This will bring something similar to: - // `{config_toml_place}/build/bootstrap/debug/deps/bootstrap-c7ee91d5661e2804` - // `{config_toml_place}` can be anywhere, not just in the rust project directory. - let dep = Path::new(args.first().unwrap()); - let expected_out = dep.ancestors().nth(4).unwrap(); + assert_eq!(&cfg.out, expected_out); + } + } - assert_eq!(&cfg.out, expected_out); + test(parse(""), None); + + { + let build_dir = if cfg!(windows) { Some("C:\\tmp") } else { Some("/tmp") }; + test(parse("build.build-dir = \"/tmp\""), build_dir); + } } diff --git a/src/bootstrap/defaults/config.codegen.toml b/src/bootstrap/defaults/config.codegen.toml index 20b2699c761b..113df88d7c34 100644 --- a/src/bootstrap/defaults/config.codegen.toml +++ b/src/bootstrap/defaults/config.codegen.toml @@ -9,6 +9,8 @@ compiler-docs = true assertions = true # enable warnings during the llvm compilation enable-warnings = true +# build llvm from source +download-ci-llvm = false [rust] # This enables `RUSTC_LOG=debug`, avoiding confusing situations diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 2ce54d9a3b43..8ce220c86478 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1488,7 +1488,7 @@ impl Step for Extended { let xform = |p: &Path| { let mut contents = t!(fs::read_to_string(p)); - for tool in &["rust-demangler", "miri"] { + for tool in &["rust-demangler", "miri", "rust-docs"] { if !built_tools.contains(tool) { contents = filter(&contents, tool); } @@ -1585,11 +1585,10 @@ impl Step for Extended { prepare("rustc"); prepare("cargo"); prepare("rust-analysis"); - prepare("rust-docs"); prepare("rust-std"); prepare("clippy"); prepare("rust-analyzer"); - for tool in &["rust-demangler", "miri"] { + for tool in &["rust-docs", "rust-demangler", "miri"] { if built_tools.contains(tool) { prepare(tool); } @@ -1624,23 +1623,25 @@ impl Step for Extended { .arg("-out") .arg(exe.join("RustcGroup.wxs")), ); - builder.run( - Command::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rust-docs") - .args(&heat_flags) - .arg("-cg") - .arg("DocsGroup") - .arg("-dr") - .arg("Docs") - .arg("-var") - .arg("var.DocsDir") - .arg("-out") - .arg(exe.join("DocsGroup.wxs")) - .arg("-t") - .arg(etc.join("msi/squash-components.xsl")), - ); + if built_tools.contains("rust-docs") { + builder.run( + Command::new(&heat) + .current_dir(&exe) + .arg("dir") + .arg("rust-docs") + .args(&heat_flags) + .arg("-cg") + .arg("DocsGroup") + .arg("-dr") + .arg("Docs") + .arg("-var") + .arg("var.DocsDir") + .arg("-out") + .arg(exe.join("DocsGroup.wxs")) + .arg("-t") + .arg(etc.join("msi/squash-components.xsl")), + ); + } builder.run( Command::new(&heat) .current_dir(&exe) @@ -1787,7 +1788,6 @@ impl Step for Extended { cmd.current_dir(&exe) .arg("-nologo") .arg("-dRustcDir=rustc") - .arg("-dDocsDir=rust-docs") .arg("-dCargoDir=cargo") .arg("-dStdDir=rust-std") .arg("-dAnalysisDir=rust-analysis") @@ -1799,6 +1799,9 @@ impl Step for Extended { .arg(&input); add_env(builder, &mut cmd, target); + if built_tools.contains("rust-docs") { + cmd.arg("-dDocsDir=rust-docs"); + } if built_tools.contains("rust-demangler") { cmd.arg("-dRustDemanglerDir=rust-demangler"); } @@ -1817,7 +1820,9 @@ impl Step for Extended { candle(&etc.join("msi/ui.wxs")); candle(&etc.join("msi/rustwelcomedlg.wxs")); candle("RustcGroup.wxs".as_ref()); - candle("DocsGroup.wxs".as_ref()); + if built_tools.contains("rust-docs") { + candle("DocsGroup.wxs".as_ref()); + } candle("CargoGroup.wxs".as_ref()); candle("StdGroup.wxs".as_ref()); candle("ClippyGroup.wxs".as_ref()); @@ -1854,7 +1859,6 @@ impl Step for Extended { .arg("ui.wixobj") .arg("rustwelcomedlg.wixobj") .arg("RustcGroup.wixobj") - .arg("DocsGroup.wixobj") .arg("CargoGroup.wixobj") .arg("StdGroup.wixobj") .arg("AnalysisGroup.wixobj") @@ -1870,6 +1874,9 @@ impl Step for Extended { if built_tools.contains("rust-demangler") { cmd.arg("RustDemanglerGroup.wixobj"); } + if built_tools.contains("rust-docs") { + cmd.arg("DocsGroup.wixobj"); + } if target.ends_with("windows-gnu") { cmd.arg("GccGroup.wixobj"); diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index 8fbc034965a6..242515565842 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -367,26 +367,70 @@ impl Config { pub(crate) fn download_ci_rustc(&self, commit: &str) { self.verbose(&format!("using downloaded stage2 artifacts from CI (commit {commit})")); + let version = self.artifact_version_part(commit); + // download-rustc doesn't need its own cargo, it can just use beta's. But it does need the + // `rustc_private` crates for tools. + let extra_components = ["rustc-dev"]; + + self.download_toolchain( + &version, + "ci-rustc", + commit, + &extra_components, + Self::download_ci_component, + ); + } + + pub(crate) fn download_beta_toolchain(&self) { + self.verbose(&format!("downloading stage0 beta artifacts")); + + let date = &self.stage0_metadata.compiler.date; + let version = &self.stage0_metadata.compiler.version; + let extra_components = ["cargo"]; + + let download_beta_component = |config: &Config, filename, prefix: &_, date: &_| { + config.download_component(DownloadSource::Dist, filename, prefix, date, "stage0") + }; + + self.download_toolchain( + version, + "stage0", + date, + &extra_components, + download_beta_component, + ); + } + + fn download_toolchain( + &self, + // FIXME(ozkanonur) use CompilerMetadata instead of `version: &str` + version: &str, + sysroot: &str, + stamp_key: &str, + extra_components: &[&str], + download_component: fn(&Config, String, &str, &str), + ) { let host = self.build.triple; - let bin_root = self.out.join(host).join("ci-rustc"); + let bin_root = self.out.join(host).join(sysroot); let rustc_stamp = bin_root.join(".rustc-stamp"); - if !bin_root.join("bin").join("rustc").exists() || program_out_of_date(&rustc_stamp, commit) + if !bin_root.join("bin").join(exe("rustc", self.build)).exists() + || program_out_of_date(&rustc_stamp, stamp_key) { if bin_root.exists() { t!(fs::remove_dir_all(&bin_root)); } let filename = format!("rust-std-{version}-{host}.tar.xz"); let pattern = format!("rust-std-{host}"); - self.download_ci_component(filename, &pattern, commit); + download_component(self, filename, &pattern, stamp_key); let filename = format!("rustc-{version}-{host}.tar.xz"); - self.download_ci_component(filename, "rustc", commit); - // download-rustc doesn't need its own cargo, it can just use beta's. - let filename = format!("rustc-dev-{version}-{host}.tar.xz"); - self.download_ci_component(filename, "rustc-dev", commit); - let filename = format!("rust-src-{version}.tar.xz"); - self.download_ci_component(filename, "rust-src", commit); + download_component(self, filename, "rustc", stamp_key); + + for component in extra_components { + let filename = format!("{component}-{version}-{host}.tar.xz"); + download_component(self, filename, component, stamp_key); + } if self.should_fix_bins_and_dylibs() { self.fix_bin_or_dylib(&bin_root.join("bin").join("rustc")); @@ -403,7 +447,7 @@ impl Config { } } - t!(fs::write(rustc_stamp, commit)); + t!(fs::write(rustc_stamp, stamp_key)); } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index e3f3ab5243e2..5ee18cf64110 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -358,14 +358,14 @@ impl Build { #[cfg(not(unix))] let is_sudo = false; - let ignore_git = config.ignore_git; - let rust_info = channel::GitInfo::new(ignore_git, &src); - let cargo_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/cargo")); + let omit_git_hash = config.omit_git_hash; + let rust_info = channel::GitInfo::new(omit_git_hash, &src); + let cargo_info = channel::GitInfo::new(omit_git_hash, &src.join("src/tools/cargo")); let rust_analyzer_info = - channel::GitInfo::new(ignore_git, &src.join("src/tools/rust-analyzer")); - let clippy_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/clippy")); - let miri_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/miri")); - let rustfmt_info = channel::GitInfo::new(ignore_git, &src.join("src/tools/rustfmt")); + channel::GitInfo::new(omit_git_hash, &src.join("src/tools/rust-analyzer")); + let clippy_info = channel::GitInfo::new(omit_git_hash, &src.join("src/tools/clippy")); + let miri_info = channel::GitInfo::new(omit_git_hash, &src.join("src/tools/miri")); + let rustfmt_info = channel::GitInfo::new(omit_git_hash, &src.join("src/tools/rustfmt")); // we always try to use git for LLVM builds let in_tree_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-project")); @@ -1233,7 +1233,7 @@ impl Build { match &self.config.channel[..] { "stable" => num.to_string(), "beta" => { - if self.rust_info().is_managed_git_subrepository() && !self.config.ignore_git { + if self.rust_info().is_managed_git_subrepository() && !self.config.omit_git_hash { format!("{}-beta.{}", num, self.beta_prerelease_version()) } else { format!("{}-beta", num) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 92a7603a9df6..058ff429e80f 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -694,7 +694,7 @@ impl Step for CompiletestTest { /// Runs `cargo test` for compiletest. fn run(self, builder: &Builder<'_>) { let host = self.host; - let compiler = builder.compiler(0, host); + let compiler = builder.compiler(1, host); // We need `ToolStd` for the locally-built sysroot because // compiletest uses unstable features of the `test` crate. @@ -1133,7 +1133,7 @@ impl Step for Tidy { if builder.config.channel == "dev" || builder.config.channel == "nightly" { builder.info("fmt check"); if builder.initial_rustfmt().is_none() { - let inferred_rustfmt_dir = builder.config.initial_rustc.parent().unwrap(); + let inferred_rustfmt_dir = builder.initial_rustc.parent().unwrap(); eprintln!( "\ error: no `rustfmt` binary found in {PATH} diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 3c9a154da9ab..6a687a7903e0 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -320,7 +320,7 @@ pub fn prepare_tool_cargo( cargo.env("CFG_RELEASE_NUM", &builder.version); cargo.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel()); - let info = GitInfo::new(builder.config.ignore_git, &dir); + let info = GitInfo::new(builder.config.omit_git_hash, &dir); if let Some(sha) = info.sha() { cargo.env("CFG_COMMIT_HASH", sha); } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 9a6aaffe22b2..2e1adbf63bb1 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -146,106 +146,9 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> { fs::symlink(src, dest) } - // Creating a directory junction on windows involves dealing with reparse - // points and the DeviceIoControl function, and this code is a skeleton of - // what can be found here: - // - // http://www.flexhex.com/docs/articles/hard-links.phtml #[cfg(windows)] fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> { - use std::ffi::OsStr; - use std::os::windows::ffi::OsStrExt; - - use windows::{ - core::PCWSTR, - Win32::Foundation::{CloseHandle, HANDLE}, - Win32::Storage::FileSystem::{ - CreateFileW, FILE_ACCESS_FLAGS, FILE_FLAG_BACKUP_SEMANTICS, - FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, - MAXIMUM_REPARSE_DATA_BUFFER_SIZE, OPEN_EXISTING, - }, - Win32::System::Ioctl::FSCTL_SET_REPARSE_POINT, - Win32::System::SystemServices::{GENERIC_WRITE, IO_REPARSE_TAG_MOUNT_POINT}, - Win32::System::IO::DeviceIoControl, - }; - - #[allow(non_snake_case)] - #[repr(C)] - struct REPARSE_MOUNTPOINT_DATA_BUFFER { - ReparseTag: u32, - ReparseDataLength: u32, - Reserved: u16, - ReparseTargetLength: u16, - ReparseTargetMaximumLength: u16, - Reserved1: u16, - ReparseTarget: u16, - } - - fn to_u16s>(s: S) -> io::Result> { - Ok(s.as_ref().encode_wide().chain(Some(0)).collect()) - } - - // We're using low-level APIs to create the junction, and these are more - // picky about paths. For example, forward slashes cannot be used as a - // path separator, so we should try to canonicalize the path first. - let target = fs::canonicalize(target)?; - - fs::create_dir(junction)?; - - let path = to_u16s(junction)?; - - let h = unsafe { - CreateFileW( - PCWSTR(path.as_ptr()), - FILE_ACCESS_FLAGS(GENERIC_WRITE), - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - None, - OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, - HANDLE::default(), - ) - } - .map_err(|_| io::Error::last_os_error())?; - - unsafe { - #[repr(C, align(8))] - struct Align8(T); - let mut data = Align8([0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]); - let db = data.0.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER; - let buf = core::ptr::addr_of_mut!((*db).ReparseTarget) as *mut u16; - let mut i = 0; - // FIXME: this conversion is very hacky - let v = br"\??\"; - let v = v.iter().map(|x| *x as u16); - for c in v.chain(target.as_os_str().encode_wide().skip(4)) { - *buf.offset(i) = c; - i += 1; - } - *buf.offset(i) = 0; - i += 1; - - (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; - (*db).ReparseTargetMaximumLength = (i * 2) as u16; - (*db).ReparseTargetLength = ((i - 1) * 2) as u16; - (*db).ReparseDataLength = ((*db).ReparseTargetLength + 12) as u32; - - let mut ret = 0u32; - DeviceIoControl( - h, - FSCTL_SET_REPARSE_POINT, - Some(db.cast()), - (*db).ReparseDataLength + 8, - None, - 0, - Some(&mut ret), - None, - ) - .ok() - .map_err(|_| io::Error::last_os_error())?; - } - - unsafe { CloseHandle(h) }; - Ok(()) + junction::create(&target, &junction) } } diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile index b5715024a848..34b93be412e5 100644 --- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile @@ -1,8 +1,6 @@ FROM ubuntu:22.04 ARG DEBIAN_FRONTEND=noninteractive -# NOTE: intentionally uses python2 for x.py so we can test it still works. -# validate-toolstate only runs in our CI, so it's ok for it to only support python3. RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ @@ -33,4 +31,6 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ +# NOTE: intentionally uses python2 for x.py so we can test it still works. +# validate-toolstate only runs in our CI, so it's ok for it to only support python3. ENV SCRIPT python2.7 ../x.py test --stage 0 src/tools/tidy tidyselftest diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile index 7e640c49f015..2217e6ee7043 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile @@ -24,6 +24,6 @@ RUN sh /scripts/sccache.sh # We are disabling CI LLVM since distcheck is an offline build. ENV NO_DOWNLOAD_CI_LLVM 1 -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.omit-git-hash=false ENV SCRIPT python3 ../x.py --stage 2 test distcheck ENV DIST_SRC 1 diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index c7f120dafeaf..62347f169a5e 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -71,9 +71,11 @@ If not specified, debug assertions are automatically enabled only if the This flag controls the generation of debug information. It takes one of the following values: -* `0`: no debug info at all (the default). -* `1`: line tables only. -* `2`: full debug info. +* `0` or `none`: no debug info at all (the default). +* `line-directives-only`: line info directives only. For the nvptx* targets this enables [profiling](https://reviews.llvm.org/D46061). For other use cases, `line-tables-only` is the better, more compatible choice. +* `line-tables-only`: line tables only. Generates the minimal amount of debug info for backtraces with filename/line number info, but not anything else, i.e. no variable or function parameter info. +* `1` or `limited`: debug info without type or variable-level information. +* `2` or `full`: full debug info. Note: The [`-g` flag][option-g-debug] is an alias for `-C debuginfo=2`. diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 5c18a38ddab9..67fe2a610c22 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -257,6 +257,7 @@ target | std | host | notes `bpfel-unknown-none` | * | | BPF (little endian) `hexagon-unknown-linux-musl` | ? | | `i386-apple-ios` | ✓ | | 32-bit x86 iOS +[`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX Neutrino 7.0 RTOS | `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+) `i686-pc-windows-msvc` | * | | 32-bit Windows XP support `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 38198fe6c3a0..0d815c9b5980 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -16,10 +16,18 @@ and [Blackberry QNX][BlackBerry]. ## Requirements -Currently, only cross-compilation for QNX Neutrino on AArch64 and x86_64 are supported (little endian). +Currently, the following QNX Neutrino versions and compilation targets are supported: + +| QNX Neutrino Version | Target Architecture | Full support | `no_std` support | +|----------------------|---------------------|:------------:|:----------------:| +| 7.1 | AArch64 | ✓ | ✓ | +| 7.1 | x86_64 | ✓ | ✓ | +| 7.0 | x86 | | ✓ | + Adding other architectures that are supported by QNX Neutrino is possible. -The standard library, including `core` and `alloc` (with default allocator) are supported. +In the table above, 'full support' indicates support for building Rust applications with the full standard library. +'`no_std` support' indicates that only `core` and `alloc` are available. For building or using the Rust toolchain for QNX Neutrino, the [QNX Software Development Platform (SDP)](https://blackberry.qnx.com/en/products/foundation-software/qnx-software-development-platform) @@ -70,7 +78,7 @@ fn panic(_panic: &PanicInfo<'_>) -> ! { pub extern "C" fn rust_eh_personality() {} ``` -The QNX Neutrino support of Rust has been tested with QNX Neutrino 7.1. +The QNX Neutrino support of Rust has been tested with QNX Neutrino 7.0 and 7.1. There are no further known requirements. @@ -80,6 +88,7 @@ For conditional compilation, following QNX Neutrino specific attributes are defi - `target_os` = `"nto"` - `target_env` = `"nto71"` (for QNX Neutrino 7.1) +- `target_env` = `"nto70"` (for QNX Neutrino 7.0) ## Building the target diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 960c1de1782c..ae180439d23d 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -38,6 +38,15 @@ future. Attempting to use these error numbers on stable will result in the code sample being interpreted as plain text. +### `missing_doc_code_examples` lint + +This lint will emit a warning if an item doesn't have a code example in its documentation. +It can be enabled using: + +```rust,ignore (nightly) +#![deny(rustdoc::missing_doc_code_examples)] +``` + ## Extensions to the `#[doc]` attribute These features operate by extending the `#[doc]` attribute, and thus can be caught by the compiler diff --git a/src/doc/rustdoc/src/write-documentation/what-to-include.md b/src/doc/rustdoc/src/write-documentation/what-to-include.md index cf1e6a8d3ca4..16457ed0ff82 100644 --- a/src/doc/rustdoc/src/write-documentation/what-to-include.md +++ b/src/doc/rustdoc/src/write-documentation/what-to-include.md @@ -39,9 +39,7 @@ warning: 1 warning emitted As a library author, adding the lint `#![deny(missing_docs)]` is a great way to ensure the project does not drift away from being documented well, and `#![warn(missing_docs)]` is a good way to move towards comprehensive -documentation. In addition to docs, `#![deny(rustdoc::missing_doc_code_examples)]` -ensures each function contains a usage example. In our example above, the -warning is resolved by adding crate level documentation. +documentation. There are more lints in the upcoming chapter [Lints][rustdoc-lints]. diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index 39238dffa103..6adb3506e646 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -16,18 +16,26 @@ and one for deallocation. A freestanding program that uses the `Box` sugar for dynamic allocations via `malloc` and `free`: ```rust,ignore (libc-is-finicky) -#![feature(lang_items, box_syntax, start, libc, core_intrinsics, rustc_private)] +#![feature(lang_items, start, libc, core_intrinsics, rustc_private, rustc_attrs)] #![no_std] use core::intrinsics; use core::panic::PanicInfo; +use core::ptr::NonNull; extern crate libc; -struct Unique(*mut T); +struct Unique(NonNull); #[lang = "owned_box"] pub struct Box(Unique); +impl Box { + pub fn new(x: T) -> Self { + #[rustc_box] + Box::new(x) + } +} + #[lang = "exchange_malloc"] unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { let p = libc::malloc(size as libc::size_t) as *mut u8; @@ -47,13 +55,13 @@ unsafe fn box_free(ptr: *mut T) { #[start] fn main(_argc: isize, _argv: *const *const u8) -> isize { - let _x = box 1; + let _x = Box::new(1); 0 } #[lang = "eh_personality"] extern fn rust_eh_personality() {} -#[lang = "panic_impl"] extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } } +#[lang = "panic_impl"] extern fn rust_begin_panic(_info: &PanicInfo) -> ! { intrinsics::abort() } #[no_mangle] pub extern fn rust_eh_register_frames () {} #[no_mangle] pub extern fn rust_eh_unregister_frames () {} ``` diff --git a/src/doc/unstable-book/src/language-features/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md index dfbb468d4df9..1fade6ce95b8 100644 --- a/src/doc/unstable-book/src/language-features/plugin.md +++ b/src/doc/unstable-book/src/language-features/plugin.md @@ -37,7 +37,7 @@ additional checks for code style, safety, etc. Now let's write a plugin that warns about any item named `lintme`. ```rust,ignore (requires-stage-2) -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] extern crate rustc_ast; @@ -68,7 +68,7 @@ impl EarlyLintPass for Pass { #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&TEST_LINT]); - reg.lint_store.register_early_pass(|| box Pass); + reg.lint_store.register_early_pass(|| Box::new(Pass)); } ``` diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs index 0aa0784e5445..9f4e4fd0611d 100644 --- a/src/etc/installer/msi/rust.wxs +++ b/src/etc/installer/msi/rust.wxs @@ -167,7 +167,9 @@ + + @@ -209,6 +211,7 @@ + + @@ -256,6 +260,7 @@ + + + + @@ -55,15 +57,19 @@ > + + rustc.pkg cargo.pkg + rust-docs.pkg + rust-std.pkg uninstall.pkg ( BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params } } -/// Get DefId of of an item's user-visible parent. -/// -/// "User-visible" should account for re-exporting and inlining, which is why this function isn't -/// just `tcx.parent(def_id)`. If the provided `path` has more than one path element, the `DefId` -/// of the second-to-last will be given. -/// -/// ```text -/// use crate::foo::Bar; -/// ^^^ DefId of this item will be returned -/// ``` -/// -/// If the provided path has only one item, `tcx.parent(def_id)` will be returned instead. -fn get_path_parent_def_id( - tcx: TyCtxt<'_>, - def_id: DefId, - path: &hir::UsePath<'_>, -) -> Option { - if let [.., parent_segment, _] = &path.segments { - match parent_segment.res { - hir::def::Res::Def(_, parent_def_id) => Some(parent_def_id), - _ if parent_segment.ident.name == kw::Crate => { - // In case the "parent" is the crate, it'll give `Res::Err` so we need to - // circumvent it this way. - Some(tcx.parent(def_id)) - } - _ => None, - } - } else { - // If the path doesn't have a parent, then the parent is the current module. - Some(tcx.parent(def_id)) - } -} - -/// This visitor is used to find an HIR Item based on its `use` path. This doesn't use the ordinary -/// name resolver because it does not walk all the way through a chain of re-exports. -pub(crate) struct OneLevelVisitor<'hir> { - map: rustc_middle::hir::map::Map<'hir>, - pub(crate) item: Option<&'hir hir::Item<'hir>>, - looking_for: Ident, +pub(crate) fn reexport_chain<'tcx>( + tcx: TyCtxt<'tcx>, + import_def_id: LocalDefId, target_def_id: LocalDefId, -} - -impl<'hir> OneLevelVisitor<'hir> { - pub(crate) fn new(map: rustc_middle::hir::map::Map<'hir>, target_def_id: LocalDefId) -> Self { - Self { map, item: None, looking_for: Ident::empty(), target_def_id } - } - - pub(crate) fn find_target( - &mut self, - tcx: TyCtxt<'_>, - def_id: DefId, - path: &hir::UsePath<'_>, - ) -> Option<&'hir hir::Item<'hir>> { - let parent_def_id = get_path_parent_def_id(tcx, def_id, path)?; - let parent = self.map.get_if_local(parent_def_id)?; - - // We get the `Ident` we will be looking for into `item`. - self.looking_for = path.segments[path.segments.len() - 1].ident; - // We reset the `item`. - self.item = None; - - match parent { - hir::Node::Item(parent_item) => { - hir::intravisit::walk_item(self, parent_item); - } - hir::Node::Crate(m) => { - hir::intravisit::walk_mod( - self, - m, - tcx.local_def_id_to_hir_id(parent_def_id.as_local().unwrap()), - ); - } - _ => return None, - } - self.item - } -} - -impl<'hir> hir::intravisit::Visitor<'hir> for OneLevelVisitor<'hir> { - type NestedFilter = rustc_middle::hir::nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.map - } - - fn visit_item(&mut self, item: &'hir hir::Item<'hir>) { - if self.item.is_none() - && item.ident == self.looking_for - && (matches!(item.kind, hir::ItemKind::Use(_, _)) - || item.owner_id.def_id == self.target_def_id) +) -> &'tcx [Reexport] { + for child in tcx.module_reexports(tcx.local_parent(import_def_id)) { + if child.res.opt_def_id() == Some(target_def_id.to_def_id()) + && child.reexport_chain[0].id() == Some(import_def_id.to_def_id()) { - self.item = Some(item); + return &child.reexport_chain; } } + &[] } -/// Because a `Use` item directly links to the imported item, we need to manually go through each -/// import one by one. To do so, we go to the parent item and look for the `Ident` into it. Then, -/// if we found the "end item" (the imported one), we stop there because we don't need its -/// documentation. Otherwise, we repeat the same operation until we find the "end item". +/// Collect attributes from the whole import chain. fn get_all_import_attributes<'hir>( - mut item: &hir::Item<'hir>, cx: &mut DocContext<'hir>, + import_def_id: LocalDefId, target_def_id: LocalDefId, is_inline: bool, - mut prev_import: LocalDefId, ) -> Vec<(Cow<'hir, ast::Attribute>, Option)> { - let mut attributes: Vec<(Cow<'hir, ast::Attribute>, Option)> = Vec::new(); + let mut attrs = Vec::new(); let mut first = true; - let hir_map = cx.tcx.hir(); - let mut visitor = OneLevelVisitor::new(hir_map, target_def_id); - let mut visited = FxHashSet::default(); - - // If the item is an import and has at least a path with two parts, we go into it. - while let hir::ItemKind::Use(path, _) = item.kind && visited.insert(item.hir_id()) { - let import_parent = cx.tcx.opt_local_parent(prev_import).map(|def_id| def_id.to_def_id()); + for def_id in reexport_chain(cx.tcx, import_def_id, target_def_id) + .iter() + .flat_map(|reexport| reexport.id()) + { + let import_attrs = inline::load_attrs(cx, def_id); if first { // This is the "original" reexport so we get all its attributes without filtering them. - attributes = hir_map.attrs(item.hir_id()) - .iter() - .map(|attr| (Cow::Borrowed(attr), import_parent)) - .collect::>(); + attrs = import_attrs.iter().map(|attr| (Cow::Borrowed(attr), Some(def_id))).collect(); first = false; } else { - add_without_unwanted_attributes(&mut attributes, hir_map.attrs(item.hir_id()), is_inline, import_parent); + add_without_unwanted_attributes(&mut attrs, import_attrs, is_inline, Some(def_id)); } - - if let Some(i) = visitor.find_target(cx.tcx, item.owner_id.def_id.to_def_id(), path) { - item = i; - } else { - break; - } - prev_import = item.owner_id.def_id; } - attributes + attrs } fn filter_tokens_from_list( @@ -2375,39 +2279,24 @@ fn clean_maybe_renamed_item<'tcx>( _ => unreachable!("not yet converted"), }; - let attrs = if let Some(import_id) = import_id && - let Some(hir::Node::Item(use_node)) = cx.tcx.hir().find_by_def_id(import_id) - { + let target_attrs = inline::load_attrs(cx, def_id); + let attrs = if let Some(import_id) = import_id { let is_inline = inline::load_attrs(cx, import_id.to_def_id()) .lists(sym::doc) .get_word_attr(sym::inline) .is_some(); - // Then we get all the various imports' attributes. - let mut attrs = get_all_import_attributes( - use_node, - cx, - item.owner_id.def_id, - is_inline, - import_id, - ); - - add_without_unwanted_attributes( - &mut attrs, - inline::load_attrs(cx, def_id), - is_inline, - None - ); + let mut attrs = + get_all_import_attributes(cx, import_id, item.owner_id.def_id, is_inline); + add_without_unwanted_attributes(&mut attrs, target_attrs, is_inline, None); attrs } else { // We only keep the item's attributes. - inline::load_attrs(cx, def_id).iter().map(|attr| (Cow::Borrowed(attr), None)).collect::>() + target_attrs.iter().map(|attr| (Cow::Borrowed(attr), None)).collect() }; let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg); - let attrs = Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| match attr { - Cow::Borrowed(attr) => (*attr, *did), - Cow::Owned(attr) => (attr, *did) - }), false); + let attrs = + Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false); let mut item = Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 0895bb510d48..7a2449cbe9ac 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -136,10 +136,6 @@ impl Buffer { self.into_inner() } - pub(crate) fn is_for_html(&self) -> bool { - self.for_html - } - pub(crate) fn reserve(&mut self, additional: usize) { self.buffer.reserve(additional) } @@ -1142,22 +1138,21 @@ fn fmt_type<'cx>( // the ugliness comes from inlining across crates where // everything comes in as a fully resolved QPath (hard to // look at). - match href(trait_.def_id(), cx) { - Ok((ref url, _, ref path)) if !f.alternate() => { - write!( - f, - "{name}{args}", - url = url, - shortty = ItemType::AssocType, - name = assoc.name, - path = join_with_double_colon(path), - args = assoc.args.print(cx), - )?; - } - _ => write!(f, "{}{:#}", assoc.name, assoc.args.print(cx))?, - } - Ok(()) + if !f.alternate() && let Ok((url, _, path)) = href(trait_.def_id(), cx) { + write!( + f, + "{name}", + shortty = ItemType::AssocType, + name = assoc.name, + path = join_with_double_colon(&path), + ) + } else { + write!(f, "{}", assoc.name) + }?; + + // Carry `f.alternate()` into this display w/o branching manually. + fmt::Display::fmt(&assoc.args.print(cx), f) } } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index d75d03071f89..1e3cd2668506 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -50,6 +50,7 @@ use std::string::ToString; use askama::Template; use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, StabilityLevel}; +use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::Mutability; @@ -69,7 +70,7 @@ use crate::formats::item_type::ItemType; use crate::formats::{AssocItemRender, Impl, RenderMode}; use crate::html::escape::Escape; use crate::html::format::{ - href, join_with_double_colon, print_abi_with_space, print_constness_with_space, + display_fn, href, join_with_double_colon, print_abi_with_space, print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space, Buffer, Ending, HrefError, PrintWithSpace, }; @@ -408,128 +409,134 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String { ) } -fn document( - w: &mut Buffer, - cx: &mut Context<'_>, - item: &clean::Item, - parent: Option<&clean::Item>, +fn document<'a, 'cx: 'a>( + cx: &'a mut Context<'cx>, + item: &'a clean::Item, + parent: Option<&'a clean::Item>, heading_offset: HeadingOffset, -) { +) -> impl fmt::Display + 'a + Captures<'cx> { if let Some(ref name) = item.name { info!("Documenting {}", name); } - document_item_info(cx, item, parent).render_into(w).unwrap(); - if parent.is_none() { - document_full_collapsible(w, item, cx, heading_offset); - } else { - document_full(w, item, cx, heading_offset); - } + + display_fn(move |f| { + document_item_info(cx, item, parent).render_into(f).unwrap(); + if parent.is_none() { + write!(f, "{}", document_full_collapsible(item, cx, heading_offset))?; + } else { + write!(f, "{}", document_full(item, cx, heading_offset))?; + } + Ok(()) + }) } /// Render md_text as markdown. -fn render_markdown( - w: &mut Buffer, - cx: &mut Context<'_>, - md_text: &str, +fn render_markdown<'a, 'cx: 'a>( + cx: &'a mut Context<'cx>, + md_text: &'a str, links: Vec, heading_offset: HeadingOffset, -) { - write!( - w, - "

{}
", - Markdown { - content: md_text, - links: &links, - ids: &mut cx.id_map, - error_codes: cx.shared.codes, - edition: cx.shared.edition(), - playground: &cx.shared.playground, - heading_offset, - } - .into_string() - ) +) -> impl fmt::Display + 'a + Captures<'cx> { + display_fn(move |f| { + write!( + f, + "
{}
", + Markdown { + content: md_text, + links: &links, + ids: &mut cx.id_map, + error_codes: cx.shared.codes, + edition: cx.shared.edition(), + playground: &cx.shared.playground, + heading_offset, + } + .into_string() + ) + }) } /// Writes a documentation block containing only the first paragraph of the documentation. If the /// docs are longer, a "Read more" link is appended to the end. -fn document_short( - w: &mut Buffer, - item: &clean::Item, - cx: &mut Context<'_>, - link: AssocItemLink<'_>, - parent: &clean::Item, +fn document_short<'a, 'cx: 'a>( + item: &'a clean::Item, + cx: &'a mut Context<'cx>, + link: AssocItemLink<'a>, + parent: &'a clean::Item, show_def_docs: bool, -) { - document_item_info(cx, item, Some(parent)).render_into(w).unwrap(); - if !show_def_docs { - return; - } - if let Some(s) = item.doc_value() { - let (mut summary_html, has_more_content) = - MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content(); +) -> impl fmt::Display + 'a + Captures<'cx> { + display_fn(move |f| { + document_item_info(cx, item, Some(parent)).render_into(f).unwrap(); + if !show_def_docs { + return Ok(()); + } + if let Some(s) = item.doc_value() { + let (mut summary_html, has_more_content) = + MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content(); - if has_more_content { - let link = format!(r#" Read more"#, assoc_href_attr(item, link, cx)); + if has_more_content { + let link = format!(r#" Read more"#, assoc_href_attr(item, link, cx)); - if let Some(idx) = summary_html.rfind("

") { - summary_html.insert_str(idx, &link); + if let Some(idx) = summary_html.rfind("

") { + summary_html.insert_str(idx, &link); + } else { + summary_html.push_str(&link); + } + } + + write!(f, "
{}
", summary_html)?; + } + Ok(()) + }) +} + +fn document_full_collapsible<'a, 'cx: 'a>( + item: &'a clean::Item, + cx: &'a mut Context<'cx>, + heading_offset: HeadingOffset, +) -> impl fmt::Display + 'a + Captures<'cx> { + document_full_inner(item, cx, true, heading_offset) +} + +fn document_full<'a, 'cx: 'a>( + item: &'a clean::Item, + cx: &'a mut Context<'cx>, + heading_offset: HeadingOffset, +) -> impl fmt::Display + 'a + Captures<'cx> { + document_full_inner(item, cx, false, heading_offset) +} + +fn document_full_inner<'a, 'cx: 'a>( + item: &'a clean::Item, + cx: &'a mut Context<'cx>, + is_collapsible: bool, + heading_offset: HeadingOffset, +) -> impl fmt::Display + 'a + Captures<'cx> { + display_fn(move |f| { + if let Some(s) = item.collapsed_doc_value() { + debug!("Doc block: =====\n{}\n=====", s); + if is_collapsible { + write!( + f, + "
\ + \ + Expand description\ + {}
", + render_markdown(cx, &s, item.links(cx), heading_offset) + )?; } else { - summary_html.push_str(&link); + write!(f, "{}", render_markdown(cx, &s, item.links(cx), heading_offset))?; } } - write!(w, "
{}
", summary_html,); - } -} + let kind = match &*item.kind { + clean::ItemKind::StrippedItem(box kind) | kind => kind, + }; -fn document_full_collapsible( - w: &mut Buffer, - item: &clean::Item, - cx: &mut Context<'_>, - heading_offset: HeadingOffset, -) { - document_full_inner(w, item, cx, true, heading_offset); -} - -fn document_full( - w: &mut Buffer, - item: &clean::Item, - cx: &mut Context<'_>, - heading_offset: HeadingOffset, -) { - document_full_inner(w, item, cx, false, heading_offset); -} - -fn document_full_inner( - w: &mut Buffer, - item: &clean::Item, - cx: &mut Context<'_>, - is_collapsible: bool, - heading_offset: HeadingOffset, -) { - if let Some(s) = item.collapsed_doc_value() { - debug!("Doc block: =====\n{}\n=====", s); - if is_collapsible { - w.write_str( - "
\ - \ - Expand description\ - ", - ); - render_markdown(w, cx, &s, item.links(cx), heading_offset); - w.write_str("
"); - } else { - render_markdown(w, cx, &s, item.links(cx), heading_offset); + if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind { + render_call_locations(f, cx, item); } - } - - let kind = match &*item.kind { - clean::ItemKind::StrippedItem(box kind) | kind => kind, - }; - - if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind { - render_call_locations(w, cx, item); - } + Ok(()) + }) } #[derive(Template)] @@ -653,7 +660,7 @@ fn short_item_info( // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages). pub(crate) fn render_impls( cx: &mut Context<'_>, - w: &mut Buffer, + mut w: impl Write, impls: &[&Impl], containing_item: &clean::Item, toggle_open_by_default: bool, @@ -665,7 +672,7 @@ pub(crate) fn render_impls( let did = i.trait_did().unwrap(); let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx); let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods); - let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() }; + let mut buffer = Buffer::new(); render_impl( &mut buffer, cx, @@ -686,7 +693,7 @@ pub(crate) fn render_impls( }) .collect::>(); rendered_impls.sort(); - w.write_str(&rendered_impls.join("")); + w.write_str(&rendered_impls.join("")).unwrap(); } /// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item. @@ -842,7 +849,7 @@ fn assoc_method( let (indent, indent_str, end_newline) = if parent == ItemType::Trait { header_len += 4; let indent_str = " "; - render_attributes_in_pre(w, meth, indent_str); + write!(w, "{}", render_attributes_in_pre(meth, indent_str)); (4, indent_str, Ending::NoNewline) } else { render_attributes_in_code(w, meth); @@ -1038,10 +1045,16 @@ fn attributes(it: &clean::Item) -> Vec { // When an attribute is rendered inside a `
` tag, it is formatted using
 // a whitespace prefix and newline.
-fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
-    for a in attributes(it) {
-        writeln!(w, "{}{}", prefix, a);
-    }
+fn render_attributes_in_pre<'a>(
+    it: &'a clean::Item,
+    prefix: &'a str,
+) -> impl fmt::Display + Captures<'a> {
+    crate::html::format::display_fn(move |f| {
+        for a in attributes(it) {
+            writeln!(f, "{}{}", prefix, a)?;
+        }
+        Ok(())
+    })
 }
 
 // When an attribute is rendered inside a  tag, it is formatted using
@@ -1067,61 +1080,68 @@ impl<'a> AssocItemLink<'a> {
     }
 }
 
-fn write_impl_section_heading(w: &mut Buffer, title: &str, id: &str) {
+fn write_impl_section_heading(mut w: impl fmt::Write, title: &str, id: &str) {
     write!(
         w,
         "

\ {title}\ §\

" - ); + ) + .unwrap(); } pub(crate) fn render_all_impls( - w: &mut Buffer, + mut w: impl Write, cx: &mut Context<'_>, containing_item: &clean::Item, concrete: &[&Impl], synthetic: &[&Impl], blanket_impl: &[&Impl], ) { - let mut impls = Buffer::empty_from(w); + let mut impls = Buffer::html(); render_impls(cx, &mut impls, concrete, containing_item, true); let impls = impls.into_inner(); if !impls.is_empty() { - write_impl_section_heading(w, "Trait Implementations", "trait-implementations"); - write!(w, "
{}
", impls); + write_impl_section_heading(&mut w, "Trait Implementations", "trait-implementations"); + write!(w, "
{}
", impls).unwrap(); } if !synthetic.is_empty() { - write_impl_section_heading(w, "Auto Trait Implementations", "synthetic-implementations"); - w.write_str("
"); - render_impls(cx, w, synthetic, containing_item, false); - w.write_str("
"); + write_impl_section_heading( + &mut w, + "Auto Trait Implementations", + "synthetic-implementations", + ); + w.write_str("
").unwrap(); + render_impls(cx, &mut w, synthetic, containing_item, false); + w.write_str("
").unwrap(); } if !blanket_impl.is_empty() { - write_impl_section_heading(w, "Blanket Implementations", "blanket-implementations"); - w.write_str("
"); - render_impls(cx, w, blanket_impl, containing_item, false); - w.write_str("
"); + write_impl_section_heading(&mut w, "Blanket Implementations", "blanket-implementations"); + w.write_str("
").unwrap(); + render_impls(cx, &mut w, blanket_impl, containing_item, false); + w.write_str("
").unwrap(); } } -fn render_assoc_items( - w: &mut Buffer, - cx: &mut Context<'_>, - containing_item: &clean::Item, +fn render_assoc_items<'a, 'cx: 'a>( + cx: &'a mut Context<'cx>, + containing_item: &'a clean::Item, it: DefId, - what: AssocItemRender<'_>, -) { + what: AssocItemRender<'a>, +) -> impl fmt::Display + 'a + Captures<'cx> { let mut derefs = DefIdSet::default(); derefs.insert(it); - render_assoc_items_inner(w, cx, containing_item, it, what, &mut derefs) + display_fn(move |f| { + render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs); + Ok(()) + }) } fn render_assoc_items_inner( - w: &mut Buffer, + mut w: &mut dyn fmt::Write, cx: &mut Context<'_>, containing_item: &clean::Item, it: DefId, @@ -1134,7 +1154,7 @@ fn render_assoc_items_inner( let Some(v) = cache.impls.get(&it) else { return }; let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { - let mut tmp_buf = Buffer::empty_from(w); + let mut tmp_buf = Buffer::html(); let (render_mode, id) = match what { AssocItemRender::All => { write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations"); @@ -1158,7 +1178,7 @@ fn render_assoc_items_inner( (RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id)) } }; - let mut impls_buf = Buffer::empty_from(w); + let mut impls_buf = Buffer::html(); for i in &non_trait { render_impl( &mut impls_buf, @@ -1178,10 +1198,10 @@ fn render_assoc_items_inner( ); } if !impls_buf.is_empty() { - w.push_buffer(tmp_buf); - write!(w, "
", id); - w.push_buffer(impls_buf); - w.write_str("
"); + write!(w, "{}", tmp_buf.into_inner()).unwrap(); + write!(w, "
", id).unwrap(); + write!(w, "{}", impls_buf.into_inner()).unwrap(); + w.write_str("
").unwrap(); } } @@ -1191,7 +1211,7 @@ fn render_assoc_items_inner( if let Some(impl_) = deref_impl { let has_deref_mut = traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait()); - render_deref_methods(w, cx, impl_, containing_item, has_deref_mut, derefs); + render_deref_methods(&mut w, cx, impl_, containing_item, has_deref_mut, derefs); } // If we were already one level into rendering deref methods, we don't want to render @@ -1210,7 +1230,7 @@ fn render_assoc_items_inner( } fn render_deref_methods( - w: &mut Buffer, + mut w: impl Write, cx: &mut Context<'_>, impl_: &Impl, container_item: &clean::Item, @@ -1242,10 +1262,10 @@ fn render_deref_methods( return; } } - render_assoc_items_inner(w, cx, container_item, did, what, derefs); + render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs); } else if let Some(prim) = target.primitive_type() { if let Some(&did) = cache.primitive_locations.get(&prim) { - render_assoc_items_inner(w, cx, container_item, did, what, derefs); + render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs); } } } @@ -1478,18 +1498,25 @@ fn render_impl( document_item_info(cx, it, Some(parent)) .render_into(&mut info_buffer) .unwrap(); - document_full(&mut doc_buffer, item, cx, HeadingOffset::H5); + write!( + &mut doc_buffer, + "{}", + document_full(item, cx, HeadingOffset::H5) + ); short_documented = false; } else { // In case the item isn't documented, // provide short documentation from the trait. - document_short( + write!( &mut doc_buffer, - it, - cx, - link, - parent, - rendering_params.show_def_docs, + "{}", + document_short( + it, + cx, + link, + parent, + rendering_params.show_def_docs, + ) ); } } @@ -1498,18 +1525,15 @@ fn render_impl( .render_into(&mut info_buffer) .unwrap(); if rendering_params.show_def_docs { - document_full(&mut doc_buffer, item, cx, HeadingOffset::H5); + write!(&mut doc_buffer, "{}", document_full(item, cx, HeadingOffset::H5)); short_documented = false; } } } else { - document_short( + write!( &mut doc_buffer, - item, - cx, - link, - parent, - rendering_params.show_def_docs, + "{}", + document_short(item, cx, link, parent, rendering_params.show_def_docs,) ); } } @@ -2206,7 +2230,7 @@ const MAX_FULL_EXAMPLES: usize = 5; const NUM_VISIBLE_LINES: usize = 10; /// Generates the HTML for example call locations generated via the --scrape-examples flag. -fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item) { +fn render_call_locations(mut w: W, cx: &mut Context<'_>, item: &clean::Item) { let tcx = cx.tcx(); let def_id = item.item_id.expect_def_id(); let key = tcx.def_path_hash(def_id); @@ -2215,7 +2239,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite // Generate a unique ID so users can link to this section for a given method let id = cx.id_map.derive("scraped-examples"); write!( - w, + &mut w, "
\ \
\ @@ -2224,7 +2248,8 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
", root_path = cx.root_path(), id = id - ); + ) + .unwrap(); // Create a URL to a particular location in a reverse-dependency's source file let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) { @@ -2242,7 +2267,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite }; // Generate the HTML for a single example, being the title and code block - let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool { + let write_example = |mut w: &mut W, (path, call_data): (&PathBuf, &CallData)| -> bool { let contents = match fs::read_to_string(&path) { Ok(contents) => contents, Err(err) => { @@ -2290,7 +2315,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite let locations_encoded = serde_json::to_string(&line_ranges).unwrap(); write!( - w, + &mut w, "
\
\ {name} ({title})\ @@ -2303,10 +2328,12 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite // The locations are encoded as a data attribute, so they can be read // later by the JS for interactions. locations = Escape(&locations_encoded) - ); + ) + .unwrap(); if line_ranges.len() > 1 { - write!(w, r#" "#); + write!(w, r#" "#) + .unwrap(); } // Look for the example file in the source map if it exists, otherwise return a dummy span @@ -2333,7 +2360,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite decoration_info.insert("highlight", byte_ranges); sources::print_src( - w, + &mut w, contents_subset, file_span, cx, @@ -2341,7 +2368,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite highlight::DecorationInfo(decoration_info), sources::SourceContext::Embedded { offset: line_min, needs_expansion }, ); - write!(w, "
"); + write!(w, "
").unwrap(); true }; @@ -2375,7 +2402,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite // An example may fail to write if its source can't be read for some reason, so this method // continues iterating until a write succeeds - let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| { + let write_and_skip_failure = |w: &mut W, it: &mut Peekable<_>| { while let Some(example) = it.next() { if write_example(&mut *w, example) { break; @@ -2384,7 +2411,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite }; // Write just one example that's visible by default in the method's description. - write_and_skip_failure(w, &mut it); + write_and_skip_failure(&mut w, &mut it); // Then add the remaining examples in a hidden section. if it.peek().is_some() { @@ -2397,17 +2424,19 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
Hide additional examples
\
\
" - ); + ) + .unwrap(); // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could // make the page arbitrarily huge! for _ in 0..MAX_FULL_EXAMPLES { - write_and_skip_failure(w, &mut it); + write_and_skip_failure(&mut w, &mut it); } // For the remaining examples, generate a
    containing links to the source files. if it.peek().is_some() { - write!(w, r#"").unwrap(); } - write!(w, "
"); + write!(w, "").unwrap(); } - write!(w, ""); + write!(w, "").unwrap(); } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 674cd0d62d49..6bce57340040 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -202,7 +202,7 @@ fn should_hide_fields(n_fields: usize) -> bool { n_fields > 12 } -fn toggle_open(w: &mut Buffer, text: impl fmt::Display) { +fn toggle_open(mut w: impl fmt::Write, text: impl fmt::Display) { write!( w, "
\ @@ -210,15 +210,16 @@ fn toggle_open(w: &mut Buffer, text: impl fmt::Display) { Show {}\ ", text - ); + ) + .unwrap(); } -fn toggle_close(w: &mut Buffer) { - w.write_str("
"); +fn toggle_close(mut w: impl fmt::Write) { + w.write_str("").unwrap(); } fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) { - document(w, cx, item, None, HeadingOffset::H2); + write!(w, "{}", document(cx, item, None, HeadingOffset::H2)); let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::>(); @@ -544,12 +545,12 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx)); wrap_item(w, |w| { - render_attributes_in_pre(w, it, ""); w.reserve(header_len); write!( w, - "{vis}{constness}{asyncness}{unsafety}{abi}fn \ + "{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \ {name}{generics}{decl}{notable_traits}{where_clause}", + attrs = render_attributes_in_pre(it, ""), vis = visibility, constness = constness, asyncness = asyncness, @@ -562,7 +563,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle notable_traits = notable_traits.unwrap_or_default(), ); }); - document(w, cx, it, None, HeadingOffset::H2); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); } fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Trait) { @@ -580,17 +581,17 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let must_implement_one_of_functions = tcx.trait_def(t.def_id).must_implement_one_of.clone(); // Output the trait definition - wrap_item(w, |w| { - render_attributes_in_pre(w, it, ""); + wrap_item(w, |mut w| { write!( w, - "{}{}{}trait {}{}{}", + "{attrs}{}{}{}trait {}{}{}", visibility_print_with_space(it.visibility(tcx), it.item_id, cx), t.unsafety(tcx).print_with_space(), if t.is_auto(tcx) { "auto " } else { "" }, it.name.unwrap(), t.generics.print(cx), - bounds + bounds, + attrs = render_attributes_in_pre(it, ""), ); if !t.generics.where_predicates.is_empty() { @@ -610,7 +611,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: if should_hide_fields(count_types) { toggle = true; toggle_open( - w, + &mut w, format_args!("{} associated items", count_types + count_consts + count_methods), ); } @@ -634,7 +635,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: if !toggle && should_hide_fields(count_types + count_consts) { toggle = true; toggle_open( - w, + &mut w, format_args!( "{} associated constant{} and {} method{}", count_consts, @@ -662,7 +663,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } if !toggle && should_hide_fields(count_methods) { toggle = true; - toggle_open(w, format_args!("{} methods", count_methods)); + toggle_open(&mut w, format_args!("{} methods", count_methods)); } if count_consts != 0 && count_methods != 0 { w.write_str("\n"); @@ -710,14 +711,14 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } } if toggle { - toggle_close(w); + toggle_close(&mut w); } w.write_str("}"); } }); // Trait documentation - document(w, cx, it, None, HeadingOffset::H2); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) { write!( @@ -735,7 +736,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); let mut content = Buffer::empty_from(w); - document(&mut content, cx, m, Some(t), HeadingOffset::H5); + write!(&mut content, "{}", document(cx, m, Some(t), HeadingOffset::H5)); let toggled = !content.is_empty(); if toggled { let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; @@ -847,7 +848,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } // If there are methods directly on this trait object, render them here. - render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All); + write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)); let cloned_shared = Rc::clone(&cx.shared); let cache = &cloned_shared.cache; @@ -1057,147 +1058,201 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TraitAlias) { wrap_item(w, |w| { - render_attributes_in_pre(w, it, ""); write!( w, - "trait {}{}{} = {};", + "{attrs}trait {}{}{} = {};", it.name.unwrap(), t.generics.print(cx), print_where_clause(&t.generics, cx, 0, Ending::Newline), - bounds(&t.bounds, true, cx) + bounds(&t.bounds, true, cx), + attrs = render_attributes_in_pre(it, ""), ); }); - document(w, cx, it, None, HeadingOffset::H2); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show // associated items from the aliased type (see discussion in #32077), but // we need #14072 to make sense of the generics. - render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All) + write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)) } fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) { wrap_item(w, |w| { - render_attributes_in_pre(w, it, ""); write!( w, - "type {}{}{where_clause} = impl {bounds};", + "{attrs}type {}{}{where_clause} = impl {bounds};", it.name.unwrap(), t.generics.print(cx), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), bounds = bounds(&t.bounds, false, cx), + attrs = render_attributes_in_pre(it, ""), ); }); - document(w, cx, it, None, HeadingOffset::H2); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show // associated items from the aliased type (see discussion in #32077), but // we need #14072 to make sense of the generics. - render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All) + write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)) } fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Typedef) { fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) { wrap_item(w, |w| { - render_attributes_in_pre(w, it, ""); write!( w, - "{}type {}{}{where_clause} = {type_};", + "{attrs}{}type {}{}{where_clause} = {type_};", visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), it.name.unwrap(), t.generics.print(cx), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), type_ = t.type_.print(cx), + attrs = render_attributes_in_pre(it, ""), ); }); } write_content(w, cx, it, t); - document(w, cx, it, None, HeadingOffset::H2); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); let def_id = it.item_id.expect_def_id(); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show // associated items from the aliased type (see discussion in #32077), but // we need #14072 to make sense of the generics. - render_assoc_items(w, cx, it, def_id, AssocItemRender::All); - document_type_layout(w, cx, def_id); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); + write!(w, "{}", document_type_layout(cx, def_id)); } fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Union) { - wrap_item(w, |w| { - render_attributes_in_pre(w, it, ""); - render_union(w, it, Some(&s.generics), &s.fields, cx); - }); + #[derive(Template)] + #[template(path = "item_union.html")] + struct ItemUnion<'a, 'cx> { + cx: std::cell::RefCell<&'a mut Context<'cx>>, + it: &'a clean::Item, + s: &'a clean::Union, + } - document(w, cx, it, None, HeadingOffset::H2); + impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { + fn render_assoc_items<'b>( + &'b self, + ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let def_id = self.it.item_id.expect_def_id(); + let mut cx = self.cx.borrow_mut(); + let v = render_assoc_items(*cx, self.it, def_id, AssocItemRender::All); + write!(f, "{v}") + }) + } + fn document_type_layout<'b>( + &'b self, + ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let def_id = self.it.item_id.expect_def_id(); + let cx = self.cx.borrow_mut(); + let v = document_type_layout(*cx, def_id); + write!(f, "{v}") + }) + } + fn render_union<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let cx = self.cx.borrow_mut(); + let v = render_union(self.it, Some(&self.s.generics), &self.s.fields, *cx); + write!(f, "{v}") + }) + } + fn render_attributes_in_pre<'b>( + &'b self, + ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let v = render_attributes_in_pre(self.it, ""); + write!(f, "{v}") + }) + } + fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let mut cx = self.cx.borrow_mut(); + let v = document(*cx, self.it, None, HeadingOffset::H2); + write!(f, "{v}") + }) + } + fn document_field<'b>( + &'b self, + field: &'a clean::Item, + ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let mut cx = self.cx.borrow_mut(); + let v = document(*cx, field, Some(self.it), HeadingOffset::H3); + write!(f, "{v}") + }) + } + fn stability_field(&self, field: &clean::Item) -> Option { + let cx = self.cx.borrow(); + field.stability_class(cx.tcx()) + } + fn print_ty<'b>( + &'b self, + ty: &'a clean::Type, + ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let cx = self.cx.borrow(); + let v = ty.print(*cx); + write!(f, "{v}") + }) + } - let mut fields = s - .fields - .iter() - .filter_map(|f| match *f.kind { - clean::StructFieldItem(ref ty) => Some((f, ty)), - _ => None, - }) - .peekable(); - if fields.peek().is_some() { - write!( - w, - "

\ - Fields§\ -

" - ); - for (field, ty) in fields { - let name = field.name.expect("union field name"); - let id = format!("{}.{}", ItemType::StructField, name); - write!( - w, - "\ - §\ - {name}: {ty}\ - ", - shortty = ItemType::StructField, - ty = ty.print(cx), - ); - if let Some(stability_class) = field.stability_class(cx.tcx()) { - write!(w, ""); - } - document(w, cx, field, Some(it), HeadingOffset::H3); + fn fields_iter( + &self, + ) -> std::iter::Peekable> { + self.s + .fields + .iter() + .filter_map(|f| match *f.kind { + clean::StructFieldItem(ref ty) => Some((f, ty)), + _ => None, + }) + .peekable() } } - let def_id = it.item_id.expect_def_id(); - render_assoc_items(w, cx, it, def_id, AssocItemRender::All); - document_type_layout(w, cx, def_id); + + ItemUnion { cx: std::cell::RefCell::new(cx), it, s }.render_into(w).unwrap(); } -fn print_tuple_struct_fields(w: &mut Buffer, cx: &Context<'_>, s: &[clean::Item]) { - for (i, ty) in s.iter().enumerate() { - if i > 0 { - w.write_str(", "); +fn print_tuple_struct_fields<'a, 'cx: 'a>( + cx: &'a Context<'cx>, + s: &'a [clean::Item], +) -> impl fmt::Display + 'a + Captures<'cx> { + display_fn(|f| { + for (i, ty) in s.iter().enumerate() { + if i > 0 { + f.write_str(", ")?; + } + match *ty.kind { + clean::StrippedItem(box clean::StructFieldItem(_)) => f.write_str("_")?, + clean::StructFieldItem(ref ty) => write!(f, "{}", ty.print(cx))?, + _ => unreachable!(), + } } - match *ty.kind { - clean::StrippedItem(box clean::StructFieldItem(_)) => w.write_str("_"), - clean::StructFieldItem(ref ty) => write!(w, "{}", ty.print(cx)), - _ => unreachable!(), - } - } + Ok(()) + }) } fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) { let tcx = cx.tcx(); let count_variants = e.variants().count(); - wrap_item(w, |w| { - render_attributes_in_pre(w, it, ""); + wrap_item(w, |mut w| { write!( w, - "{}enum {}{}", + "{attrs}{}enum {}{}", visibility_print_with_space(it.visibility(tcx), it.item_id, cx), it.name.unwrap(), e.generics.print(cx), + attrs = render_attributes_in_pre(it, ""), ); if !print_where_clause_and_check(w, &e.generics, cx) { // If there wasn't a `where` clause, we add a whitespace. @@ -1211,7 +1266,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: w.write_str("{\n"); let toggle = should_hide_fields(count_variants); if toggle { - toggle_open(w, format_args!("{} variants", count_variants)); + toggle_open(&mut w, format_args!("{} variants", count_variants)); } for v in e.variants() { w.write_str(" "); @@ -1221,9 +1276,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: clean::VariantItem(ref var) => match var.kind { clean::VariantKind::CLike => write!(w, "{}", name), clean::VariantKind::Tuple(ref s) => { - write!(w, "{}(", name); - print_tuple_struct_fields(w, cx, s); - w.write_str(")"); + write!(w, "{name}({})", print_tuple_struct_fields(cx, s),); } clean::VariantKind::Struct(ref s) => { render_struct(w, v, None, None, &s.fields, " ", false, cx); @@ -1238,24 +1291,25 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: w.write_str(" // some variants omitted\n"); } if toggle { - toggle_close(w); + toggle_close(&mut w); } w.write_str("}"); } }); - document(w, cx, it, None, HeadingOffset::H2); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); if count_variants != 0 { write!( w, "

\ Variants{}§\ -

", - document_non_exhaustive_header(it) + \ + {}\ +
", + document_non_exhaustive_header(it), + document_non_exhaustive(it) ); - document_non_exhaustive(w, it); - write!(w, "
"); for variant in e.variants() { let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap())); write!( @@ -1276,9 +1330,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; if let clean::VariantKind::Tuple(ref s) = variant_data.kind { - w.write_str("("); - print_tuple_struct_fields(w, cx, s); - w.write_str(")"); + write!(w, "({})", print_tuple_struct_fields(cx, s),); } w.write_str(""); @@ -1302,9 +1354,10 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: write!( w, "
\ -

{heading}

", +

{heading}

\ + {}", + document_non_exhaustive(variant) ); - document_non_exhaustive(w, variant); for field in fields { match *field.kind { clean::StrippedItem(box clean::StructFieldItem(_)) => {} @@ -1322,10 +1375,13 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: {f}: {t}\ ", f = field.name.unwrap(), - t = ty.print(cx) + t = ty.print(cx), + ); + write!( + w, + "{}
", + document(cx, field, Some(variant), HeadingOffset::H5) ); - document(w, cx, field, Some(variant), HeadingOffset::H5); - write!(w, "
"); } _ => unreachable!(), } @@ -1333,18 +1389,18 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: w.write_str("
"); } - document(w, cx, variant, Some(it), HeadingOffset::H4); + write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4)); } write!(w, ""); } let def_id = it.item_id.expect_def_id(); - render_assoc_items(w, cx, it, def_id, AssocItemRender::All); - document_type_layout(w, cx, def_id); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); + write!(w, "{}", document_type_layout(cx, def_id)); } fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) { highlight::render_item_decl_with_highlighting(&t.source, w); - document(w, cx, it, None, HeadingOffset::H2) + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) } fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &clean::ProcMacro) { @@ -1370,14 +1426,14 @@ fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &c } } }); - document(w, cx, it, None, HeadingOffset::H2) + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) } fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { let def_id = it.item_id.expect_def_id(); - document(w, cx, it, None, HeadingOffset::H2); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) { - render_assoc_items(w, cx, it, def_id, AssocItemRender::All); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); } else { // We handle the "reference" primitive type on its own because we only want to list // implementations on generic types. @@ -1433,7 +1489,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle } }); - document(w, cx, it, None, HeadingOffset::H2) + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) } fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) { @@ -1442,7 +1498,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx); }); - document(w, cx, it, None, HeadingOffset::H2); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); let mut fields = s .fields @@ -1458,11 +1514,12 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean w, "

\ {}{}§\ -

", + \ + {}", if s.ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, - document_non_exhaustive_header(it) + document_non_exhaustive_header(it), + document_non_exhaustive(it) ); - document_non_exhaustive(w, it); for (index, (field, ty)) in fields.enumerate() { let field_name = field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string()); @@ -1476,13 +1533,13 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean item_type = ItemType::StructField, ty = ty.print(cx) ); - document(w, cx, field, Some(it), HeadingOffset::H3); + write!(w, "{}", document(cx, field, Some(it), HeadingOffset::H3)); } } } let def_id = it.item_id.expect_def_id(); - render_assoc_items(w, cx, it, def_id, AssocItemRender::All); - document_type_layout(w, cx, def_id); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); + write!(w, "{}", document_type_layout(cx, def_id)); } fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { @@ -1497,7 +1554,7 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean typ = s.type_.print(cx) ); }); - document(w, cx, it, None, HeadingOffset::H2) + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) } fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { @@ -1512,13 +1569,13 @@ fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { ); }); - document(w, cx, it, None, HeadingOffset::H2); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All) + write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)) } fn item_keyword(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { - document(w, cx, it, None, HeadingOffset::H2) + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) } /// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order). @@ -1655,64 +1712,69 @@ fn render_implementor( ); } -fn render_union( - w: &mut Buffer, - it: &clean::Item, - g: Option<&clean::Generics>, - fields: &[clean::Item], - cx: &Context<'_>, -) { - let tcx = cx.tcx(); - write!( - w, - "{}union {}", - visibility_print_with_space(it.visibility(tcx), it.item_id, cx), - it.name.unwrap(), - ); +fn render_union<'a, 'cx: 'a>( + it: &'a clean::Item, + g: Option<&'a clean::Generics>, + fields: &'a [clean::Item], + cx: &'a Context<'cx>, +) -> impl fmt::Display + 'a + Captures<'cx> { + display_fn(move |mut f| { + let tcx = cx.tcx(); + write!( + f, + "{}union {}", + visibility_print_with_space(it.visibility(tcx), it.item_id, cx), + it.name.unwrap(), + )?; - let where_displayed = g - .map(|g| { - write!(w, "{}", g.print(cx)); - print_where_clause_and_check(w, g, cx) - }) - .unwrap_or(false); + let where_displayed = g + .map(|g| { + let mut buf = Buffer::html(); + write!(buf, "{}", g.print(cx)); + let where_displayed = print_where_clause_and_check(&mut buf, g, cx); + write!(f, "{buf}", buf = buf.into_inner()).unwrap(); + where_displayed + }) + .unwrap_or(false); - // If there wasn't a `where` clause, we add a whitespace. - if !where_displayed { - w.write_str(" "); - } - - write!(w, "{{\n"); - let count_fields = - fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count(); - let toggle = should_hide_fields(count_fields); - if toggle { - toggle_open(w, format_args!("{} fields", count_fields)); - } - - for field in fields { - if let clean::StructFieldItem(ref ty) = *field.kind { - write!( - w, - " {}{}: {},\n", - visibility_print_with_space(field.visibility(tcx), field.item_id, cx), - field.name.unwrap(), - ty.print(cx) - ); + // If there wasn't a `where` clause, we add a whitespace. + if !where_displayed { + f.write_str(" ")?; } - } - if it.has_stripped_entries().unwrap() { - write!(w, " /* private fields */\n"); - } - if toggle { - toggle_close(w); - } - w.write_str("}"); + write!(f, "{{\n")?; + let count_fields = + fields.iter().filter(|field| matches!(*field.kind, clean::StructFieldItem(..))).count(); + let toggle = should_hide_fields(count_fields); + if toggle { + toggle_open(&mut f, format_args!("{} fields", count_fields)); + } + + for field in fields { + if let clean::StructFieldItem(ref ty) = *field.kind { + write!( + f, + " {}{}: {},\n", + visibility_print_with_space(field.visibility(tcx), field.item_id, cx), + field.name.unwrap(), + ty.print(cx) + )?; + } + } + + if it.has_stripped_entries().unwrap() { + write!(f, " /* private fields */\n")?; + } + if toggle { + toggle_close(&mut f); + } + f.write_str("}").unwrap(); + Ok(()) + }) } fn render_struct( - w: &mut Buffer, + mut w: &mut Buffer, it: &clean::Item, g: Option<&clean::Generics>, ty: Option, @@ -1747,7 +1809,7 @@ fn render_struct( let has_visible_fields = count_fields > 0; let toggle = should_hide_fields(count_fields); if toggle { - toggle_open(w, format_args!("{} fields", count_fields)); + toggle_open(&mut w, format_args!("{} fields", count_fields)); } for field in fields { if let clean::StructFieldItem(ref ty) = *field.kind { @@ -1771,7 +1833,7 @@ fn render_struct( write!(w, " /* private fields */ "); } if toggle { - toggle_close(w); + toggle_close(&mut w); } w.write_str("}"); } @@ -1817,161 +1879,169 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str { if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" } } -fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { - if item.is_non_exhaustive() { - write!( - w, - "
\ - {}\ -
", - { - if item.is_struct() { - "This struct is marked as non-exhaustive" - } else if item.is_enum() { - "This enum is marked as non-exhaustive" - } else if item.is_variant() { - "This variant is marked as non-exhaustive" - } else { - "This type is marked as non-exhaustive" +fn document_non_exhaustive<'a>(item: &'a clean::Item) -> impl fmt::Display + 'a { + display_fn(|f| { + if item.is_non_exhaustive() { + write!( + f, + "
\ + {}\ +
", + { + if item.is_struct() { + "This struct is marked as non-exhaustive" + } else if item.is_enum() { + "This enum is marked as non-exhaustive" + } else if item.is_variant() { + "This variant is marked as non-exhaustive" + } else { + "This type is marked as non-exhaustive" + } } + )?; + + if item.is_struct() { + f.write_str( + "Non-exhaustive structs could have additional fields added in future. \ + Therefore, non-exhaustive structs cannot be constructed in external crates \ + using the traditional Struct { .. } syntax; cannot be \ + matched against without a wildcard ..; and \ + struct update syntax will not work.", + )?; + } else if item.is_enum() { + f.write_str( + "Non-exhaustive enums could have additional variants added in future. \ + Therefore, when matching against variants of non-exhaustive enums, an \ + extra wildcard arm must be added to account for any future variants.", + )?; + } else if item.is_variant() { + f.write_str( + "Non-exhaustive enum variants could have additional fields added in future. \ + Therefore, non-exhaustive enum variants cannot be constructed in external \ + crates and cannot be matched against.", + )?; + } else { + f.write_str( + "This type will require a wildcard arm in any match statements or constructors.", + )?; } - ); - if item.is_struct() { - w.write_str( - "Non-exhaustive structs could have additional fields added in future. \ - Therefore, non-exhaustive structs cannot be constructed in external crates \ - using the traditional Struct { .. } syntax; cannot be \ - matched against without a wildcard ..; and \ - struct update syntax will not work.", - ); - } else if item.is_enum() { - w.write_str( - "Non-exhaustive enums could have additional variants added in future. \ - Therefore, when matching against variants of non-exhaustive enums, an \ - extra wildcard arm must be added to account for any future variants.", - ); - } else if item.is_variant() { - w.write_str( - "Non-exhaustive enum variants could have additional fields added in future. \ - Therefore, non-exhaustive enum variants cannot be constructed in external \ - crates and cannot be matched against.", - ); - } else { - w.write_str( - "This type will require a wildcard arm in any match statements or constructors.", - ); + f.write_str("
")?; } - - w.write_str("
"); - } + Ok(()) + }) } -fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) { - fn write_size_of_layout(w: &mut Buffer, layout: &LayoutS, tag_size: u64) { +fn document_type_layout<'a, 'cx: 'a>( + cx: &'a Context<'cx>, + ty_def_id: DefId, +) -> impl fmt::Display + 'a + Captures<'cx> { + fn write_size_of_layout(mut w: impl fmt::Write, layout: &LayoutS, tag_size: u64) { if layout.abi.is_unsized() { - write!(w, "(unsized)"); + write!(w, "(unsized)").unwrap(); } else { let size = layout.size.bytes() - tag_size; - write!(w, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" },); + write!(w, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" }).unwrap(); if layout.abi.is_uninhabited() { write!( w, " (uninhabited)" - ); + ).unwrap(); } } } - if !cx.shared.show_type_layout { - return; - } + display_fn(move |mut f| { + if !cx.shared.show_type_layout { + return Ok(()); + } - writeln!( - w, - "

\ - Layout§

" - ); - writeln!(w, "
"); + writeln!( + f, + "

\ + Layout§

" + )?; + writeln!(f, "
")?; - let tcx = cx.tcx(); - let param_env = tcx.param_env(ty_def_id); - let ty = tcx.type_of(ty_def_id).subst_identity(); - match tcx.layout_of(param_env.and(ty)) { - Ok(ty_layout) => { - writeln!( - w, - "

Note: Most layout information is \ - completely unstable and may even differ between compilations. \ - The only exception is types with certain repr(...) attributes. \ - Please see the Rust Reference’s \ - “Type Layout” \ - chapter for details on type layout guarantees.

" - ); - w.write_str("

Size: "); - write_size_of_layout(w, &ty_layout.layout.0, 0); - writeln!(w, "

"); - if let Variants::Multiple { variants, tag, tag_encoding, .. } = - &ty_layout.layout.variants() - { - if !variants.is_empty() { - w.write_str( - "

Size for each variant:

\ -
    ", - ); + let tcx = cx.tcx(); + let param_env = tcx.param_env(ty_def_id); + let ty = tcx.type_of(ty_def_id).subst_identity(); + match tcx.layout_of(param_env.and(ty)) { + Ok(ty_layout) => { + writeln!( + f, + "

    Note: Most layout information is \ + completely unstable and may even differ between compilations. \ + The only exception is types with certain repr(...) attributes. \ + Please see the Rust Reference’s \ + “Type Layout” \ + chapter for details on type layout guarantees.

    " + )?; + f.write_str("

    Size: ")?; + write_size_of_layout(&mut f, &ty_layout.layout.0, 0); + writeln!(f, "

    ")?; + if let Variants::Multiple { variants, tag, tag_encoding, .. } = + &ty_layout.layout.variants() + { + if !variants.is_empty() { + f.write_str( + "

    Size for each variant:

    \ +
      ", + )?; - let Adt(adt, _) = ty_layout.ty.kind() else { - span_bug!(tcx.def_span(ty_def_id), "not an adt") - }; + let Adt(adt, _) = ty_layout.ty.kind() else { + span_bug!(tcx.def_span(ty_def_id), "not an adt") + }; - let tag_size = if let TagEncoding::Niche { .. } = tag_encoding { - 0 - } else if let Primitive::Int(i, _) = tag.primitive() { - i.size().bytes() - } else { - span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int") - }; + let tag_size = if let TagEncoding::Niche { .. } = tag_encoding { + 0 + } else if let Primitive::Int(i, _) = tag.primitive() { + i.size().bytes() + } else { + span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int") + }; - for (index, layout) in variants.iter_enumerated() { - let name = adt.variant(index).name; - write!(w, "
    • {name}: "); - write_size_of_layout(w, layout, tag_size); - writeln!(w, "
    • "); + for (index, layout) in variants.iter_enumerated() { + let name = adt.variant(index).name; + write!(&mut f, "
    • {name}: ")?; + write_size_of_layout(&mut f, layout, tag_size); + writeln!(&mut f, "
    • ")?; + } + f.write_str("
    ")?; } - w.write_str("
"); } } + // This kind of layout error can occur with valid code, e.g. if you try to + // get the layout of a generic type such as `Vec`. + Err(LayoutError::Unknown(_)) => { + writeln!( + f, + "

Note: Unable to compute type layout, \ + possibly due to this type having generic parameters. \ + Layout can only be computed for concrete, fully-instantiated types.

" + )?; + } + // This kind of error probably can't happen with valid code, but we don't + // want to panic and prevent the docs from building, so we just let the + // user know that we couldn't compute the layout. + Err(LayoutError::SizeOverflow(_)) => { + writeln!( + f, + "

Note: Encountered an error during type layout; \ + the type was too big.

" + )?; + } + Err(LayoutError::NormalizationFailure(_, _)) => { + writeln!( + f, + "

Note: Encountered an error during type layout; \ + the type failed to be normalized.

" + )?; + } } - // This kind of layout error can occur with valid code, e.g. if you try to - // get the layout of a generic type such as `Vec`. - Err(LayoutError::Unknown(_)) => { - writeln!( - w, - "

Note: Unable to compute type layout, \ - possibly due to this type having generic parameters. \ - Layout can only be computed for concrete, fully-instantiated types.

" - ); - } - // This kind of error probably can't happen with valid code, but we don't - // want to panic and prevent the docs from building, so we just let the - // user know that we couldn't compute the layout. - Err(LayoutError::SizeOverflow(_)) => { - writeln!( - w, - "

Note: Encountered an error during type layout; \ - the type was too big.

" - ); - } - Err(LayoutError::NormalizationFailure(_, _)) => { - writeln!( - w, - "

Note: Encountered an error during type layout; \ - the type failed to be normalized.

" - ) - } - } - writeln!(w, "
"); + writeln!(f, "
") + }) } fn pluralize(count: usize) -> &'static str { diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 1d298f52f758..c8397967c879 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -2,7 +2,6 @@ use crate::clean; use crate::docfs::PathError; use crate::error::Error; use crate::html::format; -use crate::html::format::Buffer; use crate::html::highlight; use crate::html::layout; use crate::html::render::Context; @@ -17,6 +16,7 @@ use rustc_span::source_map::FileName; use std::cell::RefCell; use std::ffi::OsStr; +use std::fmt; use std::fs; use std::ops::RangeInclusive; use std::path::{Component, Path, PathBuf}; @@ -294,7 +294,7 @@ pub(crate) enum SourceContext { /// Wrapper struct to render the source code of a file. This will do things like /// adding line numbers to the left-hand side. pub(crate) fn print_src( - buf: &mut Buffer, + mut writer: impl fmt::Write, s: &str, file_span: rustc_span::Span, context: &Context<'_>, @@ -329,5 +329,5 @@ pub(crate) fn print_src( ); Ok(()) }); - Source { embedded, needs_expansion, lines, code_html: code }.render_into(buf).unwrap(); + Source { embedded, needs_expansion, lines, code_html: code }.render_into(&mut writer).unwrap(); } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 933a44c5aa78..9df193525673 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -6,6 +6,10 @@ 3. Copy the filenames with updated suffixes from the directory. */ +:root { + --nav-sub-mobile-padding: 8px; +} + /* See FiraSans-LICENSE.txt for the Fira Sans license. */ @font-face { font-family: 'Fira Sans'; @@ -348,7 +352,7 @@ pre.item-decl { .source .content pre { padding: 20px; } -.rustdoc.source .example-wrap > pre.src-line-numbers { +.rustdoc.source .example-wrap pre.src-line-numbers { padding: 20px 0 20px 4px; } @@ -392,6 +396,7 @@ img { overflow-x: hidden; /* The sidebar is by default hidden */ overflow-y: hidden; + z-index: 1; } .sidebar, .mobile-topbar, .sidebar-menu-toggle, @@ -532,14 +537,17 @@ ul.block, .block li { margin-bottom: 0px; } -.rustdoc .example-wrap > pre { +.rustdoc .example-wrap pre { margin: 0; flex-grow: 1; +} + +.rustdoc:not(.source) .example-wrap pre { overflow: auto hidden; } -.rustdoc .example-wrap > pre.example-line-numbers, -.rustdoc .example-wrap > pre.src-line-numbers { +.rustdoc .example-wrap pre.example-line-numbers, +.rustdoc .example-wrap pre.src-line-numbers { flex-grow: 0; min-width: fit-content; /* prevent collapsing into nothing in truncated scraped examples */ overflow: initial; @@ -550,7 +558,7 @@ ul.block, .block li { color: var(--src-line-numbers-span-color); } -.rustdoc .example-wrap > pre.src-line-numbers { +.rustdoc .example-wrap pre.src-line-numbers { padding: 14px 0; } .src-line-numbers a, .src-line-numbers span { @@ -698,7 +706,7 @@ h2.small-section-header > .anchor { } .main-heading a:hover, -.example-wrap > .rust a:hover, +.example-wrap .rust a:hover, .all-items a:hover, .docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover, .docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover, @@ -1722,7 +1730,7 @@ in main.js .source nav.sub { margin: 0; - padding: 8px; + padding: var(--nav-sub-mobile-padding); } } @@ -1779,6 +1787,7 @@ in main.js .sub-logo-container > img { height: 35px; width: 35px; + margin-bottom: var(--nav-sub-mobile-padding); } } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 45c0360a49ea..56ee4c1510e8 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -332,13 +332,7 @@ function preLoadCss(cssUrl) { }; function getPageId() { - if (window.location.hash) { - const tmp = window.location.hash.replace(/^#/, ""); - if (tmp.length > 0) { - return tmp; - } - } - return null; + return window.location.hash.replace(/^#/, ""); } const toggleAllDocsId = "toggle-all-docs"; @@ -707,7 +701,7 @@ function preLoadCss(cssUrl) { }); const pageId = getPageId(); - if (pageId !== null) { + if (pageId !== "") { expandSection(pageId); } }()); diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 1cd552e7f25b..ebbe6c1ca9a2 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -86,12 +86,8 @@ if (settingId === "theme") { const useSystem = getSettingValue("use-system-theme"); if (useSystem === "true" || settingValue === null) { - if (useSystem !== "false") { - settingValue = "system preference"; - } else { - // This is the default theme. - settingValue = "light"; - } + // "light" is the default theme + settingValue = useSystem === "false" ? "light" : "system preference"; } } if (settingValue !== null && settingValue !== "null") { diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 8d82b5b78edb..93979a944183 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -53,10 +53,9 @@ function removeClass(elem, className) { * @param {boolean} [reversed] - Whether to iterate in reverse */ function onEach(arr, func, reversed) { - if (arr && arr.length > 0 && func) { + if (arr && arr.length > 0) { if (reversed) { - const length = arr.length; - for (let i = length - 1; i >= 0; --i) { + for (let i = arr.length - 1; i >= 0; --i) { if (func(arr[i])) { return true; } @@ -150,26 +149,19 @@ const updateTheme = (function() { * … dictates that it should be. */ function updateTheme() { - const use = (theme, saveTheme) => { - switchTheme(theme, saveTheme); - }; - // 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"; + updateLocalStorage("use-system-theme", "true"); - if (mql.matches) { - use(darkTheme, true); - } else { - // prefers a light theme, or has no preference - use(lightTheme, true); - } + // use light theme if user prefers it, or has no preference + switchTheme(mql.matches ? darkTheme : 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"), false); + switchTheme(getSettingValue("theme"), false); } } diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html new file mode 100644 index 000000000000..a01457971c17 --- /dev/null +++ b/src/librustdoc/html/templates/item_union.html @@ -0,0 +1,23 @@ +

+    {{ self.render_attributes_in_pre() | safe }}
+    {{ self.render_union() | safe }}
+
+{{ self.document() | safe }} +{% if self.fields_iter().peek().is_some() %} +

+ Fields§ +

+ {% for (field, ty) in self.fields_iter() %} + {% let name = field.name.expect("union field name") %} + + § + {{ name }}: {{ self.print_ty(ty) | safe }} + + {% if let Some(stability_class) = self.stability_field(field) %} + + {% endif %} + {{ self.document_field(field) | safe }} + {% endfor %} +{% endif %} +{{ self.render_assoc_items() | safe }} +{{ self.document_type_layout() | safe }} diff --git a/src/librustdoc/html/templates/source.html b/src/librustdoc/html/templates/source.html index a224ff12f448..42d01277db2c 100644 --- a/src/librustdoc/html/templates/source.html +++ b/src/librustdoc/html/templates/source.html @@ -1,5 +1,7 @@
{# #} -
+    {# https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr
+       Do not show "1 2 3 4 5 ..." in web search results. #}
+    
         {% for line in lines.clone() %}
             {% if embedded %}
                 {{line|safe}}
@@ -7,7 +9,7 @@
                 {{line|safe}}
             {%~ endif %}
         {% endfor %}
-    
{# #} +
{# #}
 {# #}
         
             {% if needs_expansion %}
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 4c4dbc9864fd..79f53ee57cc9 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -203,7 +203,7 @@ fn init_logging() {
         .with_verbose_exit(true)
         .with_verbose_entry(true)
         .with_indent_amount(2);
-    #[cfg(parallel_compiler)]
+    #[cfg(all(parallel_compiler, debug_assertions))]
     let layer = layer.with_thread_ids(true).with_thread_names(true);
 
     use tracing_subscriber::layer::SubscriberExt;
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 060062db0027..393d51fe0906 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -13,9 +13,9 @@ use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 
-use std::mem;
+use std::{iter, mem};
 
-use crate::clean::{cfg::Cfg, AttributesExt, NestedAttributesExt, OneLevelVisitor};
+use crate::clean::{cfg::Cfg, reexport_chain, AttributesExt, NestedAttributesExt};
 use crate::core;
 
 /// This module is used to store stuff from Rust's AST in a more convenient
@@ -133,7 +133,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         // is declared but also a reexport of itself producing two exports of the same
         // macro in the same module.
         let mut inserted = FxHashSet::default();
-        for export in self.cx.tcx.module_reexports(CRATE_DEF_ID).unwrap_or(&[]) {
+        for export in self.cx.tcx.module_reexports(CRATE_DEF_ID) {
             if let Res::Def(DefKind::Macro(_), def_id) = export.res &&
                 let Some(local_def_id) = def_id.as_local() &&
                 self.cx.tcx.has_attr(def_id, sym::macro_export) &&
@@ -220,7 +220,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         renamed: Option,
         glob: bool,
         please_inline: bool,
-        path: &hir::UsePath<'_>,
     ) -> bool {
         debug!("maybe_inline_local res: {:?}", res);
 
@@ -266,9 +265,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         }
 
         if !please_inline &&
-            let mut visitor = OneLevelVisitor::new(self.cx.tcx.hir(), res_did) &&
-            let Some(item) = visitor.find_target(self.cx.tcx, def_id.to_def_id(), path) &&
-            let item_def_id = item.owner_id.def_id &&
+            let Some(item_def_id) = reexport_chain(self.cx.tcx, def_id, res_did).iter()
+                .flat_map(|reexport| reexport.id()).map(|id| id.expect_local())
+                .chain(iter::once(res_did)).nth(1) &&
             item_def_id != def_id &&
             self
                 .cx
@@ -383,7 +382,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                             ident,
                             is_glob,
                             please_inline,
-                            path,
                         ) {
                             continue;
                         }
@@ -421,12 +419,20 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             | hir::ItemKind::Struct(..)
             | hir::ItemKind::Union(..)
             | hir::ItemKind::TyAlias(..)
-            | hir::ItemKind::OpaqueTy(..)
+            | hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+                origin: hir::OpaqueTyOrigin::TyAlias, ..
+            })
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Trait(..)
             | hir::ItemKind::TraitAlias(..) => {
                 self.add_to_current_mod(item, renamed, import_id);
             }
+            hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+                origin: hir::OpaqueTyOrigin::AsyncFn(_) | hir::OpaqueTyOrigin::FnReturn(_),
+                ..
+            }) => {
+                // return-position impl traits are never nameable, and should never be documented.
+            }
             hir::ItemKind::Const(..) => {
                 // Underscore constants do not correspond to a nameable item and
                 // so are never useful in documentation.
diff --git a/src/llvm-project b/src/llvm-project
index 2b9c52f66815..585a6eb3ebf7 160000
--- a/src/llvm-project
+++ b/src/llvm-project
@@ -1 +1 @@
-Subproject commit 2b9c52f66815bb8d6ea74a4b26df3410602be9b0
+Subproject commit 585a6eb3ebf7c40fd7c1b23e3ece557b3cc2aa36
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 327e090d38be..0bb1775aae9c 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
 
         let sized_trait = need!(cx.tcx.lang_items().sized_trait());
 
-        let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter())
+        let preds = traits::elaborate(cx.tcx, cx.param_env.caller_bounds().iter())
             .filter(|p| !p.is_global())
             .filter_map(|pred| {
                 // Note that we do not want to deal with qualified predicates here.
diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
index 44bf824aa0e2..11b908e7e53d 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet;
-use rustc_ast::ast::{Item, ItemKind, Ty, TyKind};
+use rustc_ast::ast::{Item, ItemKind, Ty, TyKind, StaticItem, ConstItem};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -100,13 +100,13 @@ impl EarlyLintPass for RedundantStaticLifetimes {
         }
 
         if !item.span.from_expansion() {
-            if let ItemKind::Const(_, ref var_type, _) = item.kind {
+            if let ItemKind::Const(box ConstItem { ty: ref var_type, .. }) = item.kind {
                 Self::visit_type(var_type, cx, "constants have by default a `'static` lifetime");
                 // Don't check associated consts because `'static` cannot be elided on those (issue
                 // #2438)
             }
 
-            if let ItemKind::Static(ref var_type, _, _) = item.kind {
+            if let ItemKind::Static(box StaticItem { ty: ref var_type,.. }) = item.kind {
                 Self::visit_type(var_type, cx, "statics have by default a `'static` lifetime");
             }
         }
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index d2dedc204395..c5b58b0c060c 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -286,8 +286,8 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
     match (l, r) {
         (ExternCrate(l), ExternCrate(r)) => l == r,
         (Use(l), Use(r)) => eq_use_tree(l, r),
-        (Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
-        (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
+        (Static(box ast::StaticItem { ty: lt, mutability: lm, expr: le}), Static(box ast::StaticItem { ty: rt, mutability: rm, expr: re})) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
+        (Const(box ast::ConstItem { defaultness: ld, ty: lt, expr: le}), Const(box ast::ConstItem { defaultness: rd, ty: rt, expr: re} )) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
         (
             Fn(box ast::Fn {
                 defaultness: ld,
@@ -451,7 +451,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
 pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
     use AssocItemKind::*;
     match (l, r) {
-        (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
+        (Const(box ast::ConstItem { defaultness: ld, ty: lt, expr: le}), Const(box ast::ConstItem { defaultness: rd, ty: rt, expr: re})) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
         (
             Fn(box ast::Fn {
                 defaultness: ld,
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 619aa9f4bf6f..9051cf51658d 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -2104,7 +2104,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
         .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
     traits::impossible_predicates(
         cx.tcx,
-        traits::elaborate_predicates(cx.tcx, predicates)
+        traits::elaborate(cx.tcx, predicates)
             .collect::>(),
     )
 }
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index d66640ba0b7a..354b6d71aa46 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -301,13 +301,13 @@ fn check_terminator<'tcx>(
         | TerminatorKind::Goto { .. }
         | TerminatorKind::Return
         | TerminatorKind::Resume
+        | TerminatorKind::Terminate
         | TerminatorKind::Unreachable => Ok(()),
 
         TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body),
 
         TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
 
-        TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
         TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
             Err((span, "const fn generators are unstable".into()))
         },
@@ -318,7 +318,7 @@ fn check_terminator<'tcx>(
             from_hir_call: _,
             destination: _,
             target: _,
-            cleanup: _,
+            unwind: _,
             fn_span: _,
         } => {
             let fn_ty = func.ty(body, tcx);
@@ -361,7 +361,7 @@ fn check_terminator<'tcx>(
             expected: _,
             msg: _,
             target: _,
-            cleanup: _,
+            unwind: _,
         } => check_operand(tcx, cond, span, body),
 
         TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 28c045f83824..98b27a5c6b60 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -8,24 +8,65 @@ use std::process::Command;
 use std::str::FromStr;
 
 use crate::util::{add_dylib_path, PathBufExt};
-use lazycell::LazyCell;
+use lazycell::AtomicLazyCell;
+use serde::de::{Deserialize, Deserializer, Error as _};
+use std::collections::{HashMap, HashSet};
 use test::{ColorConfig, OutputFormat};
 
-#[derive(Clone, Copy, PartialEq, Debug)]
-pub enum Mode {
-    RunPassValgrind,
-    Pretty,
-    DebugInfo,
-    Codegen,
-    Rustdoc,
-    RustdocJson,
-    CodegenUnits,
-    Incremental,
-    RunMake,
-    Ui,
-    JsDocTest,
-    MirOpt,
-    Assembly,
+macro_rules! string_enum {
+    ($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => {
+        $(#[$meta])*
+        $vis enum $name {
+            $($variant,)*
+        }
+
+        impl $name {
+            $vis const VARIANTS: &'static [Self] = &[$(Self::$variant,)*];
+            $vis const STR_VARIANTS: &'static [&'static str] = &[$(Self::$variant.to_str(),)*];
+
+            $vis const fn to_str(&self) -> &'static str {
+                match self {
+                    $(Self::$variant => $repr,)*
+                }
+            }
+        }
+
+        impl fmt::Display for $name {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt::Display::fmt(self.to_str(), f)
+            }
+        }
+
+        impl FromStr for $name {
+            type Err = ();
+
+            fn from_str(s: &str) -> Result {
+                match s {
+                    $($repr => Ok(Self::$variant),)*
+                    _ => Err(()),
+                }
+            }
+        }
+    }
+}
+
+string_enum! {
+    #[derive(Clone, Copy, PartialEq, Debug)]
+    pub enum Mode {
+        RunPassValgrind => "run-pass-valgrind",
+        Pretty => "pretty",
+        DebugInfo => "debuginfo",
+        Codegen => "codegen",
+        Rustdoc => "rustdoc",
+        RustdocJson => "rustdoc-json",
+        CodegenUnits => "codegen-units",
+        Incremental => "incremental",
+        RunMake => "run-make",
+        Ui => "ui",
+        JsDocTest => "js-doc-test",
+        MirOpt => "mir-opt",
+        Assembly => "assembly",
+    }
 }
 
 impl Mode {
@@ -39,76 +80,12 @@ impl Mode {
     }
 }
 
-impl FromStr for Mode {
-    type Err = ();
-    fn from_str(s: &str) -> Result {
-        match s {
-            "run-pass-valgrind" => Ok(RunPassValgrind),
-            "pretty" => Ok(Pretty),
-            "debuginfo" => Ok(DebugInfo),
-            "codegen" => Ok(Codegen),
-            "rustdoc" => Ok(Rustdoc),
-            "rustdoc-json" => Ok(RustdocJson),
-            "codegen-units" => Ok(CodegenUnits),
-            "incremental" => Ok(Incremental),
-            "run-make" => Ok(RunMake),
-            "ui" => Ok(Ui),
-            "js-doc-test" => Ok(JsDocTest),
-            "mir-opt" => Ok(MirOpt),
-            "assembly" => Ok(Assembly),
-            _ => Err(()),
-        }
-    }
-}
-
-impl fmt::Display for Mode {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let s = match *self {
-            RunPassValgrind => "run-pass-valgrind",
-            Pretty => "pretty",
-            DebugInfo => "debuginfo",
-            Codegen => "codegen",
-            Rustdoc => "rustdoc",
-            RustdocJson => "rustdoc-json",
-            CodegenUnits => "codegen-units",
-            Incremental => "incremental",
-            RunMake => "run-make",
-            Ui => "ui",
-            JsDocTest => "js-doc-test",
-            MirOpt => "mir-opt",
-            Assembly => "assembly",
-        };
-        fmt::Display::fmt(s, f)
-    }
-}
-
-#[derive(Clone, Copy, PartialEq, Debug, Hash)]
-pub enum PassMode {
-    Check,
-    Build,
-    Run,
-}
-
-impl FromStr for PassMode {
-    type Err = ();
-    fn from_str(s: &str) -> Result {
-        match s {
-            "check" => Ok(PassMode::Check),
-            "build" => Ok(PassMode::Build),
-            "run" => Ok(PassMode::Run),
-            _ => Err(()),
-        }
-    }
-}
-
-impl fmt::Display for PassMode {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let s = match *self {
-            PassMode::Check => "check",
-            PassMode::Build => "build",
-            PassMode::Run => "run",
-        };
-        fmt::Display::fmt(s, f)
+string_enum! {
+    #[derive(Clone, Copy, PartialEq, Debug, Hash)]
+    pub enum PassMode {
+        Check => "check",
+        Build => "build",
+        Run => "run",
     }
 }
 
@@ -119,63 +96,30 @@ pub enum FailMode {
     Run,
 }
 
-#[derive(Clone, Debug, PartialEq)]
-pub enum CompareMode {
-    Polonius,
-    Chalk,
-    NextSolver,
-    SplitDwarf,
-    SplitDwarfSingle,
-}
-
-impl CompareMode {
-    pub(crate) fn to_str(&self) -> &'static str {
-        match *self {
-            CompareMode::Polonius => "polonius",
-            CompareMode::Chalk => "chalk",
-            CompareMode::NextSolver => "next-solver",
-            CompareMode::SplitDwarf => "split-dwarf",
-            CompareMode::SplitDwarfSingle => "split-dwarf-single",
-        }
-    }
-
-    pub fn parse(s: String) -> CompareMode {
-        match s.as_str() {
-            "polonius" => CompareMode::Polonius,
-            "chalk" => CompareMode::Chalk,
-            "next-solver" => CompareMode::NextSolver,
-            "split-dwarf" => CompareMode::SplitDwarf,
-            "split-dwarf-single" => CompareMode::SplitDwarfSingle,
-            x => panic!("unknown --compare-mode option: {}", x),
-        }
+string_enum! {
+    #[derive(Clone, Debug, PartialEq)]
+    pub enum CompareMode {
+        Polonius => "polonius",
+        Chalk => "chalk",
+        NextSolver => "next-solver",
+        SplitDwarf => "split-dwarf",
+        SplitDwarfSingle => "split-dwarf-single",
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum Debugger {
-    Cdb,
-    Gdb,
-    Lldb,
-}
-
-impl Debugger {
-    fn to_str(&self) -> &'static str {
-        match self {
-            Debugger::Cdb => "cdb",
-            Debugger::Gdb => "gdb",
-            Debugger::Lldb => "lldb",
-        }
+string_enum! {
+    #[derive(Clone, Copy, Debug, PartialEq)]
+    pub enum Debugger {
+        Cdb => "cdb",
+        Gdb => "gdb",
+        Lldb => "lldb",
     }
 }
 
-impl fmt::Display for Debugger {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self.to_str(), f)
-    }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, Default, serde::Deserialize)]
+#[serde(rename_all = "kebab-case")]
 pub enum PanicStrategy {
+    #[default]
     Unwind,
     Abort,
 }
@@ -383,7 +327,7 @@ pub struct Config {
     /// Only rerun the tests that result has been modified accoring to Git status
     pub only_modified: bool,
 
-    pub target_cfg: LazyCell,
+    pub target_cfgs: AtomicLazyCell,
 
     pub nocapture: bool,
 }
@@ -396,8 +340,18 @@ impl Config {
         })
     }
 
-    fn target_cfg(&self) -> &TargetCfg {
-        self.target_cfg.borrow_with(|| TargetCfg::new(self))
+    pub fn target_cfgs(&self) -> &TargetCfgs {
+        match self.target_cfgs.borrow() {
+            Some(cfgs) => cfgs,
+            None => {
+                let _ = self.target_cfgs.fill(TargetCfgs::new(self));
+                self.target_cfgs.borrow().unwrap()
+            }
+        }
+    }
+
+    pub fn target_cfg(&self) -> &TargetCfg {
+        &self.target_cfgs().current
     }
 
     pub fn matches_arch(&self, arch: &str) -> bool {
@@ -449,94 +403,154 @@ impl Config {
     }
 }
 
-#[derive(Clone, Debug)]
+#[derive(Debug, Clone)]
+pub struct TargetCfgs {
+    pub current: TargetCfg,
+    pub all_targets: HashSet,
+    pub all_archs: HashSet,
+    pub all_oses: HashSet,
+    pub all_oses_and_envs: HashSet,
+    pub all_envs: HashSet,
+    pub all_abis: HashSet,
+    pub all_families: HashSet,
+    pub all_pointer_widths: HashSet,
+}
+
+impl TargetCfgs {
+    fn new(config: &Config) -> TargetCfgs {
+        let targets: HashMap = if config.stage_id.starts_with("stage0-") {
+            // #[cfg(bootstrap)]
+            // Needed only for one cycle, remove during the bootstrap bump.
+            Self::collect_all_slow(config)
+        } else {
+            serde_json::from_str(&rustc_output(
+                config,
+                &["--print=all-target-specs-json", "-Zunstable-options"],
+            ))
+            .unwrap()
+        };
+
+        let mut current = None;
+        let mut all_targets = HashSet::new();
+        let mut all_archs = HashSet::new();
+        let mut all_oses = HashSet::new();
+        let mut all_oses_and_envs = HashSet::new();
+        let mut all_envs = HashSet::new();
+        let mut all_abis = HashSet::new();
+        let mut all_families = HashSet::new();
+        let mut all_pointer_widths = HashSet::new();
+
+        for (target, cfg) in targets.into_iter() {
+            all_archs.insert(cfg.arch.clone());
+            all_oses.insert(cfg.os.clone());
+            all_oses_and_envs.insert(cfg.os_and_env());
+            all_envs.insert(cfg.env.clone());
+            all_abis.insert(cfg.abi.clone());
+            for family in &cfg.families {
+                all_families.insert(family.clone());
+            }
+            all_pointer_widths.insert(format!("{}bit", cfg.pointer_width));
+
+            if target == config.target {
+                current = Some(cfg);
+            }
+            all_targets.insert(target.into());
+        }
+
+        Self {
+            current: current.expect("current target not found"),
+            all_targets,
+            all_archs,
+            all_oses,
+            all_oses_and_envs,
+            all_envs,
+            all_abis,
+            all_families,
+            all_pointer_widths,
+        }
+    }
+
+    // #[cfg(bootstrap)]
+    // Needed only for one cycle, remove during the bootstrap bump.
+    fn collect_all_slow(config: &Config) -> HashMap {
+        let mut result = HashMap::new();
+        for target in rustc_output(config, &["--print=target-list"]).trim().lines() {
+            let json = rustc_output(
+                config,
+                &["--print=target-spec-json", "-Zunstable-options", "--target", target],
+            );
+            match serde_json::from_str(&json) {
+                Ok(res) => {
+                    result.insert(target.into(), res);
+                }
+                Err(err) => panic!("failed to parse target spec for {target}: {err}"),
+            }
+        }
+        result
+    }
+}
+
+#[derive(Clone, Debug, serde::Deserialize)]
+#[serde(rename_all = "kebab-case")]
 pub struct TargetCfg {
-    arch: String,
-    os: String,
-    env: String,
-    abi: String,
-    families: Vec,
-    pointer_width: u32,
+    pub(crate) arch: String,
+    #[serde(default = "default_os")]
+    pub(crate) os: String,
+    #[serde(default)]
+    pub(crate) env: String,
+    #[serde(default)]
+    pub(crate) abi: String,
+    #[serde(rename = "target-family", default)]
+    pub(crate) families: Vec,
+    #[serde(rename = "target-pointer-width", deserialize_with = "serde_parse_u32")]
+    pub(crate) pointer_width: u32,
+    #[serde(rename = "target-endian", default)]
     endian: Endian,
+    #[serde(rename = "panic-strategy", default)]
     panic: PanicStrategy,
 }
 
-#[derive(Eq, PartialEq, Clone, Debug)]
+impl TargetCfg {
+    pub(crate) fn os_and_env(&self) -> String {
+        format!("{}-{}", self.os, self.env)
+    }
+}
+
+fn default_os() -> String {
+    "none".into()
+}
+
+#[derive(Eq, PartialEq, Clone, Debug, Default, serde::Deserialize)]
+#[serde(rename_all = "kebab-case")]
 pub enum Endian {
+    #[default]
     Little,
     Big,
 }
 
-impl TargetCfg {
-    fn new(config: &Config) -> TargetCfg {
-        let mut command = Command::new(&config.rustc_path);
-        add_dylib_path(&mut command, iter::once(&config.compile_lib_path));
-        let output = match command
-            .arg("--print=cfg")
-            .arg("--target")
-            .arg(&config.target)
-            .args(&config.target_rustcflags)
-            .output()
-        {
-            Ok(output) => output,
-            Err(e) => panic!("error: failed to get cfg info from {:?}: {e}", config.rustc_path),
-        };
-        if !output.status.success() {
-            panic!(
-                "error: failed to get cfg info from {:?}\n--- stdout\n{}\n--- stderr\n{}",
-                config.rustc_path,
-                String::from_utf8(output.stdout).unwrap(),
-                String::from_utf8(output.stderr).unwrap(),
-            );
-        }
-        let print_cfg = String::from_utf8(output.stdout).unwrap();
-        let mut arch = None;
-        let mut os = None;
-        let mut env = None;
-        let mut abi = None;
-        let mut families = Vec::new();
-        let mut pointer_width = None;
-        let mut endian = None;
-        let mut panic = None;
-        for line in print_cfg.lines() {
-            if let Some((name, value)) = line.split_once('=') {
-                let value = value.trim_matches('"');
-                match name {
-                    "target_arch" => arch = Some(value),
-                    "target_os" => os = Some(value),
-                    "target_env" => env = Some(value),
-                    "target_abi" => abi = Some(value),
-                    "target_family" => families.push(value.to_string()),
-                    "target_pointer_width" => pointer_width = Some(value.parse().unwrap()),
-                    "target_endian" => {
-                        endian = Some(match value {
-                            "little" => Endian::Little,
-                            "big" => Endian::Big,
-                            s => panic!("unexpected {s}"),
-                        })
-                    }
-                    "panic" => {
-                        panic = match value {
-                            "abort" => Some(PanicStrategy::Abort),
-                            "unwind" => Some(PanicStrategy::Unwind),
-                            s => panic!("unexpected {s}"),
-                        }
-                    }
-                    _ => {}
-                }
-            }
-        }
-        TargetCfg {
-            arch: arch.unwrap().to_string(),
-            os: os.unwrap().to_string(),
-            env: env.unwrap().to_string(),
-            abi: abi.unwrap().to_string(),
-            families,
-            pointer_width: pointer_width.unwrap(),
-            endian: endian.unwrap(),
-            panic: panic.unwrap(),
-        }
+fn rustc_output(config: &Config, args: &[&str]) -> String {
+    let mut command = Command::new(&config.rustc_path);
+    add_dylib_path(&mut command, iter::once(&config.compile_lib_path));
+    command.args(&config.target_rustcflags).args(args);
+    command.env("RUSTC_BOOTSTRAP", "1");
+
+    let output = match command.output() {
+        Ok(output) => output,
+        Err(e) => panic!("error: failed to run {command:?}: {e}"),
+    };
+    if !output.status.success() {
+        panic!(
+            "error: failed to run {command:?}\n--- stdout\n{}\n--- stderr\n{}",
+            String::from_utf8(output.stdout).unwrap(),
+            String::from_utf8(output.stderr).unwrap(),
+        );
     }
+    String::from_utf8(output.stdout).unwrap()
+}
+
+fn serde_parse_u32<'de, D: Deserializer<'de>>(deserializer: D) -> Result {
+    let string = String::deserialize(deserializer)?;
+    string.parse().map_err(D::Error::custom)
 }
 
 #[derive(Debug, Clone)]
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 5bc9d9afcb9d..a7efe16150ea 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -6,24 +6,19 @@ use std::io::BufReader;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
+use build_helper::ci::CiEnv;
 use tracing::*;
 
-use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PassMode};
+use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
+use crate::header::cfg::parse_cfg_name_directive;
+use crate::header::cfg::MatchOutcome;
 use crate::util;
 use crate::{extract_cdb_version, extract_gdb_version};
 
+mod cfg;
 #[cfg(test)]
 mod tests;
 
-/// The result of parse_cfg_name_directive.
-#[derive(Clone, Copy, PartialEq, Debug)]
-enum ParsedNameDirective {
-    /// No match.
-    NoMatch,
-    /// Match.
-    Match,
-}
-
 /// Properties which must be known very early, before actually running
 /// the test.
 #[derive(Default)]
@@ -150,6 +145,8 @@ pub struct TestProps {
     pub normalize_stdout: Vec<(String, String)>,
     pub normalize_stderr: Vec<(String, String)>,
     pub failure_status: i32,
+    // For UI tests, allows compiler to exit with arbitrary failure status
+    pub dont_check_failure_status: bool,
     // Whether or not `rustfix` should apply the `CodeSuggestion`s of this test and compile the
     // resulting Rust code.
     pub run_rustfix: bool,
@@ -192,6 +189,7 @@ mod directives {
     pub const CHECK_TEST_LINE_NUMBERS_MATCH: &'static str = "check-test-line-numbers-match";
     pub const IGNORE_PASS: &'static str = "ignore-pass";
     pub const FAILURE_STATUS: &'static str = "failure-status";
+    pub const DONT_CHECK_FAILURE_STATUS: &'static str = "dont-check-failure-status";
     pub const RUN_RUSTFIX: &'static str = "run-rustfix";
     pub const RUSTFIX_ONLY_MACHINE_APPLICABLE: &'static str = "rustfix-only-machine-applicable";
     pub const ASSEMBLY_OUTPUT: &'static str = "assembly-output";
@@ -239,6 +237,7 @@ impl TestProps {
             normalize_stdout: vec![],
             normalize_stderr: vec![],
             failure_status: -1,
+            dont_check_failure_status: false,
             run_rustfix: false,
             rustfix_only_machine_applicable: false,
             assembly_output: None,
@@ -278,8 +277,12 @@ impl TestProps {
     /// `//[foo]`), then the property is ignored unless `cfg` is
     /// `Some("foo")`.
     fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
-        // Mode-dependent defaults.
-        self.remap_src_base = config.mode == Mode::Ui && !config.suite.contains("rustdoc");
+        // In CI, we've sometimes encountered non-determinism related to truncating very long paths.
+        // Set a consistent (short) prefix to avoid issues, but only in CI to avoid regressing the
+        // contributor experience.
+        if CiEnv::is_ci() {
+            self.remap_src_base = config.mode == Mode::Ui && !config.suite.contains("rustdoc");
+        }
 
         let mut has_edition = false;
         if !testfile.is_dir() {
@@ -401,6 +404,12 @@ impl TestProps {
                     self.failure_status = code;
                 }
 
+                config.set_name_directive(
+                    ln,
+                    DONT_CHECK_FAILURE_STATUS,
+                    &mut self.dont_check_failure_status,
+                );
+
                 config.set_name_directive(ln, RUN_RUSTFIX, &mut self.run_rustfix);
                 config.set_name_directive(
                     ln,
@@ -647,7 +656,7 @@ impl Config {
     }
 
     fn parse_custom_normalization(&self, mut line: &str, prefix: &str) -> Option<(String, String)> {
-        if self.parse_cfg_name_directive(line, prefix) == ParsedNameDirective::Match {
+        if parse_cfg_name_directive(self, line, prefix).outcome == MatchOutcome::Match {
             let from = parse_normalization_string(&mut line)?;
             let to = parse_normalization_string(&mut line)?;
             Some((from, to))
@@ -664,68 +673,6 @@ impl Config {
         self.parse_name_directive(line, "needs-profiler-support")
     }
 
-    /// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86`
-    /// or `normalize-stderr-32bit`.
-    fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective {
-        if !line.as_bytes().starts_with(prefix.as_bytes()) {
-            return ParsedNameDirective::NoMatch;
-        }
-        if line.as_bytes().get(prefix.len()) != Some(&b'-') {
-            return ParsedNameDirective::NoMatch;
-        }
-
-        let name = line[prefix.len() + 1..].split(&[':', ' '][..]).next().unwrap();
-
-        let matches_pointer_width = || {
-            name.strip_suffix("bit")
-                .and_then(|width| width.parse::().ok())
-                .map(|width| self.get_pointer_width() == width)
-                .unwrap_or(false)
-        };
-
-        // If something is ignored for emscripten, it likely also needs to be
-        // ignored for wasm32-unknown-unknown.
-        // `wasm32-bare` is an alias to refer to just wasm32-unknown-unknown
-        // (in contrast to `wasm32` which also matches non-bare targets like
-        // asmjs-unknown-emscripten).
-        let matches_wasm32_alias = || {
-            self.target == "wasm32-unknown-unknown" && matches!(name, "emscripten" | "wasm32-bare")
-        };
-
-        let is_match = name == "test" ||
-            self.target == name ||                              // triple
-            self.matches_os(name) ||
-            self.matches_env(name) ||
-            self.matches_abi(name) ||
-            self.matches_family(name) ||
-            self.target.ends_with(name) ||                      // target and env
-            self.matches_arch(name) ||
-            matches_wasm32_alias() ||
-            matches_pointer_width() ||
-            name == self.stage_id.split('-').next().unwrap() || // stage
-            name == self.channel ||                             // channel
-            (self.target != self.host && name == "cross-compile") ||
-            (name == "endian-big" && self.is_big_endian()) ||
-            (self.remote_test_client.is_some() && name == "remote") ||
-            match self.compare_mode {
-                Some(CompareMode::Polonius) => name == "compare-mode-polonius",
-                Some(CompareMode::Chalk) => name == "compare-mode-chalk",
-                Some(CompareMode::NextSolver) => name == "compare-mode-next-solver",
-                Some(CompareMode::SplitDwarf) => name == "compare-mode-split-dwarf",
-                Some(CompareMode::SplitDwarfSingle) => name == "compare-mode-split-dwarf-single",
-                None => false,
-            } ||
-            (cfg!(debug_assertions) && name == "debug") ||
-            match self.debugger {
-                Some(Debugger::Cdb) => name == "cdb",
-                Some(Debugger::Gdb) => name == "gdb",
-                Some(Debugger::Lldb) => name == "lldb",
-                None => false,
-            };
-
-        if is_match { ParsedNameDirective::Match } else { ParsedNameDirective::NoMatch }
-    }
-
     fn has_cfg_prefix(&self, line: &str, prefix: &str) -> bool {
         // returns whether this line contains this prefix or not. For prefix
         // "ignore", returns true if line says "ignore-x86_64", "ignore-arch",
@@ -992,21 +939,44 @@ pub fn make_test_description(
                 }
             };
         }
-        ignore = match config.parse_cfg_name_directive(ln, "ignore") {
-            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 => {
-                    ignore_message = Some("cfg -> only => NoMatch");
+        {
+            let parsed = parse_cfg_name_directive(config, ln, "ignore");
+            ignore = match parsed.outcome {
+                MatchOutcome::Match => {
+                    let reason = parsed.pretty_reason.unwrap();
+                    // The ignore reason must be a &'static str, so we have to leak memory to
+                    // create it. This is fine, as the header is parsed only at the start of
+                    // compiletest so it won't grow indefinitely.
+                    ignore_message = Some(Box::leak(Box::::from(match parsed.comment {
+                        Some(comment) => format!("ignored {reason} ({comment})"),
+                        None => format!("ignored {reason}"),
+                    })) as &str);
                     true
                 }
+                MatchOutcome::NoMatch => ignore,
+                MatchOutcome::External => ignore,
+                MatchOutcome::Invalid => panic!("invalid line in {}: {ln}", path.display()),
+            };
+        }
+
+        if config.has_cfg_prefix(ln, "only") {
+            let parsed = parse_cfg_name_directive(config, ln, "only");
+            ignore = match parsed.outcome {
+                MatchOutcome::Match => ignore,
+                MatchOutcome::NoMatch => {
+                    let reason = parsed.pretty_reason.unwrap();
+                    // The ignore reason must be a &'static str, so we have to leak memory to
+                    // create it. This is fine, as the header is parsed only at the start of
+                    // compiletest so it won't grow indefinitely.
+                    ignore_message = Some(Box::leak(Box::::from(match parsed.comment {
+                        Some(comment) => format!("only executed {reason} ({comment})"),
+                        None => format!("only executed {reason}"),
+                    })) as &str);
+                    true
+                }
+                MatchOutcome::External => ignore,
+                MatchOutcome::Invalid => panic!("invalid line in {}: {ln}", path.display()),
             };
         }
 
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs
new file mode 100644
index 000000000000..3b9333dfe7a0
--- /dev/null
+++ b/src/tools/compiletest/src/header/cfg.rs
@@ -0,0 +1,320 @@
+use crate::common::{CompareMode, Config, Debugger};
+use std::collections::HashSet;
+
+const EXTRA_ARCHS: &[&str] = &["spirv"];
+
+/// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86`
+/// or `normalize-stderr-32bit`.
+pub(super) fn parse_cfg_name_directive<'a>(
+    config: &Config,
+    line: &'a str,
+    prefix: &str,
+) -> ParsedNameDirective<'a> {
+    if !line.as_bytes().starts_with(prefix.as_bytes()) {
+        return ParsedNameDirective::invalid();
+    }
+    if line.as_bytes().get(prefix.len()) != Some(&b'-') {
+        return ParsedNameDirective::invalid();
+    }
+    let line = &line[prefix.len() + 1..];
+
+    let (name, comment) =
+        line.split_once(&[':', ' ']).map(|(l, c)| (l, Some(c))).unwrap_or((line, None));
+
+    // Some of the matchers might be "" depending on what the target information is. To avoid
+    // problems we outright reject empty directives.
+    if name == "" {
+        return ParsedNameDirective::invalid();
+    }
+
+    let mut outcome = MatchOutcome::Invalid;
+    let mut message = None;
+
+    macro_rules! condition {
+        (
+            name: $name:expr,
+            $(allowed_names: $allowed_names:expr,)?
+            $(condition: $condition:expr,)?
+            message: $($message:tt)*
+        ) => {{
+            // This is not inlined to avoid problems with macro repetitions.
+            let format_message = || format!($($message)*);
+
+            if outcome != MatchOutcome::Invalid {
+                // Ignore all other matches if we already found one
+            } else if $name.custom_matches(name) {
+                message = Some(format_message());
+                if true $(&& $condition)? {
+                    outcome = MatchOutcome::Match;
+                } else {
+                    outcome = MatchOutcome::NoMatch;
+                }
+            }
+            $(else if $allowed_names.custom_contains(name) {
+                message = Some(format_message());
+                outcome = MatchOutcome::NoMatch;
+            })?
+        }};
+    }
+
+    let target_cfgs = config.target_cfgs();
+    let target_cfg = config.target_cfg();
+
+    condition! {
+        name: "test",
+        message: "always"
+    }
+    condition! {
+        name: &config.target,
+        allowed_names: &target_cfgs.all_targets,
+        message: "when the target is {name}"
+    }
+    condition! {
+        name: &[
+            Some(&*target_cfg.os),
+            // If something is ignored for emscripten, it likely also needs to be
+            // ignored for wasm32-unknown-unknown.
+            (config.target == "wasm32-unknown-unknown").then_some("emscripten"),
+        ],
+        allowed_names: &target_cfgs.all_oses,
+        message: "when the operative system is {name}"
+    }
+    condition! {
+        name: &target_cfg.env,
+        allowed_names: &target_cfgs.all_envs,
+        message: "when the target environment is {name}"
+    }
+    condition! {
+        name: &target_cfg.os_and_env(),
+        allowed_names: &target_cfgs.all_oses_and_envs,
+        message: "when the operative system and target environment are {name}"
+    }
+    condition! {
+        name: &target_cfg.abi,
+        allowed_names: &target_cfgs.all_abis,
+        message: "when the ABI is {name}"
+    }
+    condition! {
+        name: &target_cfg.arch,
+        allowed_names: ContainsEither { a: &target_cfgs.all_archs, b: &EXTRA_ARCHS },
+        message: "when the architecture is {name}"
+    }
+    condition! {
+        name: format!("{}bit", target_cfg.pointer_width),
+        allowed_names: &target_cfgs.all_pointer_widths,
+        message: "when the pointer width is {name}"
+    }
+    condition! {
+        name: &*target_cfg.families,
+        allowed_names: &target_cfgs.all_families,
+        message: "when the target family is {name}"
+    }
+
+    // `wasm32-bare` is an alias to refer to just wasm32-unknown-unknown
+    // (in contrast to `wasm32` which also matches non-bare targets like
+    // asmjs-unknown-emscripten).
+    condition! {
+        name: "wasm32-bare",
+        condition: config.target == "wasm32-unknown-unknown",
+        message: "when the target is WASM"
+    }
+
+    condition! {
+        name: "asmjs",
+        condition: config.target.starts_with("asmjs"),
+        message: "when the architecture is asm.js",
+    }
+    condition! {
+        name: "thumb",
+        condition: config.target.starts_with("thumb"),
+        message: "when the architecture is part of the Thumb family"
+    }
+
+    condition! {
+        name: &config.channel,
+        allowed_names: &["stable", "beta", "nightly"],
+        message: "when the release channel is {name}",
+    }
+    condition! {
+        name: "cross-compile",
+        condition: config.target != config.host,
+        message: "when cross-compiling"
+    }
+    condition! {
+        name: "endian-big",
+        condition: config.is_big_endian(),
+        message: "on big-endian targets",
+    }
+    condition! {
+        name: config.stage_id.split('-').next().unwrap(),
+        allowed_names: &["stage0", "stage1", "stage2"],
+        message: "when the bootstrapping stage is {name}",
+    }
+    condition! {
+        name: "remote",
+        condition: config.remote_test_client.is_some(),
+        message: "when running tests remotely",
+    }
+    condition! {
+        name: "debug",
+        condition: cfg!(debug_assertions),
+        message: "when building with debug assertions",
+    }
+    condition! {
+        name: config.debugger.as_ref().map(|d| d.to_str()),
+        allowed_names: &Debugger::STR_VARIANTS,
+        message: "when the debugger is {name}",
+    }
+    condition! {
+        name: config.compare_mode
+            .as_ref()
+            .map(|d| format!("compare-mode-{}", d.to_str())),
+        allowed_names: ContainsPrefixed {
+            prefix: "compare-mode-",
+            inner: CompareMode::STR_VARIANTS,
+        },
+        message: "when comparing with {name}",
+    }
+
+    if prefix == "ignore" && outcome == MatchOutcome::Invalid {
+        // Don't error out for ignore-tidy-* diretives, as those are not handled by compiletest.
+        if name.starts_with("tidy-") {
+            outcome = MatchOutcome::External;
+        }
+
+        // Don't error out for ignore-pass, as that is handled elsewhere.
+        if name == "pass" {
+            outcome = MatchOutcome::External;
+        }
+
+        // Don't error out for ignore-llvm-version, that has a custom syntax and is handled
+        // elsewhere.
+        if name == "llvm-version" {
+            outcome = MatchOutcome::External;
+        }
+
+        // Don't error out for ignore-llvm-version, that has a custom syntax and is handled
+        // elsewhere.
+        if name == "gdb-version" {
+            outcome = MatchOutcome::External;
+        }
+    }
+
+    ParsedNameDirective {
+        name: Some(name),
+        comment: comment.map(|c| c.trim().trim_start_matches('-').trim()),
+        outcome,
+        pretty_reason: message,
+    }
+}
+
+/// The result of parse_cfg_name_directive.
+#[derive(Clone, PartialEq, Debug)]
+pub(super) struct ParsedNameDirective<'a> {
+    pub(super) name: Option<&'a str>,
+    pub(super) pretty_reason: Option,
+    pub(super) comment: Option<&'a str>,
+    pub(super) outcome: MatchOutcome,
+}
+
+impl ParsedNameDirective<'_> {
+    fn invalid() -> Self {
+        Self { name: None, pretty_reason: None, comment: None, outcome: MatchOutcome::NoMatch }
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub(super) enum MatchOutcome {
+    /// No match.
+    NoMatch,
+    /// Match.
+    Match,
+    /// The directive was invalid.
+    Invalid,
+    /// The directive is handled by other parts of our tooling.
+    External,
+}
+
+trait CustomContains {
+    fn custom_contains(&self, item: &str) -> bool;
+}
+
+impl CustomContains for HashSet {
+    fn custom_contains(&self, item: &str) -> bool {
+        self.contains(item)
+    }
+}
+
+impl CustomContains for &[&str] {
+    fn custom_contains(&self, item: &str) -> bool {
+        self.contains(&item)
+    }
+}
+
+impl CustomContains for [&str; N] {
+    fn custom_contains(&self, item: &str) -> bool {
+        self.contains(&item)
+    }
+}
+
+struct ContainsPrefixed {
+    prefix: &'static str,
+    inner: T,
+}
+
+impl CustomContains for ContainsPrefixed {
+    fn custom_contains(&self, item: &str) -> bool {
+        match item.strip_prefix(self.prefix) {
+            Some(stripped) => self.inner.custom_contains(stripped),
+            None => false,
+        }
+    }
+}
+
+struct ContainsEither<'a, A: CustomContains, B: CustomContains> {
+    a: &'a A,
+    b: &'a B,
+}
+
+impl CustomContains for ContainsEither<'_, A, B> {
+    fn custom_contains(&self, item: &str) -> bool {
+        self.a.custom_contains(item) || self.b.custom_contains(item)
+    }
+}
+
+trait CustomMatches {
+    fn custom_matches(&self, name: &str) -> bool;
+}
+
+impl CustomMatches for &str {
+    fn custom_matches(&self, name: &str) -> bool {
+        name == *self
+    }
+}
+
+impl CustomMatches for String {
+    fn custom_matches(&self, name: &str) -> bool {
+        name == self
+    }
+}
+
+impl CustomMatches for &[T] {
+    fn custom_matches(&self, name: &str) -> bool {
+        self.iter().any(|m| m.custom_matches(name))
+    }
+}
+
+impl CustomMatches for [T; N] {
+    fn custom_matches(&self, name: &str) -> bool {
+        self.iter().any(|m| m.custom_matches(name))
+    }
+}
+
+impl CustomMatches for Option {
+    fn custom_matches(&self, name: &str) -> bool {
+        match self {
+            Some(inner) => inner.custom_matches(name),
+            None => false,
+        }
+    }
+}
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index e42b8c524084..acd588d7fee0 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -47,7 +47,7 @@ fn config() -> Config {
         "--src-base=",
         "--build-base=",
         "--sysroot-base=",
-        "--stage-id=stage2",
+        "--stage-id=stage2-x86_64-unknown-linux-gnu",
         "--cc=c",
         "--cxx=c++",
         "--cflags=",
@@ -174,7 +174,7 @@ fn ignore_target() {
     assert!(check_ignore(&config, "// ignore-gnu"));
     assert!(check_ignore(&config, "// ignore-64bit"));
 
-    assert!(!check_ignore(&config, "// ignore-i686"));
+    assert!(!check_ignore(&config, "// ignore-x86"));
     assert!(!check_ignore(&config, "// ignore-windows"));
     assert!(!check_ignore(&config, "// ignore-msvc"));
     assert!(!check_ignore(&config, "// ignore-32bit"));
@@ -200,7 +200,7 @@ fn only_target() {
 #[test]
 fn stage() {
     let mut config = config();
-    config.stage_id = "stage1".to_owned();
+    config.stage_id = "stage1-x86_64-unknown-linux-gnu".to_owned();
 
     assert!(check_ignore(&config, "// ignore-stage1"));
     assert!(!check_ignore(&config, "// ignore-stage2"));
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 7048b0e08bbf..cfb1ee34f679 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -6,12 +6,12 @@
 extern crate test;
 
 use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
-use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, TestPaths};
+use crate::common::{Config, Debugger, Mode, PassMode, TestPaths};
 use crate::util::logv;
 use build_helper::git::{get_git_modified_files, get_git_untracked_files};
 use core::panic;
 use getopts::Options;
-use lazycell::LazyCell;
+use lazycell::AtomicLazyCell;
 use std::collections::BTreeSet;
 use std::ffi::OsString;
 use std::fs;
@@ -25,6 +25,7 @@ use tracing::*;
 use walkdir::WalkDir;
 
 use self::header::{make_test_description, EarlyProps};
+use std::sync::Arc;
 
 #[cfg(test)]
 mod tests;
@@ -42,7 +43,7 @@ pub mod util;
 fn main() {
     tracing_subscriber::fmt::init();
 
-    let config = parse_config(env::args().collect());
+    let config = Arc::new(parse_config(env::args().collect()));
 
     if config.valgrind_path.is_none() && config.force_valgrind {
         panic!("Can't find Valgrind to run Valgrind tests");
@@ -293,7 +294,9 @@ pub fn parse_config(args: Vec) -> Config {
         only_modified: matches.opt_present("only-modified"),
         color,
         remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from),
-        compare_mode: matches.opt_str("compare-mode").map(CompareMode::parse),
+        compare_mode: matches
+            .opt_str("compare-mode")
+            .map(|s| s.parse().expect("invalid --compare-mode provided")),
         rustfix_coverage: matches.opt_present("rustfix-coverage"),
         has_tidy,
         channel: matches.opt_str("channel").unwrap(),
@@ -311,7 +314,7 @@ pub fn parse_config(args: Vec) -> Config {
 
         force_rerun: matches.opt_present("force-rerun"),
 
-        target_cfg: LazyCell::new(),
+        target_cfgs: AtomicLazyCell::new(),
 
         nocapture: matches.opt_present("nocapture"),
     }
@@ -367,7 +370,7 @@ pub fn opt_str2(maybestr: Option) -> String {
     }
 }
 
-pub fn run_tests(config: Config) {
+pub fn run_tests(config: Arc) {
     // If we want to collect rustfix coverage information,
     // we first make sure that the coverage file does not exist.
     // It will be created later on.
@@ -409,7 +412,7 @@ pub fn run_tests(config: Config) {
     };
 
     let mut tests = Vec::new();
-    for c in &configs {
+    for c in configs {
         let mut found_paths = BTreeSet::new();
         make_tests(c, &mut tests, &mut found_paths);
         check_overlapping_tests(&found_paths);
@@ -431,7 +434,11 @@ pub fn run_tests(config: Config) {
             println!(
                 "Some tests failed in compiletest suite={}{} mode={} host={} target={}",
                 config.suite,
-                config.compare_mode.map(|c| format!(" compare_mode={:?}", c)).unwrap_or_default(),
+                config
+                    .compare_mode
+                    .as_ref()
+                    .map(|c| format!(" compare_mode={:?}", c))
+                    .unwrap_or_default(),
                 config.mode,
                 config.host,
                 config.target
@@ -451,13 +458,13 @@ pub fn run_tests(config: Config) {
     }
 }
 
-fn configure_cdb(config: &Config) -> Option {
+fn configure_cdb(config: &Config) -> Option> {
     config.cdb.as_ref()?;
 
-    Some(Config { debugger: Some(Debugger::Cdb), ..config.clone() })
+    Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() }))
 }
 
-fn configure_gdb(config: &Config) -> Option {
+fn configure_gdb(config: &Config) -> Option> {
     config.gdb_version?;
 
     if config.matches_env("msvc") {
@@ -488,10 +495,10 @@ fn configure_gdb(config: &Config) -> Option {
         env::set_var("RUST_TEST_THREADS", "1");
     }
 
-    Some(Config { debugger: Some(Debugger::Gdb), ..config.clone() })
+    Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() }))
 }
 
-fn configure_lldb(config: &Config) -> Option {
+fn configure_lldb(config: &Config) -> Option> {
     config.lldb_python_dir.as_ref()?;
 
     if let Some(350) = config.lldb_version {
@@ -504,7 +511,7 @@ fn configure_lldb(config: &Config) -> Option {
         return None;
     }
 
-    Some(Config { debugger: Some(Debugger::Lldb), ..config.clone() })
+    Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() }))
 }
 
 pub fn test_opts(config: &Config) -> test::TestOpts {
@@ -539,17 +546,17 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
 }
 
 pub fn make_tests(
-    config: &Config,
+    config: Arc,
     tests: &mut Vec,
     found_paths: &mut BTreeSet,
 ) {
     debug!("making tests from {:?}", config.src_base.display());
-    let inputs = common_inputs_stamp(config);
-    let modified_tests = modified_tests(config, &config.src_base).unwrap_or_else(|err| {
+    let inputs = common_inputs_stamp(&config);
+    let modified_tests = modified_tests(&config, &config.src_base).unwrap_or_else(|err| {
         panic!("modified_tests got error from dir: {}, error: {}", config.src_base.display(), err)
     });
     collect_tests_from_dir(
-        config,
+        config.clone(),
         &config.src_base,
         &PathBuf::new(),
         &inputs,
@@ -620,7 +627,7 @@ fn modified_tests(config: &Config, dir: &Path) -> Result, String> {
 }
 
 fn collect_tests_from_dir(
-    config: &Config,
+    config: Arc,
     dir: &Path,
     relative_dir_path: &Path,
     inputs: &Stamp,
@@ -648,7 +655,7 @@ fn collect_tests_from_dir(
     // sequential loop because otherwise, if we do it in the
     // tests themselves, they race for the privilege of
     // creating the directories and sometimes fail randomly.
-    let build_dir = output_relative_path(config, relative_dir_path);
+    let build_dir = output_relative_path(&config, relative_dir_path);
     fs::create_dir_all(&build_dir).unwrap();
 
     // Add each `.rs` file as a test, and recurse further on any
@@ -664,13 +671,13 @@ fn collect_tests_from_dir(
             let paths =
                 TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() };
 
-            tests.extend(make_test(config, &paths, inputs))
+            tests.extend(make_test(config.clone(), &paths, inputs))
         } else if file_path.is_dir() {
             let relative_file_path = relative_dir_path.join(file.file_name());
             if &file_name != "auxiliary" {
                 debug!("found directory: {:?}", file_path.display());
                 collect_tests_from_dir(
-                    config,
+                    config.clone(),
                     &file_path,
                     &relative_file_path,
                     inputs,
@@ -699,14 +706,18 @@ pub fn is_test(file_name: &OsString) -> bool {
     !invalid_prefixes.iter().any(|p| file_name.starts_with(p))
 }
 
-fn make_test(config: &Config, testpaths: &TestPaths, inputs: &Stamp) -> Vec {
+fn make_test(
+    config: Arc,
+    testpaths: &TestPaths,
+    inputs: &Stamp,
+) -> Vec {
     let test_path = if config.mode == Mode::RunMake {
         // Parse directives in the Makefile
         testpaths.file.join("Makefile")
     } else {
         PathBuf::from(&testpaths.file)
     };
-    let early_props = EarlyProps::from_file(config, &test_path);
+    let early_props = EarlyProps::from_file(&config, &test_path);
 
     // Incremental tests are special, they inherently cannot be run in parallel.
     // `runtest::run` will be responsible for iterating over revisions.
@@ -721,19 +732,22 @@ fn make_test(config: &Config, testpaths: &TestPaths, inputs: &Stamp) -> Vec,
     testpaths: &TestPaths,
     revision: Option<&String>,
 ) -> test::TestFn {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index a40030723105..e55c82c4b634 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -30,6 +30,7 @@ use std::iter;
 use std::path::{Path, PathBuf};
 use std::process::{Child, Command, ExitStatus, Output, Stdio};
 use std::str;
+use std::sync::Arc;
 
 use glob::glob;
 use once_cell::sync::Lazy;
@@ -96,7 +97,7 @@ pub fn get_lib_name(lib: &str, dylib: bool) -> String {
     }
 }
 
-pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) {
+pub fn run(config: Arc, testpaths: &TestPaths, revision: Option<&str>) {
     match &*config.target {
         "arm-linux-androideabi"
         | "armv7-linux-androideabi"
@@ -309,7 +310,9 @@ impl<'test> TestCx<'test> {
                 );
             }
 
-            self.check_correct_failure_status(proc_res);
+            if !self.props.dont_check_failure_status {
+                self.check_correct_failure_status(proc_res);
+            }
         }
     }
 
@@ -2132,7 +2135,7 @@ impl<'test> TestCx<'test> {
             if let Some(ref p) = self.config.nodejs {
                 args.push(p.clone());
             } else {
-                self.fatal("no NodeJS binary found (--nodejs)");
+                self.fatal("emscripten target requested and no NodeJS binary found (--nodejs)");
             }
         // If this is otherwise wasm, then run tests under nodejs with our
         // shim
@@ -2140,7 +2143,7 @@ impl<'test> TestCx<'test> {
             if let Some(ref p) = self.config.nodejs {
                 args.push(p.clone());
             } else {
-                self.fatal("no NodeJS binary found (--nodejs)");
+                self.fatal("wasm32 target requested and no NodeJS binary found (--nodejs)");
             }
 
             let src = self
@@ -2996,6 +2999,7 @@ impl<'test> TestCx<'test> {
             || host.contains("freebsd")
             || host.contains("netbsd")
             || host.contains("openbsd")
+            || host.contains("aix")
         {
             "gmake"
         } else {
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 1bf1217c83b9..f1ed3be2edd3 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-bd991d9953625e9d51fc4fcb5e19aa9c3ea598a8
+d4be8efc6296bace5b1e165f1b34d3c6da76aa8e
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 21a413002d06..8f6ae7294917 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -951,7 +951,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         if this.machine.panic_on_unsupported {
             // message is slightly different here to make automated analysis easier
             let error_msg = format!("unsupported Miri functionality: {}", error_msg.as_ref());
-            this.start_panic(error_msg.as_ref(), StackPopUnwind::Skip)?;
+            this.start_panic(error_msg.as_ref(), mir::UnwindAction::Continue)?;
             Ok(())
         } else {
             throw_unsup_format!("{}", error_msg.as_ref());
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index f95fe585a8f7..5c8aba6d441f 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -5,7 +5,6 @@
 #![feature(io_error_more)]
 #![feature(variant_count)]
 #![feature(yeet_expr)]
-#![feature(is_some_and)]
 #![feature(nonzero_ops)]
 #![feature(local_key_cell_methods)]
 #![feature(is_terminal)]
@@ -125,10 +124,13 @@ pub use crate::tag_gc::{EvalContextExt as _, VisitTags};
 
 /// Insert rustc arguments at the beginning of the argument list that Miri wants to be
 /// set per default, for maximal validation power.
+/// Also disable the MIR pass that inserts an alignment check on every pointer dereference. Miri
+/// does that too, and with a better error message.
 pub const MIRI_DEFAULT_ARGS: &[&str] = &[
     "--cfg=miri",
     "-Zalways-encode-mir",
     "-Zextra-const-ub-checks",
     "-Zmir-emit-retag",
     "-Zmir-opt-level=0",
+    "-Zmir-enable-passes=-CheckAlignment",
 ];
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index cc1964de332c..477d8d33ebba 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -834,7 +834,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
         args: &[OpTy<'tcx, Provenance>],
         dest: &PlaceTy<'tcx, Provenance>,
         ret: Option,
-        unwind: StackPopUnwind,
+        unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
         ecx.find_mir_or_eval_fn(instance, abi, args, dest, ret, unwind)
     }
@@ -847,7 +847,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
         args: &[OpTy<'tcx, Provenance>],
         dest: &PlaceTy<'tcx, Provenance>,
         ret: Option,
-        _unwind: StackPopUnwind,
+        _unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
         ecx.call_dlsym(fn_val, abi, args, dest, ret)
     }
@@ -859,7 +859,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
         args: &[OpTy<'tcx, Provenance>],
         dest: &PlaceTy<'tcx, Provenance>,
         ret: Option,
-        unwind: StackPopUnwind,
+        unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
         ecx.call_intrinsic(instance, args, dest, ret, unwind)
     }
@@ -868,7 +868,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
     fn assert_panic(
         ecx: &mut MiriInterpCx<'mir, 'tcx>,
         msg: &mir::AssertMessage<'tcx>,
-        unwind: Option,
+        unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
         ecx.assert_panic(msg, unwind)
     }
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 73439133af21..fcee381ff713 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -258,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         args: &[OpTy<'tcx, Provenance>],
         dest: &PlaceTy<'tcx, Provenance>,
         ret: Option,
-        unwind: StackPopUnwind,
+        unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
         let this = self.eval_context_mut();
         let link_name = this.item_link_name(def_id);
diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs
index 9ecbb18ef5ad..ca2c1652dc19 100644
--- a/src/tools/miri/src/shims/intrinsics/mod.rs
+++ b/src/tools/miri/src/shims/intrinsics/mod.rs
@@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         args: &[OpTy<'tcx, Provenance>],
         dest: &PlaceTy<'tcx, Provenance>,
         ret: Option,
-        _unwind: StackPopUnwind,
+        _unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs
index dbc48876a4b0..918efda3777f 100644
--- a/src/tools/miri/src/shims/mod.rs
+++ b/src/tools/miri/src/shims/mod.rs
@@ -34,7 +34,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         args: &[OpTy<'tcx, Provenance>],
         dest: &PlaceTy<'tcx, Provenance>,
         ret: Option,
-        unwind: StackPopUnwind,
+        unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
         let this = self.eval_context_mut();
         trace!("eval_fn_call: {:#?}, {:?}", instance, dest);
@@ -70,7 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         align_op: &OpTy<'tcx, Provenance>,
         dest: &PlaceTy<'tcx, Provenance>,
         ret: Option,
-        unwind: StackPopUnwind,
+        unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, bool> {
         let this = self.eval_context_mut();
         let ret = ret.unwrap();
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index acc97c4b8a0a..18ae01a19f91 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -53,7 +53,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         abi: Abi,
         link_name: Symbol,
         args: &[OpTy<'tcx, Provenance>],
-        unwind: StackPopUnwind,
+        unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
@@ -106,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             &[data.into()],
             None,
             // Directly return to caller.
-            StackPopCleanup::Goto { ret: Some(ret), unwind: StackPopUnwind::Skip },
+            StackPopCleanup::Goto { ret: Some(ret), unwind: mir::UnwindAction::Continue },
         )?;
 
         // We ourselves will return `0`, eventually (will be overwritten if we catch a panic).
@@ -157,7 +157,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 &[catch_unwind.data.into(), payload.into()],
                 None,
                 // Directly return to caller of `try`.
-                StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: StackPopUnwind::Skip },
+                StackPopCleanup::Goto {
+                    ret: Some(catch_unwind.ret),
+                    unwind: mir::UnwindAction::Continue,
+                },
             )?;
 
             // We pushed a new stack frame, the engine should not do any jumping now!
@@ -168,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     }
 
     /// Start a panic in the interpreter with the given message as payload.
-    fn start_panic(&mut self, msg: &str, unwind: StackPopUnwind) -> InterpResult<'tcx> {
+    fn start_panic(&mut self, msg: &str, unwind: mir::UnwindAction) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
         // First arg: message.
@@ -189,7 +192,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     fn assert_panic(
         &mut self,
         msg: &mir::AssertMessage<'tcx>,
-        unwind: Option,
+        unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
         use rustc_middle::mir::AssertKind::*;
         let this = self.eval_context_mut();
@@ -211,13 +214,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     Abi::Rust,
                     &[index.into(), len.into()],
                     None,
-                    StackPopCleanup::Goto {
-                        ret: None,
-                        unwind: match unwind {
-                            Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
-                            None => StackPopUnwind::Skip,
-                        },
-                    },
+                    StackPopCleanup::Goto { ret: None, unwind },
                 )?;
             }
             MisalignedPointerDereference { required, found } => {
@@ -238,25 +235,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     Abi::Rust,
                     &[required.into(), found.into()],
                     None,
-                    StackPopCleanup::Goto {
-                        ret: None,
-                        unwind: match unwind {
-                            Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
-                            None => StackPopUnwind::Skip,
-                        },
-                    },
+                    StackPopCleanup::Goto { ret: None, unwind },
                 )?;
             }
 
             _ => {
                 // Forward everything else to `panic` lang item.
-                this.start_panic(
-                    msg.description(),
-                    match unwind {
-                        Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
-                        None => StackPopUnwind::Skip,
-                    },
-                )?;
+                this.start_panic(msg.description(), unwind)?;
             }
         }
         Ok(())
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
index 484f703f9c1b..e1631471ae2b 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
@@ -1,6 +1,6 @@
 thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-error: abnormal termination: the program aborted execution
+error: abnormal termination: panic in a function that cannot unwind
   --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC
    |
 LL | / extern "C-unwind" fn nounwind() {
@@ -8,7 +8,7 @@ LL | |
 LL | |
 LL | |     panic!();
 LL | | }
-   | |_^ the program aborted execution
+   | |_^ panic in a function that cannot unwind
    |
    = note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
index 484f703f9c1b..e1631471ae2b 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
@@ -1,6 +1,6 @@
 thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-error: abnormal termination: the program aborted execution
+error: abnormal termination: panic in a function that cannot unwind
   --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC
    |
 LL | / extern "C-unwind" fn nounwind() {
@@ -8,7 +8,7 @@ LL | |
 LL | |
 LL | |     panic!();
 LL | | }
-   | |_^ the program aborted execution
+   | |_^ panic in a function that cannot unwind
    |
    = note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs
index 554cbe09cf03..65ba3433c28c 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs
@@ -4,8 +4,8 @@
 #[cfg_attr(any(definition, both), rustc_nounwind)]
 #[no_mangle]
 extern "C-unwind" fn nounwind() {
-    //~[definition]^ ERROR: abnormal termination: the program aborted execution
-    //~[both]^^ ERROR: abnormal termination: the program aborted execution
+    //~[definition]^ ERROR: abnormal termination: panic in a function that cannot unwind
+    //~[both]^^ ERROR: abnormal termination: panic in a function that cannot unwind
     panic!();
 }
 
diff --git a/src/tools/miri/tests/fail/terminate-terminator.rs b/src/tools/miri/tests/fail/terminate-terminator.rs
new file mode 100644
index 000000000000..f4931659fc82
--- /dev/null
+++ b/src/tools/miri/tests/fail/terminate-terminator.rs
@@ -0,0 +1,27 @@
+//@compile-flags: -Zmir-opt-level=3
+// Enable MIR inlining to ensure that `TerminatorKind::Terminate` is generated
+// instead of just `UnwindAction::Terminate`.
+
+#![feature(c_unwind)]
+
+struct Foo;
+
+impl Drop for Foo {
+    fn drop(&mut self) {}
+}
+
+#[inline(always)]
+fn has_cleanup() {
+    //~^ ERROR: panic in a function that cannot unwind
+    // FIXME(nbdd0121): The error should be reported at the call site.
+    let _f = Foo;
+    panic!();
+}
+
+extern "C" fn panic_abort() {
+    has_cleanup();
+}
+
+fn main() {
+    panic_abort();
+}
diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr
new file mode 100644
index 000000000000..c046678f73f5
--- /dev/null
+++ b/src/tools/miri/tests/fail/terminate-terminator.stderr
@@ -0,0 +1,29 @@
+warning: You have explicitly enabled MIR optimizations, overriding Miri's default which is to completely disable them. Any optimizations may hide UB that Miri would otherwise detect, and it is not necessarily possible to predict what kind of UB will be missed. If you are enabling optimizations to make Miri run faster, we advise using cfg(miri) to shrink your workload instead. The performance benefit of enabling MIR optimizations is usually marginal at best.
+
+thread 'main' panicked at 'explicit panic', $DIR/terminate-terminator.rs:LL:CC
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+error: abnormal termination: panic in a function that cannot unwind
+  --> $DIR/terminate-terminator.rs:LL:CC
+   |
+LL | / fn has_cleanup() {
+LL | |
+LL | |     // FIXME(nbdd0121): The error should be reported at the call site.
+LL | |     let _f = Foo;
+LL | |     panic!();
+LL | | }
+   | |_^ panic in a function that cannot unwind
+...
+LL |       has_cleanup();
+   |       ------------- in this inlined function call
+   |
+   = note: inside `panic_abort` at $DIR/terminate-terminator.rs:LL:CC
+note: inside `main`
+  --> $DIR/terminate-terminator.rs:LL:CC
+   |
+LL |     panic_abort();
+   |     ^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/tools/miri/tests/fail/abort-terminator.rs b/src/tools/miri/tests/fail/unwind-action-terminate.rs
similarity index 64%
rename from src/tools/miri/tests/fail/abort-terminator.rs
rename to src/tools/miri/tests/fail/unwind-action-terminate.rs
index c954443a2762..876b9a9ab0ab 100644
--- a/src/tools/miri/tests/fail/abort-terminator.rs
+++ b/src/tools/miri/tests/fail/unwind-action-terminate.rs
@@ -1,7 +1,7 @@
 #![feature(c_unwind)]
 
 extern "C" fn panic_abort() {
-    //~^ ERROR: the program aborted
+    //~^ ERROR: panic in a function that cannot unwind
     panic!()
 }
 
diff --git a/src/tools/miri/tests/fail/abort-terminator.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr
similarity index 50%
rename from src/tools/miri/tests/fail/abort-terminator.stderr
rename to src/tools/miri/tests/fail/unwind-action-terminate.stderr
index 2d3275f6b190..52a1879cb5fe 100644
--- a/src/tools/miri/tests/fail/abort-terminator.stderr
+++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr
@@ -1,17 +1,17 @@
-thread 'main' panicked at 'explicit panic', $DIR/abort-terminator.rs:LL:CC
+thread 'main' panicked at 'explicit panic', $DIR/unwind-action-terminate.rs:LL:CC
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-error: abnormal termination: the program aborted execution
-  --> $DIR/abort-terminator.rs:LL:CC
+error: abnormal termination: panic in a function that cannot unwind
+  --> $DIR/unwind-action-terminate.rs:LL:CC
    |
 LL | / extern "C" fn panic_abort() {
 LL | |
 LL | |     panic!()
 LL | | }
-   | |_^ the program aborted execution
+   | |_^ panic in a function that cannot unwind
    |
-   = note: inside `panic_abort` at $DIR/abort-terminator.rs:LL:CC
+   = note: inside `panic_abort` at $DIR/unwind-action-terminate.rs:LL:CC
 note: inside `main`
-  --> $DIR/abort-terminator.rs:LL:CC
+  --> $DIR/unwind-action-terminate.rs:LL:CC
    |
 LL |     panic_abort();
    |     ^^^^^^^^^^^^^
diff --git a/src/tools/miri/tests/panic/alignment-assertion.rs b/src/tools/miri/tests/panic/alignment-assertion.rs
deleted file mode 100644
index 68aa19a88db0..000000000000
--- a/src/tools/miri/tests/panic/alignment-assertion.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@compile-flags: -Zmiri-disable-alignment-check -Cdebug-assertions=yes
-
-fn main() {
-    let mut x = [0u32; 2];
-    let ptr: *mut u8 = x.as_mut_ptr().cast::();
-    unsafe {
-        *(ptr.add(1).cast::()) = 42;
-    }
-}
diff --git a/src/tools/miri/tests/panic/alignment-assertion.stderr b/src/tools/miri/tests/panic/alignment-assertion.stderr
deleted file mode 100644
index 26cf51b0cd2e..000000000000
--- a/src/tools/miri/tests/panic/alignment-assertion.stderr
+++ /dev/null
@@ -1,2 +0,0 @@
-thread 'main' panicked at 'misaligned pointer dereference: address must be a multiple of 0x4 but is $HEX', $DIR/alignment-assertion.rs:LL:CC
-note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index 8286bd506bca..b9cf2617ba9e 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 
 [dependencies]
 clap = "4.0.32"
-env_logger = "0.7.1"
+env_logger = "0.10"
 
 [dependencies.mdbook]
 version = "0.4.28"
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 25e8a024857c..43779cfaecd3 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -1804,13 +1804,15 @@ pub(crate) struct StaticParts<'a> {
 
 impl<'a> StaticParts<'a> {
     pub(crate) fn from_item(item: &'a ast::Item) -> Self {
-        let (defaultness, prefix, ty, mutability, expr) = match item.kind {
-            ast::ItemKind::Static(ref ty, mutability, ref expr) => {
-                (None, "static", ty, mutability, expr)
-            }
-            ast::ItemKind::Const(defaultness, ref ty, ref expr) => {
-                (Some(defaultness), "const", ty, ast::Mutability::Not, expr)
-            }
+        let (defaultness, prefix, ty, mutability, expr) = match &item.kind {
+            ast::ItemKind::Static(s) => (None, "static", &s.ty, s.mutability, &s.expr),
+            ast::ItemKind::Const(c) => (
+                Some(c.defaultness),
+                "const",
+                &c.ty,
+                ast::Mutability::Not,
+                &c.expr,
+            ),
             _ => unreachable!(),
         };
         StaticParts {
@@ -1826,10 +1828,8 @@ impl<'a> StaticParts<'a> {
     }
 
     pub(crate) fn from_trait_item(ti: &'a ast::AssocItem) -> Self {
-        let (defaultness, ty, expr_opt) = match ti.kind {
-            ast::AssocItemKind::Const(defaultness, ref ty, ref expr_opt) => {
-                (defaultness, ty, expr_opt)
-            }
+        let (defaultness, ty, expr_opt) = match &ti.kind {
+            ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr),
             _ => unreachable!(),
         };
         StaticParts {
@@ -1845,8 +1845,8 @@ impl<'a> StaticParts<'a> {
     }
 
     pub(crate) fn from_impl_item(ii: &'a ast::AssocItem) -> Self {
-        let (defaultness, ty, expr) = match ii.kind {
-            ast::AssocItemKind::Const(defaultness, ref ty, ref expr) => (defaultness, ty, expr),
+        let (defaultness, ty, expr) = match &ii.kind {
+            ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr),
             _ => unreachable!(),
         };
         StaticParts {
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index cdf1dd366046..8c6b1eb22ecb 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 autobins = false
 
 [dependencies]
-cargo_metadata = "0.14"
+cargo_metadata = "0.15"
 cargo-platform = "0.1.2"
 regex = "1"
 miropt-test-tools = { path = "../miropt-test-tools" }
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index f582666ab283..0f08f5d0b700 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -7,8 +7,8 @@ use std::collections::HashMap;
 use std::fs;
 use std::path::{Path, PathBuf};
 
-const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
+const ENTRY_LIMIT: usize = 885;
 const ROOT_ENTRY_LIMIT: usize = 881;
 const ISSUES_ENTRY_LIMIT: usize = 1978;
 
diff --git a/tests/assembly/asm/global_asm.rs b/tests/assembly/asm/global_asm.rs
index 0b361a7ed963..36f017cf9d60 100644
--- a/tests/assembly/asm/global_asm.rs
+++ b/tests/assembly/asm/global_asm.rs
@@ -25,9 +25,9 @@ global_asm!("movl ${}, %ecx", const 5, options(att_syntax));
 global_asm!("call {}", sym my_func);
 // CHECK: lea rax, [rip + MY_STATIC]
 global_asm!("lea rax, [rip + {}]", sym MY_STATIC);
-// CHECK: call _RNvCsiubXh4Yz005_10global_asm6foobar
+// CHECK: call _RNvCsddMtV7nAi4C_10global_asm6foobar
 global_asm!("call {}", sym foobar);
-// CHECK: _RNvCsiubXh4Yz005_10global_asm6foobar:
+// CHECK: _RNvCsddMtV7nAi4C_10global_asm6foobar:
 fn foobar() {
     loop {}
 }
diff --git a/tests/codegen/abi-main-signature-16bit-c-int.rs b/tests/codegen/abi-main-signature-16bit-c-int.rs
index 4ed491dfb2b4..3548cc06a5b6 100644
--- a/tests/codegen/abi-main-signature-16bit-c-int.rs
+++ b/tests/codegen/abi-main-signature-16bit-c-int.rs
@@ -17,7 +17,6 @@
 // ignore-wasm32
 // ignore-x86
 // ignore-x86_64
-// ignore-xcore
 
 fn main() {
 }
diff --git a/tests/codegen/consts.rs b/tests/codegen/consts.rs
index 8a135039c066..fc2badc417c2 100644
--- a/tests/codegen/consts.rs
+++ b/tests/codegen/consts.rs
@@ -9,7 +9,7 @@
 // CHECK: @STATIC = {{.*}}, align 4
 
 // This checks the constants from inline_enum_const
-// CHECK: @alloc_701ed935fbda2002838d0a2cbbc171e5 = {{.*}}, align 2
+// CHECK: @alloc_af1f8e8e6f4b341431a1d405e652df2d = {{.*}}, align 2
 
 // This checks the constants from {low,high}_align_const, they share the same
 // constant, but the alignment differs, so the higher one should be used
diff --git a/tests/codegen/debug-limited.rs b/tests/codegen/debug-limited.rs
new file mode 100644
index 000000000000..48d676887fdd
--- /dev/null
+++ b/tests/codegen/debug-limited.rs
@@ -0,0 +1,27 @@
+// Verify that the limited debuginfo option emits llvm's FullDebugInfo, but no type info.
+//
+// compile-flags: -C debuginfo=limited
+
+#[repr(C)]
+struct StructType {
+    a: i64,
+    b: i32,
+}
+
+extern "C" {
+    fn creator() -> *mut StructType;
+    fn save(p: *const StructType);
+}
+
+fn main() {
+    unsafe {
+        let value: &mut StructType = &mut *creator();
+        value.a = 7;
+        save(value as *const StructType)
+    }
+}
+
+// CHECK: !DICompileUnit
+// CHECK: emissionKind: FullDebug
+// CHECK: !DILocation
+// CHECK-NOT: !DIBasicType
diff --git a/tests/codegen/debug-line-directives-only.rs b/tests/codegen/debug-line-directives-only.rs
new file mode 100644
index 000000000000..750bdd49de07
--- /dev/null
+++ b/tests/codegen/debug-line-directives-only.rs
@@ -0,0 +1,27 @@
+// Verify that the only debuginfo generated are the line directives.
+//
+// compile-flags: -C debuginfo=line-directives-only
+
+#[repr(C)]
+struct StructType {
+    a: i64,
+    b: i32,
+}
+
+extern "C" {
+    fn creator() -> *mut StructType;
+    fn save(p: *const StructType);
+}
+
+fn main() {
+    unsafe {
+        let value: &mut StructType = &mut *creator();
+        value.a = 7;
+        save(value as *const StructType)
+    }
+}
+
+// CHECK: !DICompileUnit
+// CHECK: emissionKind: DebugDirectivesOnly
+// CHECK: !DILocation
+// CHECK-NOT: !DIBasicType
diff --git a/tests/codegen/debug-line-tables-only.rs b/tests/codegen/debug-line-tables-only.rs
new file mode 100644
index 000000000000..3ed165a6f696
--- /dev/null
+++ b/tests/codegen/debug-line-tables-only.rs
@@ -0,0 +1,27 @@
+// Verify that the only debuginfo generated are the line tables.
+//
+// compile-flags: -C debuginfo=line-tables-only
+
+#[repr(C)]
+struct StructType {
+    a: i64,
+    b: i32,
+}
+
+extern "C" {
+    fn creator() -> *mut StructType;
+    fn save(p: *const StructType);
+}
+
+fn main() {
+    unsafe {
+        let value: &mut StructType = &mut *creator();
+        value.a = 7;
+        save(value as *const StructType)
+    }
+}
+
+// CHECK: !DICompileUnit
+// CHECK: emissionKind: LineTablesOnly
+// CHECK: !DILocation
+// CHECK-NOT: !DIBasicType
diff --git a/tests/codegen/global_asm.rs b/tests/codegen/global_asm.rs
index fab84868fdfb..9912b1e75bf5 100644
--- a/tests/codegen/global_asm.rs
+++ b/tests/codegen/global_asm.rs
@@ -1,39 +1,20 @@
 // ignore-aarch64
-// ignore-aarch64_be
 // ignore-arm
-// ignore-armeb
 // ignore-avr
-// ignore-bpfel
-// ignore-bpfeb
+// ignore-bpf
+// ignore-bpf
 // ignore-hexagon
 // ignore-mips
 // ignore-mips64
 // ignore-msp430
 // ignore-powerpc64
-// ignore-powerpc64le
 // ignore-powerpc
-// ignore-r600
-// ignore-amdgcn
 // ignore-sparc
-// ignore-sparcv9
-// ignore-sparcel
+// ignore-sparc64
 // ignore-s390x
-// ignore-tce
 // ignore-thumb
-// ignore-thumbeb
-// ignore-xcore
-// ignore-nvptx
 // ignore-nvptx64
-// ignore-le32
-// ignore-le64
-// ignore-amdil
-// ignore-amdil64
-// ignore-hsail
-// ignore-hsail64
-// ignore-spir
-// ignore-spir64
-// ignore-kalimba
-// ignore-shave
+// ignore-spirv
 // ignore-wasm32
 // ignore-wasm64
 // ignore-emscripten
diff --git a/tests/codegen/global_asm_include.rs b/tests/codegen/global_asm_include.rs
index 02ee916458f4..b68c5ad3b9dd 100644
--- a/tests/codegen/global_asm_include.rs
+++ b/tests/codegen/global_asm_include.rs
@@ -1,39 +1,20 @@
 // ignore-aarch64
-// ignore-aarch64_be
 // ignore-arm
-// ignore-armeb
 // ignore-avr
-// ignore-bpfel
-// ignore-bpfeb
+// ignore-bpf
+// ignore-bpf
 // ignore-hexagon
 // ignore-mips
 // ignore-mips64
 // ignore-msp430
 // ignore-powerpc64
-// ignore-powerpc64le
 // ignore-powerpc
-// ignore-r600
-// ignore-amdgcn
 // ignore-sparc
-// ignore-sparcv9
-// ignore-sparcel
+// ignore-sparc64
 // ignore-s390x
-// ignore-tce
 // ignore-thumb
-// ignore-thumbeb
-// ignore-xcore
-// ignore-nvptx
 // ignore-nvptx64
-// ignore-le32
-// ignore-le64
-// ignore-amdil
-// ignore-amdil64
-// ignore-hsail
-// ignore-hsail64
-// ignore-spir
-// ignore-spir64
-// ignore-kalimba
-// ignore-shave
+// ignore-spirv
 // ignore-wasm32
 // ignore-wasm64
 // ignore-emscripten
diff --git a/tests/codegen/global_asm_x2.rs b/tests/codegen/global_asm_x2.rs
index bdcf0ea843c4..d87e02befb9b 100644
--- a/tests/codegen/global_asm_x2.rs
+++ b/tests/codegen/global_asm_x2.rs
@@ -1,39 +1,20 @@
 // ignore-aarch64
-// ignore-aarch64_be
 // ignore-arm
-// ignore-armeb
 // ignore-avr
-// ignore-bpfel
-// ignore-bpfeb
+// ignore-bpf
+// ignore-bpf
 // ignore-hexagon
 // ignore-mips
 // ignore-mips64
 // ignore-msp430
 // ignore-powerpc64
-// ignore-powerpc64le
 // ignore-powerpc
-// ignore-r600
-// ignore-amdgcn
 // ignore-sparc
-// ignore-sparcv9
-// ignore-sparcel
+// ignore-sparc64
 // ignore-s390x
-// ignore-tce
 // ignore-thumb
-// ignore-thumbeb
-// ignore-xcore
-// ignore-nvptx
 // ignore-nvptx64
-// ignore-le32
-// ignore-le64
-// ignore-amdil
-// ignore-amdil64
-// ignore-hsail
-// ignore-hsail64
-// ignore-spir
-// ignore-spir64
-// ignore-kalimba
-// ignore-shave
+// ignore-spirv
 // ignore-wasm32
 // ignore-wasm64
 // ignore-emscripten
diff --git a/tests/codegen/intrinsics/transmute-x64.rs b/tests/codegen/intrinsics/transmute-x64.rs
new file mode 100644
index 000000000000..99d258c62040
--- /dev/null
+++ b/tests/codegen/intrinsics/transmute-x64.rs
@@ -0,0 +1,35 @@
+// compile-flags: -O -C no-prepopulate-passes
+// only-x86_64 (it's using arch-specific types)
+// min-llvm-version: 15.0 # this test assumes `ptr`s
+
+#![crate_type = "lib"]
+
+use std::arch::x86_64::{__m128, __m128i, __m256i};
+use std::mem::transmute;
+
+// CHECK-LABEL: @check_sse_float_to_int(
+#[no_mangle]
+pub unsafe fn check_sse_float_to_int(x: __m128) -> __m128i {
+    // CHECK-NOT: alloca
+    // CHECK: %1 = load <4 x float>, ptr %x, align 16
+    // CHECK: store <4 x float> %1, ptr %0, align 16
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_sse_pair_to_avx(
+#[no_mangle]
+pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i {
+    // CHECK-NOT: alloca
+    // CHECK: %1 = load <4 x i64>, ptr %x, align 16
+    // CHECK: store <4 x i64> %1, ptr %0, align 32
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_sse_pair_from_avx(
+#[no_mangle]
+pub unsafe fn check_sse_pair_from_avx(x: __m256i) -> (__m128i, __m128i) {
+    // CHECK-NOT: alloca
+    // CHECK: %1 = load <4 x i64>, ptr %x, align 32
+    // CHECK: store <4 x i64> %1, ptr %0, align 16
+    transmute(x)
+}
diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs
index cefcf9ed9caa..57f901c67199 100644
--- a/tests/codegen/intrinsics/transmute.rs
+++ b/tests/codegen/intrinsics/transmute.rs
@@ -6,8 +6,9 @@
 #![feature(core_intrinsics)]
 #![feature(custom_mir)]
 #![feature(inline_const)]
+#![allow(unreachable_code)]
 
-use std::mem::transmute;
+use std::mem::{transmute, MaybeUninit};
 
 // Some of the cases here are statically rejected by `mem::transmute`, so
 // we need to generate custom MIR for those cases to get to codegen.
@@ -24,6 +25,9 @@ pub struct Scalar64(i64);
 #[repr(C, align(4))]
 pub struct Aggregate64(u16, u8, i8, f32);
 
+#[repr(C)]
+pub struct Aggregate8(u8);
+
 // CHECK-LABEL: @check_bigger_size(
 #[no_mangle]
 #[custom_mir(dialect = "runtime", phase = "initial")]
@@ -50,6 +54,32 @@ pub unsafe fn check_smaller_size(x: u32) -> u16 {
     }
 }
 
+// CHECK-LABEL: @check_smaller_array(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "initial")]
+pub unsafe fn check_smaller_array(x: [u32; 7]) -> [u32; 3] {
+    // CHECK: call void @llvm.trap
+    mir!{
+        {
+            RET = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_bigger_array(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "initial")]
+pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] {
+    // CHECK: call void @llvm.trap
+    mir!{
+        {
+            RET = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
 // CHECK-LABEL: @check_to_uninhabited(
 #[no_mangle]
 #[custom_mir(dialect = "runtime", phase = "initial")]
@@ -67,7 +97,7 @@ pub unsafe fn check_to_uninhabited(x: u16) -> BigNever {
 #[no_mangle]
 #[custom_mir(dialect = "runtime", phase = "initial")]
 pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 {
-    // CHECK: call void @llvm.trap
+    // CHECK: ret i16 poison
     mir!{
         {
             RET = CastTransmute(x);
@@ -76,23 +106,80 @@ pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 {
     }
 }
 
+// CHECK-LABEL: @check_intermediate_passthrough(
+#[no_mangle]
+pub unsafe fn check_intermediate_passthrough(x: u32) -> i32 {
+    // CHECK: start
+    // CHECK: %[[TMP:.+]] = add i32 1, %x
+    // CHECK: %[[RET:.+]] = add i32 %[[TMP]], 1
+    // CHECK: ret i32 %[[RET]]
+    unsafe {
+        transmute::(1 + x) + 1
+    }
+}
+
+// CHECK-LABEL: @check_nop_pair(
+#[no_mangle]
+pub unsafe fn check_nop_pair(x: (u8, i8)) -> (i8, u8) {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = insertvalue { i8, i8 } poison, i8 %x.0, 0
+    // CHECK: %1 = insertvalue { i8, i8 } %0, i8 %x.1, 1
+    // CHECK: ret { i8, i8 } %1
+    unsafe {
+        transmute(x)
+    }
+}
+
 // CHECK-LABEL: @check_to_newtype(
 #[no_mangle]
 pub unsafe fn check_to_newtype(x: u64) -> Scalar64 {
-    // CHECK: %0 = alloca i64
-    // CHECK: store i64 %x, ptr %0
-    // CHECK: %1 = load i64, ptr %0
-    // CHECK: ret i64 %1
+    // CHECK-NOT: alloca
+    // CHECK: ret i64 %x
     transmute(x)
 }
 
 // CHECK-LABEL: @check_from_newtype(
 #[no_mangle]
 pub unsafe fn check_from_newtype(x: Scalar64) -> u64 {
-    // CHECK: %0 = alloca i64
-    // CHECK: store i64 %x, ptr %0
-    // CHECK: %1 = load i64, ptr %0
-    // CHECK: ret i64 %1
+    // CHECK-NOT: alloca
+    // CHECK: ret i64 %x
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_aggregate_to_bool(
+#[no_mangle]
+pub unsafe fn check_aggregate_to_bool(x: Aggregate8) -> bool {
+    // CHECK: %x = alloca %Aggregate8, align 1
+    // CHECK: %[[BYTE:.+]] = load i8, ptr %x, align 1
+    // CHECK: %[[BOOL:.+]] = trunc i8 %[[BYTE]] to i1
+    // CHECK: ret i1 %[[BOOL]]
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_aggregate_from_bool(
+#[no_mangle]
+pub unsafe fn check_aggregate_from_bool(x: bool) -> Aggregate8 {
+    // CHECK: %0 = alloca %Aggregate8, align 1
+    // CHECK: %[[BYTE:.+]] = zext i1 %x to i8
+    // CHECK: store i8 %[[BYTE]], ptr %0, align 1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_byte_to_bool(
+#[no_mangle]
+pub unsafe fn check_byte_to_bool(x: u8) -> bool {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = trunc i8 %x to i1
+    // CHECK: ret i1 %0
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_byte_from_bool(
+#[no_mangle]
+pub unsafe fn check_byte_from_bool(x: bool) -> u8 {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = zext i1 %x to i8
+    // CHECK: ret i8 %0
     transmute(x)
 }
 
@@ -122,20 +209,18 @@ pub unsafe fn check_from_pair(x: Option) -> u64 {
 // CHECK-LABEL: @check_to_float(
 #[no_mangle]
 pub unsafe fn check_to_float(x: u32) -> f32 {
-    // CHECK: %0 = alloca float
-    // CHECK: store i32 %x, ptr %0
-    // CHECK: %1 = load float, ptr %0
-    // CHECK: ret float %1
+    // CHECK-NOT: alloca
+    // CHECK: %0 = bitcast i32 %x to float
+    // CHECK: ret float %0
     transmute(x)
 }
 
 // CHECK-LABEL: @check_from_float(
 #[no_mangle]
 pub unsafe fn check_from_float(x: f32) -> u32 {
-    // CHECK: %0 = alloca i32
-    // CHECK: store float %x, ptr %0
-    // CHECK: %1 = load i32, ptr %0
-    // CHECK: ret i32 %1
+    // CHECK-NOT: alloca
+    // CHECK: %0 = bitcast float %x to i32
+    // CHECK: ret i32 %0
     transmute(x)
 }
 
@@ -144,19 +229,15 @@ pub unsafe fn check_from_float(x: f32) -> u32 {
 pub unsafe fn check_to_bytes(x: u32) -> [u8; 4] {
     // CHECK: %0 = alloca [4 x i8], align 1
     // CHECK: store i32 %x, ptr %0, align 1
-    // CHECK: %1 = load i32, ptr %0, align 1
-    // CHECK: ret i32 %1
     transmute(x)
 }
 
 // CHECK-LABEL: @check_from_bytes(
 #[no_mangle]
 pub unsafe fn check_from_bytes(x: [u8; 4]) -> u32 {
-    // CHECK: %1 = alloca i32, align 4
     // CHECK: %x = alloca [4 x i8], align 1
-    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %1, ptr align 1 %x, i64 4, i1 false)
-    // CHECK: %3 = load i32, ptr %1, align 4
-    // CHECK: ret i32 %3
+    // CHECK: %[[VAL:.+]] = load i32, ptr %x, align 1
+    // CHECK: ret i32 %[[VAL]]
     transmute(x)
 }
 
@@ -173,7 +254,9 @@ pub unsafe fn check_to_aggregate(x: u64) -> Aggregate64 {
 // CHECK-LABEL: @check_from_aggregate(
 #[no_mangle]
 pub unsafe fn check_from_aggregate(x: Aggregate64) -> u64 {
-    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %{{[0-9]+}}, ptr align 4 %x, i64 8, i1 false)
+    // CHECK: %x = alloca %Aggregate64, align 4
+    // CHECK: %[[VAL:.+]] = load i64, ptr %x, align 4
+    // CHECK: ret i64 %[[VAL]]
     transmute(x)
 }
 
@@ -194,3 +277,155 @@ pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] {
     // CHECK-NEXT: ret void
     transmute(x)
 }
+
+// CHECK-LABEL: @check_pair_with_bool(
+#[no_mangle]
+pub unsafe fn check_pair_with_bool(x: (u8, bool)) -> (bool, i8) {
+    // CHECK-NOT: alloca
+    // CHECK: trunc i8 %x.0 to i1
+    // CHECK: zext i1 %x.1 to i8
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_float_to_pointer(
+#[no_mangle]
+pub unsafe fn check_float_to_pointer(x: f64) -> *const () {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = bitcast double %x to i64
+    // CHECK: %1 = inttoptr i64 %0 to ptr
+    // CHECK: ret ptr %1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_float_from_pointer(
+#[no_mangle]
+pub unsafe fn check_float_from_pointer(x: *const ()) -> f64 {
+    // CHECK-NOT: alloca
+    // CHECK: %0 = ptrtoint ptr %x to i64
+    // CHECK: %1 = bitcast i64 %0 to double
+    // CHECK: ret double %1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_array_to_pair(
+#[no_mangle]
+pub unsafe fn check_array_to_pair(x: [u8; 16]) -> (i64, u64) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[FST:.+]] = load i64, ptr %{{.+}}, align 1, !noundef !
+    // CHECK: %[[SND:.+]] = load i64, ptr %{{.+}}, align 1, !noundef !
+    // CHECK: %[[PAIR0:.+]] = insertvalue { i64, i64 } poison, i64 %[[FST]], 0
+    // CHECK: %[[PAIR01:.+]] = insertvalue { i64, i64 } %[[PAIR0]], i64 %[[SND]], 1
+    // CHECK: ret { i64, i64 } %[[PAIR01]]
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_pair_to_array(
+#[no_mangle]
+pub unsafe fn check_pair_to_array(x: (i64, u64)) -> [u8; 16] {
+    // CHECK-NOT: alloca
+    // CHECK: store i64 %x.0, ptr %{{.+}}, align 1
+    // CHECK: store i64 %x.1, ptr %{{.+}}, align 1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_heterogeneous_integer_pair(
+#[no_mangle]
+pub unsafe fn check_heterogeneous_integer_pair(x: (i32, bool)) -> (bool, u32) {
+    // CHECK: store i32 %x.0
+    // CHECK: %[[WIDER:.+]] = zext i1 %x.1 to i8
+    // CHECK: store i8 %[[WIDER]]
+
+    // CHECK: %[[BYTE:.+]] = load i8
+    // CHECK: trunc i8 %[[BYTE:.+]] to i1
+    // CHECK: load i32
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_heterogeneous_float_pair(
+#[no_mangle]
+pub unsafe fn check_heterogeneous_float_pair(x: (f64, f32)) -> (f32, f64) {
+    // CHECK: store double %x.0
+    // CHECK: store float %x.1
+    // CHECK: %[[A:.+]] = load float
+    // CHECK: %[[B:.+]] = load double
+    // CHECK: %[[P:.+]] = insertvalue { float, double } poison, float %[[A]], 0
+    // CHECK: insertvalue { float, double } %[[P]], double %[[B]], 1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_issue_110005(
+#[no_mangle]
+pub unsafe fn check_issue_110005(x: (usize, bool)) -> Option> {
+    // CHECK: store i64 %x.0
+    // CHECK: %[[WIDER:.+]] = zext i1 %x.1 to i8
+    // CHECK: store i8 %[[WIDER]]
+    // CHECK: load ptr
+    // CHECK: load i64
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_pair_to_dst_ref(
+#[no_mangle]
+pub unsafe fn check_pair_to_dst_ref<'a>(x: (usize, usize)) -> &'a [u8] {
+    // CHECK: %0 = inttoptr i64 %x.0 to ptr
+    // CHECK: %1 = insertvalue { ptr, i64 } poison, ptr %0, 0
+    // CHECK: %2 = insertvalue { ptr, i64 } %1, i64 %x.1, 1
+    // CHECK: ret { ptr, i64 } %2
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_issue_109992(
+#[no_mangle]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub unsafe fn check_issue_109992(x: ()) -> [(); 1] {
+    // This uses custom MIR to avoid MIR optimizations having removed ZST ops.
+
+    // CHECK: start
+    // CHECK-NEXT: ret void
+    mir!{
+        {
+            RET = CastTransmute(x);
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @check_maybe_uninit_pair(i16 %x.0, i64 %x.1)
+#[no_mangle]
+pub unsafe fn check_maybe_uninit_pair(
+    x: (MaybeUninit, MaybeUninit),
+) -> (MaybeUninit, MaybeUninit) {
+    // Thanks to `MaybeUninit` this is actually defined behaviour,
+    // unlike the examples above with pairs of primitives.
+
+    // CHECK: store i16 %x.0
+    // CHECK: store i64 %x.1
+    // CHECK: load i64
+    // CHECK-NOT: noundef
+    // CHECK: load i16
+    // CHECK-NOT: noundef
+    // CHECK: ret { i64, i16 }
+    transmute(x)
+}
+
+#[repr(align(8))]
+pub struct HighAlignScalar(u8);
+
+// CHECK-LABEL: @check_to_overalign(
+#[no_mangle]
+pub unsafe fn check_to_overalign(x: u64) -> HighAlignScalar {
+    // CHECK: %0 = alloca %HighAlignScalar, align 8
+    // CHECK: store i64 %x, ptr %0, align 8
+    // CHECK: %1 = load i64, ptr %0, align 8
+    // CHECK: ret i64 %1
+    transmute(x)
+}
+
+// CHECK-LABEL: @check_from_overalign(
+#[no_mangle]
+pub unsafe fn check_from_overalign(x: HighAlignScalar) -> u64 {
+    // CHECK: %x = alloca %HighAlignScalar, align 8
+    // CHECK: %[[VAL:.+]] = load i64, ptr %x, align 8
+    // CHECK: ret i64 %[[VAL]]
+    transmute(x)
+}
diff --git a/tests/codegen/issues/issue-37945.rs b/tests/codegen/issues/issue-37945.rs
index 19e7e8b1f6e1..4f386d335c7d 100644
--- a/tests/codegen/issues/issue-37945.rs
+++ b/tests/codegen/issues/issue-37945.rs
@@ -1,9 +1,5 @@
 // compile-flags: -O -Zmerge-functions=disabled
-// ignore-x86
-// ignore-arm
-// ignore-emscripten
-// ignore-gnux32
-// ignore 32-bit platforms (LLVM has a bug with them)
+// ignore-32bit LLVM has a bug with them
 // ignore-debug
 
 // Check that LLVM understands that `Iter` pointer is not null. Issue #37945.
diff --git a/tests/codegen/remap_path_prefix/main.rs b/tests/codegen/remap_path_prefix/main.rs
index 85523d053b59..f1e1dd69b969 100644
--- a/tests/codegen/remap_path_prefix/main.rs
+++ b/tests/codegen/remap_path_prefix/main.rs
@@ -12,7 +12,7 @@ mod aux_mod;
 include!("aux_mod.rs");
 
 // Here we check that the expansion of the file!() macro is mapped.
-// CHECK: @alloc_af9d0c7bc6ca3c31bb051d2862714536 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>
+// CHECK: @alloc_5761061597a97f66e13ef2ff92712c4b = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>
 pub static FILE_PATH: &'static str = file!();
 
 fn main() {
diff --git a/tests/codegen/repr-transparent-aggregates-2.rs b/tests/codegen/repr-transparent-aggregates-2.rs
index df7e88f08c73..e9fa5143b188 100644
--- a/tests/codegen/repr-transparent-aggregates-2.rs
+++ b/tests/codegen/repr-transparent-aggregates-2.rs
@@ -6,7 +6,6 @@
 // ignore-mips64
 // ignore-powerpc
 // ignore-powerpc64
-// ignore-powerpc64le
 // ignore-riscv64 see codegen/riscv-abi
 // ignore-s390x
 // ignore-sparc
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
index 7c77398dfcce..fd488a14bd37 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs
@@ -4,7 +4,8 @@
 #![crate_type = "lib"]
 
 #![allow(non_camel_case_types)]
-#![feature(repr_simd, platform_intrinsics, min_const_generics)]
+#![feature(repr_simd, platform_intrinsics)]
+#![feature(inline_const)]
 
 #[repr(simd)]
 #[derive(Copy, Clone)]
@@ -18,23 +19,65 @@ pub struct T([f32; 4]);
 #[derive(Copy, Clone)]
 pub struct U(f32, f32, f32, f32);
 
+// CHECK-LABEL: @array_align(
+#[no_mangle]
+pub fn array_align() -> usize {
+    // CHECK: ret [[USIZE:i[0-9]+]] [[ARRAY_ALIGN:[0-9]+]]
+    const { std::mem::align_of::() }
+}
+
+// CHECK-LABEL: @vector_align(
+#[no_mangle]
+pub fn vector_align() -> usize {
+    // CHECK: ret [[USIZE]] [[VECTOR_ALIGN:[0-9]+]]
+    const { std::mem::align_of::() }
+}
+
 // CHECK-LABEL: @build_array_s
 #[no_mangle]
 pub fn build_array_s(x: [f32; 4]) -> S<4> {
-    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}}, i{{[0-9]+}} 16, i1 false)
+    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false)
     S::<4>(x)
 }
 
+// CHECK-LABEL: @build_array_transmute_s
+#[no_mangle]
+pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> {
+    // CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]]
+    // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
+    unsafe { std::mem::transmute(x) }
+}
+
 // CHECK-LABEL: @build_array_t
 #[no_mangle]
 pub fn build_array_t(x: [f32; 4]) -> T {
-    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}}, i{{[0-9]+}} 16, i1 false)
+    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}} align [[VECTOR_ALIGN]] {{.*}} align [[ARRAY_ALIGN]] {{.*}}, [[USIZE]] 16, i1 false)
     T(x)
 }
 
+// CHECK-LABEL: @build_array_transmute_t
+#[no_mangle]
+pub fn build_array_transmute_t(x: [f32; 4]) -> T {
+    // CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]]
+    // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
+    unsafe { std::mem::transmute(x) }
+}
+
 // CHECK-LABEL: @build_array_u
 #[no_mangle]
 pub fn build_array_u(x: [f32; 4]) -> U {
-    // CHECK: call void @llvm.memcpy.{{.+}}({{.*}}, i{{[0-9]+}} 16, i1 false)
+    // CHECK: store float %a, {{.+}}, align [[VECTOR_ALIGN]]
+    // CHECK: store float %b, {{.+}}, align [[ARRAY_ALIGN]]
+    // CHECK: store float %c, {{.+}}, align
+    // CHECK: store float %d, {{.+}}, align [[ARRAY_ALIGN]]
+    let [a, b, c, d] = x;
+    U(a, b, c, d)
+}
+
+// CHECK-LABEL: @build_array_transmute_u
+#[no_mangle]
+pub fn build_array_transmute_u(x: [f32; 4]) -> U {
+    // CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]]
+    // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %0|.+>\* %.+}}, align [[VECTOR_ALIGN]]
     unsafe { std::mem::transmute(x) }
 }
diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs
index 4d7a80bfbe5c..af2cef472ec6 100644
--- a/tests/codegen/transmute-scalar.rs
+++ b/tests/codegen/transmute-scalar.rs
@@ -5,63 +5,53 @@
 
 // With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type,
 // without needing to pointercast, and SRoA will turn that into a `bitcast`.
-// As such, there's no longer special-casing in `transmute` to attempt to
-// generate `bitcast` ourselves, as that just made the IR longer.
+// Thus memory-to-memory transmutes don't need to generate them ourselves.
 
-// FIXME: That said, `bitcast`s could still be a valuable addition if they could
-// be done in `rvalue_creates_operand`, and thus avoid the `alloca`s entirely.
+// However, `bitcast`s and `ptrtoint`s and `inttoptr`s are still worth doing when
+// that allows us to avoid the `alloca`s entirely; see `rvalue_creates_operand`.
 
 // CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float noundef %x)
-// CHECK: store float %{{.*}}, ptr %0
-// CHECK-NEXT: %[[RES:.*]] = load i32, ptr %0
-// CHECK: ret i32 %[[RES]]
+// CHECK: %0 = bitcast float %x to i32
+// CHECK-NEXT: ret i32 %0
 #[no_mangle]
 pub fn f32_to_bits(x: f32) -> u32 {
     unsafe { std::mem::transmute(x) }
 }
 
 // CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 noundef zeroext %b)
-// CHECK: %1 = zext i1 %b to i8
-// CHECK-NEXT: store i8 %1, {{.*}} %0
-// CHECK-NEXT: %2 = load i8, {{.*}} %0
-// CHECK: ret i8 %2
+// CHECK: %0 = zext i1 %b to i8
+// CHECK-NEXT: ret i8 %0
 #[no_mangle]
 pub fn bool_to_byte(b: bool) -> u8 {
     unsafe { std::mem::transmute(b) }
 }
 
 // CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 noundef %byte)
-// CHECK: store i8 %byte, ptr %0
-// CHECK-NEXT: %1 = load i8, {{.*}} %0
-// CHECK-NEXT: %2 = trunc i8 %1 to i1
-// CHECK: ret i1 %2
+// CHECK: %0 = trunc i8 %byte to i1
+// CHECK-NEXT: ret i1 %0
 #[no_mangle]
 pub unsafe fn byte_to_bool(byte: u8) -> bool {
     std::mem::transmute(byte)
 }
 
-// CHECK-LABEL: define{{.*}}{{i8\*|ptr}} @ptr_to_ptr({{i16\*|ptr}} noundef %p)
-// CHECK: store {{i8\*|ptr}} %{{.*}}, {{.*}} %0
-// CHECK-NEXT: %[[RES:.*]] = load {{i8\*|ptr}}, {{.*}} %0
-// CHECK: ret {{i8\*|ptr}} %[[RES]]
+// CHECK-LABEL: define{{.*}}ptr @ptr_to_ptr(ptr noundef %p)
+// CHECK: ret ptr %p
 #[no_mangle]
 pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
     unsafe { std::mem::transmute(p) }
 }
 
-// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int({{i16\*|ptr}} noundef %p)
-// CHECK: store {{i16\*|ptr}} %p, {{.*}}
-// CHECK-NEXT: %[[RES:.*]] = load [[USIZE]], {{.*}} %0
-// CHECK: ret [[USIZE]] %[[RES]]
+// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr noundef %p)
+// CHECK: %0 = ptrtoint ptr %p to [[USIZE]]
+// CHECK-NEXT: ret [[USIZE]] %0
 #[no_mangle]
 pub fn ptr_to_int(p: *mut u16) -> usize {
     unsafe { std::mem::transmute(p) }
 }
 
-// CHECK: define{{.*}}{{i16\*|ptr}} @int_to_ptr([[USIZE]] noundef %i)
-// CHECK: store [[USIZE]] %i, {{.*}}
-// CHECK-NEXT: %[[RES:.*]] = load {{i16\*|ptr}}, {{.*}} %0
-// CHECK: ret {{i16\*|ptr}} %[[RES]]
+// CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] noundef %i)
+// CHECK: %0 = inttoptr [[USIZE]] %i to ptr
+// CHECK-NEXT: ret ptr %0
 #[no_mangle]
 pub fn int_to_ptr(i: usize) -> *mut u16 {
     unsafe { std::mem::transmute(i) }
diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs
index 9992604221bc..d68067ceb19f 100644
--- a/tests/codegen/vec-in-place.rs
+++ b/tests/codegen/vec-in-place.rs
@@ -1,11 +1,13 @@
 // ignore-debug: the debug assertions get in the way
 // compile-flags: -O -Z merge-functions=disabled
+// min-llvm-version: 16
 #![crate_type = "lib"]
 
 // Ensure that trivial casts of vec elements are O(1)
 
 pub struct Wrapper(T);
 
+// previously repr(C) caused the optimization to fail
 #[repr(C)]
 pub struct Foo {
     a: u64,
@@ -14,9 +16,8 @@ pub struct Foo {
     d: u64,
 }
 
-// Going from an aggregate struct to another type currently requires Copy to
-// enable the TrustedRandomAccess specialization. Without it optimizations do not yet
-// reliably recognize the loops as noop for repr(C) or non-Copy structs.
+// implementing Copy exercises the TrustedRandomAccess specialization inside the in-place
+// specialization
 #[derive(Copy, Clone)]
 pub struct Bar {
     a: u64,
@@ -25,6 +26,14 @@ pub struct Bar {
     d: u64,
 }
 
+// this exercises the try-fold codepath
+pub struct Baz {
+    a: u64,
+    b: u64,
+    c: u64,
+    d: u64,
+}
+
 // CHECK-LABEL: @vec_iterator_cast_primitive
 #[no_mangle]
 pub fn vec_iterator_cast_primitive(vec: Vec) -> Vec {
@@ -52,18 +61,29 @@ pub fn vec_iterator_cast_unwrap(vec: Vec>) -> Vec {
 // CHECK-LABEL: @vec_iterator_cast_aggregate
 #[no_mangle]
 pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec {
-    // FIXME These checks should be the same as other functions.
-    // CHECK-NOT: @__rust_alloc
-    // CHECK-NOT: @__rust_alloc
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
     vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
 }
 
-// CHECK-LABEL: @vec_iterator_cast_deaggregate
+// CHECK-LABEL: @vec_iterator_cast_deaggregate_tra
 #[no_mangle]
-pub fn vec_iterator_cast_deaggregate(vec: Vec) -> Vec<[u64; 4]> {
-    // FIXME These checks should be the same as other functions.
-    // CHECK-NOT: @__rust_alloc
-    // CHECK-NOT: @__rust_alloc
+pub fn vec_iterator_cast_deaggregate_tra(vec: Vec) -> Vec<[u64; 4]> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+
+    // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4].
+    // This currently is not guaranteed for repr(Rust) types, but it happens to work here and
+    // the UCG may add additional guarantees for homogenous types in the future that would make this
+    // correct.
+    vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_deaggregate_fold
+#[no_mangle]
+pub fn vec_iterator_cast_deaggregate_fold(vec: Vec) -> Vec<[u64; 4]> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
 
     // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4].
     // This currently is not guaranteed for repr(Rust) types, but it happens to work here and
diff --git a/tests/codegen/virtual-function-elimination.rs b/tests/codegen/virtual-function-elimination.rs
index 30e5cd0584d2..f22176a024fc 100644
--- a/tests/codegen/virtual-function-elimination.rs
+++ b/tests/codegen/virtual-function-elimination.rs
@@ -82,7 +82,7 @@ fn taking_u(u: &dyn U) -> i32 {
 }
 
 pub fn taking_v(v: &dyn V) -> i32 {
-    // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"NtCsfRpWlKdQPZn_28virtual_function_elimination1V")
+    // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"NtCs64ITQYi9761_28virtual_function_elimination1V")
     v.public_function()
 }
 
@@ -97,5 +97,5 @@ pub fn main() {
 // CHECK: ![[TYPE0]] = !{i64 0, !"[[MANGLED_TYPE0]]"}
 // CHECK: ![[VCALL_VIS0]] = !{i64 2}
 // CHECK: ![[TYPE1]] = !{i64 0, !"[[MANGLED_TYPE1]]"}
-// CHECK: ![[TYPE2]] = !{i64 0, !"NtCsfRpWlKdQPZn_28virtual_function_elimination1V"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"NtCs64ITQYi9761_28virtual_function_elimination1V"}
 // CHECK: ![[VCALL_VIS2]] = !{i64 1}
diff --git a/tests/debuginfo/function-names.rs b/tests/debuginfo/function-names.rs
index 2227de3b3776..d9aa03fee624 100644
--- a/tests/debuginfo/function-names.rs
+++ b/tests/debuginfo/function-names.rs
@@ -37,7 +37,7 @@
 // Const generic parameter
 // gdb-command:info functions -q function_names::const_generic_fn.*
 // gdb-check:[...]static fn function_names::const_generic_fn_bool();
-// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#6348c650c7b26618}>();
+// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#ad91263f6d2dd96e}>();
 // gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>();
 // gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>();
 
@@ -76,9 +76,9 @@
 // Const generic parameter
 // cdb-command:x a!function_names::const_generic_fn*
 // cdb-check:[...] a!function_names::const_generic_fn_bool (void)
+// cdb-check:[...] a!function_names::const_generic_fn_non_int (void)
 // cdb-check:[...] a!function_names::const_generic_fn_unsigned_int<14> (void)
 // cdb-check:[...] a!function_names::const_generic_fn_signed_int<-7> (void)
-// cdb-check:[...] a!function_names::const_generic_fn_non_int (void)
 
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
index 5f8b2f9312b7..b1d34a1962ec 100644
--- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
@@ -1,36 +1,36 @@
 // MIR for `address_of_reborrow` after SimplifyCfg-initial
 
 | User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address_of.rs:7:5: 7:18, inferred_ty: *const [i32; 10]
-| 1: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address_of.rs:9:5: 9:25, inferred_ty: *const dyn std::marker::Send
-| 2: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address_of.rs:13:12: 13:20, inferred_ty: *const [i32; 10]
-| 3: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address_of.rs:13:12: 13:20, inferred_ty: *const [i32; 10]
-| 4: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) }, span: $DIR/address_of.rs:14:12: 14:28, inferred_ty: *const [i32; 10]
-| 5: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) }, span: $DIR/address_of.rs:14:12: 14:28, inferred_ty: *const [i32; 10]
-| 6: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address_of.rs:15:12: 15:27, inferred_ty: *const dyn std::marker::Send
-| 7: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address_of.rs:15:12: 15:27, inferred_ty: *const dyn std::marker::Send
-| 8: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) }, span: $DIR/address_of.rs:16:12: 16:24, inferred_ty: *const [i32]
-| 9: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) }, span: $DIR/address_of.rs:16:12: 16:24, inferred_ty: *const [i32]
-| 10: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address_of.rs:18:5: 18:18, inferred_ty: *const [i32; 10]
-| 11: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address_of.rs:20:5: 20:25, inferred_ty: *const dyn std::marker::Send
-| 12: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address_of.rs:23:12: 23:20, inferred_ty: *const [i32; 10]
-| 13: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address_of.rs:23:12: 23:20, inferred_ty: *const [i32; 10]
-| 14: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) }, span: $DIR/address_of.rs:24:12: 24:28, inferred_ty: *const [i32; 10]
-| 15: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) }, span: $DIR/address_of.rs:24:12: 24:28, inferred_ty: *const [i32; 10]
-| 16: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address_of.rs:25:12: 25:27, inferred_ty: *const dyn std::marker::Send
-| 17: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address_of.rs:25:12: 25:27, inferred_ty: *const dyn std::marker::Send
-| 18: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) }, span: $DIR/address_of.rs:26:12: 26:24, inferred_ty: *const [i32]
-| 19: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) }, span: $DIR/address_of.rs:26:12: 26:24, inferred_ty: *const [i32]
-| 20: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) }, span: $DIR/address_of.rs:28:5: 28:16, inferred_ty: *mut [i32; 10]
-| 21: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) }, span: $DIR/address_of.rs:30:5: 30:23, inferred_ty: *mut dyn std::marker::Send
-| 22: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) }, span: $DIR/address_of.rs:33:12: 33:18, inferred_ty: *mut [i32; 10]
-| 23: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) }, span: $DIR/address_of.rs:33:12: 33:18, inferred_ty: *mut [i32; 10]
-| 24: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32; 10]) }, span: $DIR/address_of.rs:34:12: 34:26, inferred_ty: *mut [i32; 10]
-| 25: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32; 10]) }, span: $DIR/address_of.rs:34:12: 34:26, inferred_ty: *mut [i32; 10]
-| 26: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) }, span: $DIR/address_of.rs:35:12: 35:25, inferred_ty: *mut dyn std::marker::Send
-| 27: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) }, span: $DIR/address_of.rs:35:12: 35:25, inferred_ty: *mut dyn std::marker::Send
-| 28: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32]) }, span: $DIR/address_of.rs:36:12: 36:22, inferred_ty: *mut [i32]
-| 29: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32]) }, span: $DIR/address_of.rs:36:12: 36:22, inferred_ty: *mut [i32]
+| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:7:5: 7:18, inferred_ty: *const [i32; 10]
+| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:9:5: 9:25, inferred_ty: *const dyn std::marker::Send
+| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:13:12: 13:20, inferred_ty: *const [i32; 10]
+| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:13:12: 13:20, inferred_ty: *const [i32; 10]
+| 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:14:12: 14:28, inferred_ty: *const [i32; 10]
+| 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:14:12: 14:28, inferred_ty: *const [i32; 10]
+| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:15:12: 15:27, inferred_ty: *const dyn std::marker::Send
+| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:15:12: 15:27, inferred_ty: *const dyn std::marker::Send
+| 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:16:12: 16:24, inferred_ty: *const [i32]
+| 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:16:12: 16:24, inferred_ty: *const [i32]
+| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:18:5: 18:18, inferred_ty: *const [i32; 10]
+| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:20:5: 20:25, inferred_ty: *const dyn std::marker::Send
+| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:23:12: 23:20, inferred_ty: *const [i32; 10]
+| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:23:12: 23:20, inferred_ty: *const [i32; 10]
+| 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:24:12: 24:28, inferred_ty: *const [i32; 10]
+| 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:24:12: 24:28, inferred_ty: *const [i32; 10]
+| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:25:12: 25:27, inferred_ty: *const dyn std::marker::Send
+| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:25:12: 25:27, inferred_ty: *const dyn std::marker::Send
+| 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:26:12: 26:24, inferred_ty: *const [i32]
+| 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:26:12: 26:24, inferred_ty: *const [i32]
+| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:28:5: 28:16, inferred_ty: *mut [i32; 10]
+| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:30:5: 30:23, inferred_ty: *mut dyn std::marker::Send
+| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:33:12: 33:18, inferred_ty: *mut [i32; 10]
+| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:33:12: 33:18, inferred_ty: *mut [i32; 10]
+| 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:34:12: 34:26, inferred_ty: *mut [i32; 10]
+| 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:34:12: 34:26, inferred_ty: *mut [i32; 10]
+| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:35:12: 35:25, inferred_ty: *mut dyn std::marker::Send
+| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:35:12: 35:25, inferred_ty: *mut dyn std::marker::Send
+| 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:36:12: 36:22, inferred_ty: *mut [i32]
+| 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:36:12: 36:22, inferred_ty: *mut [i32]
 |
 fn address_of_reborrow() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/address_of.rs:+0:26: +0:26
diff --git a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir
index af5178d4079d..4be382fac8c3 100644
--- a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir
+++ b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir
@@ -38,7 +38,7 @@ fn main() -> () {
         _6 = _3;                         // scope 4 at $DIR/array_index_is_temporary.rs:+4:25: +4:26
         _5 = foo(move _6) -> bb1;        // scope 4 at $DIR/array_index_is_temporary.rs:+4:21: +4:27
                                          // mir::Constant
-                                         // + span: $DIR/array_index_is_temporary.rs:16:21: 16:24
+                                         // + span: $DIR/array_index_is_temporary.rs:17:21: 17:24
                                          // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value() }
     }
 
diff --git a/tests/mir-opt/array_index_is_temporary.rs b/tests/mir-opt/array_index_is_temporary.rs
index e7bde81d4ca3..702b9c70e592 100644
--- a/tests/mir-opt/array_index_is_temporary.rs
+++ b/tests/mir-opt/array_index_is_temporary.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // Retagging (from Stacked Borrows) relies on the array index being a fresh
 // temporary, so that side-effects cannot change it.
 // Test that this is indeed the case.
diff --git a/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir b/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir
index 2487ef5c2150..f6954ab35263 100644
--- a/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir
+++ b/tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir
@@ -9,7 +9,7 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49
         _1 = const ();                   // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49
-        asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind: bb2]; // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49
+        asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind terminate]; // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49
     }
 
     bb1: {
@@ -17,8 +17,4 @@ fn main() -> () {
         _0 = const ();                   // scope 1 at $DIR/asm_unwind_panic_abort.rs:+1:5: +3:6
         return;                          // scope 0 at $DIR/asm_unwind_panic_abort.rs:+4:2: +4:2
     }
-
-    bb2 (cleanup): {
-        abort;                           // scope 0 at $DIR/asm_unwind_panic_abort.rs:+0:1: +4:2
-    }
 }
diff --git a/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff b/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff
index 61a934685cdb..d663c343515b 100644
--- a/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff
+++ b/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff
@@ -47,7 +47,7 @@
   
       bb2 (cleanup): {
           _5 = move _6;                    // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
-          drop(_6) -> bb6;                 // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
+          drop(_6) -> [return: bb6, unwind terminate]; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
       }
   
       bb3: {
@@ -70,16 +70,20 @@
       }
   
       bb6 (cleanup): {
-          drop(_5) -> bb7;                 // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
+          drop(_5) -> [return: bb7, unwind terminate]; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
       }
   
       bb7 (cleanup): {
--         drop(_4) -> bb8;                 // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
+-         drop(_4) -> [return: bb8, unwind terminate]; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
 +         goto -> bb8;                     // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
       }
   
       bb8 (cleanup): {
           resume;                          // scope 0 at $DIR/basic_assignment.rs:+0:1: +14:2
++     }
++ 
++     bb9 (cleanup): {
++         unreachable;                     // scope 0 at $DIR/basic_assignment.rs:+0:1: +14:2
       }
   }
   
diff --git a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir
index f20b534259ad..d63497e3a98d 100644
--- a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after SimplifyCfg-initial
 
 | User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option>) }, span: $DIR/basic_assignment.rs:20:17: 20:33, inferred_ty: std::option::Option>
-| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option>) }, span: $DIR/basic_assignment.rs:20:17: 20:33, inferred_ty: std::option::Option>
+| 0: user_ty: Canonical { value: Ty(std::option::Option>), max_universe: U0, variables: [] }, span: $DIR/basic_assignment.rs:20:17: 20:33, inferred_ty: std::option::Option>
+| 1: user_ty: Canonical { value: Ty(std::option::Option>), max_universe: U0, variables: [] }, span: $DIR/basic_assignment.rs:20:17: 20:33, inferred_ty: std::option::Option>
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/basic_assignment.rs:+0:11: +0:11
@@ -51,7 +51,7 @@ fn main() -> () {
 
     bb2 (cleanup): {
         _5 = move _6;                    // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
-        drop(_6) -> bb6;                 // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
+        drop(_6) -> [return: bb6, unwind terminate]; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
     }
 
     bb3: {
@@ -73,11 +73,11 @@ fn main() -> () {
     }
 
     bb6 (cleanup): {
-        drop(_5) -> bb7;                 // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
+        drop(_5) -> [return: bb7, unwind terminate]; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
     }
 
     bb7 (cleanup): {
-        drop(_4) -> bb8;                 // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
+        drop(_4) -> [return: bb8, unwind terminate]; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
     }
 
     bb8 (cleanup): {
diff --git a/tests/mir-opt/box_expr.main.ElaborateDrops.before.mir b/tests/mir-opt/box_expr.main.ElaborateDrops.before.mir
index 1bbf8f37f292..bac5b21dfad1 100644
--- a/tests/mir-opt/box_expr.main.ElaborateDrops.before.mir
+++ b/tests/mir-opt/box_expr.main.ElaborateDrops.before.mir
@@ -63,15 +63,15 @@ fn main() -> () {
     }
 
     bb6 (cleanup): {
-        drop(_7) -> bb7;                 // scope 1 at $DIR/box_expr.rs:+3:11: +3:12
+        drop(_7) -> [return: bb7, unwind terminate]; // scope 1 at $DIR/box_expr.rs:+3:11: +3:12
     }
 
     bb7 (cleanup): {
-        drop(_1) -> bb9;                 // scope 0 at $DIR/box_expr.rs:+4:1: +4:2
+        drop(_1) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/box_expr.rs:+4:1: +4:2
     }
 
     bb8 (cleanup): {
-        drop(_5) -> bb9;                 // scope 0 at $DIR/box_expr.rs:+2:22: +2:23
+        drop(_5) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/box_expr.rs:+2:22: +2:23
     }
 
     bb9 (cleanup): {
diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
index fd6485de863c..7cce3415fa1b 100644
--- a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
+++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
@@ -98,14 +98,14 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
         StorageLive(_3);                 // scope 0 at $DIR/async_await.rs:+1:5: +1:14
         StorageLive(_4);                 // scope 0 at $DIR/async_await.rs:+1:8: +1:14
         StorageLive(_5);                 // scope 0 at $DIR/async_await.rs:+1:5: +1:8
-        _5 = a() -> bb2;                 // scope 0 at $DIR/async_await.rs:+1:5: +1:8
+        _5 = a() -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/async_await.rs:+1:5: +1:8
                                          // mir::Constant
                                          // + span: $DIR/async_await.rs:15:5: 15:6
                                          // + literal: Const { ty: fn() -> impl Future {a}, val: Value() }
     }
 
     bb2: {
-        _4 =  as IntoFuture>::into_future(move _5) -> bb3; // scope 0 at $DIR/async_await.rs:+1:8: +1:14
+        _4 =  as IntoFuture>::into_future(move _5) -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/async_await.rs:+1:8: +1:14
                                          // mir::Constant
                                          // + span: $DIR/async_await.rs:15:8: 15:14
                                          // + literal: Const { ty: fn(impl Future) ->  as IntoFuture>::IntoFuture { as IntoFuture>::into_future}, val: Value() }
@@ -126,7 +126,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
         StorageLive(_12);                // scope 2 at $DIR/async_await.rs:+1:8: +1:14
         _12 = &mut (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#3).0: impl std::future::Future); // scope 2 at $DIR/async_await.rs:+1:8: +1:14
         _11 = &mut (*_12);               // scope 2 at $DIR/async_await.rs:+1:8: +1:14
-        _10 = Pin::<&mut impl Future>::new_unchecked(move _11) -> bb5; // scope 2 at $DIR/async_await.rs:+1:8: +1:14
+        _10 = Pin::<&mut impl Future>::new_unchecked(move _11) -> [return: bb5, unwind unreachable]; // scope 2 at $DIR/async_await.rs:+1:8: +1:14
                                          // mir::Constant
                                          // + span: $DIR/async_await.rs:15:8: 15:14
                                          // + literal: Const { ty: unsafe fn(&mut impl Future) -> Pin<&mut impl Future> {Pin::<&mut impl Future>::new_unchecked}, val: Value() }
@@ -145,7 +145,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
     bb6: {
         _13 = &mut (*_14);               // scope 2 at $DIR/async_await.rs:+1:5: +1:14
         StorageDead(_15);                // scope 2 at $DIR/async_await.rs:+1:13: +1:14
-        _9 =  as Future>::poll(move _10, move _13) -> bb7; // scope 2 at $DIR/async_await.rs:+1:8: +1:14
+        _9 =  as Future>::poll(move _10, move _13) -> [return: bb7, unwind unreachable]; // scope 2 at $DIR/async_await.rs:+1:8: +1:14
                                          // mir::Constant
                                          // + span: $DIR/async_await.rs:15:8: 15:14
                                          // + literal: Const { ty: for<'a, 'b, 'c> fn(Pin<&'a mut impl Future>, &'b mut Context<'c>) -> Poll< as Future>::Output> { as Future>::poll}, val: Value() }
@@ -206,14 +206,14 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
         StorageDead(_3);                 // scope 0 at $DIR/async_await.rs:+1:14: +1:15
         StorageLive(_21);                // scope 0 at $DIR/async_await.rs:+2:8: +2:14
         StorageLive(_22);                // scope 0 at $DIR/async_await.rs:+2:5: +2:8
-        _22 = a() -> bb14;               // scope 0 at $DIR/async_await.rs:+2:5: +2:8
+        _22 = a() -> [return: bb14, unwind unreachable]; // scope 0 at $DIR/async_await.rs:+2:5: +2:8
                                          // mir::Constant
                                          // + span: $DIR/async_await.rs:16:5: 16:6
                                          // + literal: Const { ty: fn() -> impl Future {a}, val: Value() }
     }
 
     bb14: {
-        _21 =  as IntoFuture>::into_future(move _22) -> bb15; // scope 0 at $DIR/async_await.rs:+2:8: +2:14
+        _21 =  as IntoFuture>::into_future(move _22) -> [return: bb15, unwind unreachable]; // scope 0 at $DIR/async_await.rs:+2:8: +2:14
                                          // mir::Constant
                                          // + span: $DIR/async_await.rs:16:8: 16:14
                                          // + literal: Const { ty: fn(impl Future) ->  as IntoFuture>::IntoFuture { as IntoFuture>::into_future}, val: Value() }
@@ -234,7 +234,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
         StorageLive(_28);                // scope 5 at $DIR/async_await.rs:+2:8: +2:14
         _28 = &mut (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#4).0: impl std::future::Future); // scope 5 at $DIR/async_await.rs:+2:8: +2:14
         _27 = &mut (*_28);               // scope 5 at $DIR/async_await.rs:+2:8: +2:14
-        _26 = Pin::<&mut impl Future>::new_unchecked(move _27) -> bb17; // scope 5 at $DIR/async_await.rs:+2:8: +2:14
+        _26 = Pin::<&mut impl Future>::new_unchecked(move _27) -> [return: bb17, unwind unreachable]; // scope 5 at $DIR/async_await.rs:+2:8: +2:14
                                          // mir::Constant
                                          // + span: $DIR/async_await.rs:16:8: 16:14
                                          // + literal: Const { ty: unsafe fn(&mut impl Future) -> Pin<&mut impl Future> {Pin::<&mut impl Future>::new_unchecked}, val: Value() }
@@ -253,7 +253,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
     bb18: {
         _29 = &mut (*_30);               // scope 5 at $DIR/async_await.rs:+2:5: +2:14
         StorageDead(_31);                // scope 5 at $DIR/async_await.rs:+2:13: +2:14
-        _25 =  as Future>::poll(move _26, move _29) -> bb19; // scope 5 at $DIR/async_await.rs:+2:8: +2:14
+        _25 =  as Future>::poll(move _26, move _29) -> [return: bb19, unwind unreachable]; // scope 5 at $DIR/async_await.rs:+2:8: +2:14
                                          // mir::Constant
                                          // + span: $DIR/async_await.rs:16:8: 16:14
                                          // + literal: Const { ty: for<'a, 'b, 'c> fn(Pin<&'a mut impl Future>, &'b mut Context<'c>) -> Poll< as Future>::Output> { as Future>::poll}, val: Value() }
diff --git a/tests/mir-opt/building/enum_cast.droppy.built.after.mir b/tests/mir-opt/building/enum_cast.droppy.built.after.mir
index 5231c2eab957..1112177fbbf4 100644
--- a/tests/mir-opt/building/enum_cast.droppy.built.after.mir
+++ b/tests/mir-opt/building/enum_cast.droppy.built.after.mir
@@ -63,7 +63,7 @@ fn droppy() -> () {
     }
 
     bb4 (cleanup): {
-        drop(_2) -> bb5;                 // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6
+        drop(_2) -> [return: bb5, unwind terminate]; // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6
     }
 
     bb5 (cleanup): {
diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir
index 628a33f1020a..44c25ce673b8 100644
--- a/tests/mir-opt/building/issue_101867.main.built.after.mir
+++ b/tests/mir-opt/building/issue_101867.main.built.after.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option) }, span: $DIR/issue_101867.rs:3:12: 3:22, inferred_ty: std::option::Option
-| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option) }, span: $DIR/issue_101867.rs:3:12: 3:22, inferred_ty: std::option::Option
+| 0: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:3:12: 3:22, inferred_ty: std::option::Option
+| 1: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:3:12: 3:22, inferred_ty: std::option::Option
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/issue_101867.rs:+0:11: +0:11
diff --git a/tests/mir-opt/building/issue_49232.main.built.after.mir b/tests/mir-opt/building/issue_49232.main.built.after.mir
index de5e4c0f6ed4..cc135f417215 100644
--- a/tests/mir-opt/building/issue_49232.main.built.after.mir
+++ b/tests/mir-opt/building/issue_49232.main.built.after.mir
@@ -17,7 +17,7 @@ fn main() -> () {
     }
 
     bb1: {
-        falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/issue_49232.rs:+1:5: +9:6
+        falseUnwind -> [real: bb2, unwind: bb11]; // scope 0 at $DIR/issue_49232.rs:+1:5: +9:6
     }
 
     bb2: {
diff --git a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir
index 41eb00363bd9..7a6944dee03a 100644
--- a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir
+++ b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir
@@ -1,10 +1,10 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut Test) }, span: $DIR/receiver_ptr_mutability.rs:14:14: 14:23, inferred_ty: *mut Test
-| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut Test) }, span: $DIR/receiver_ptr_mutability.rs:14:14: 14:23, inferred_ty: *mut Test
-| 2: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], value: Ty(&&&&*mut Test) }, span: $DIR/receiver_ptr_mutability.rs:18:18: 18:31, inferred_ty: &&&&*mut Test
-| 3: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], value: Ty(&&&&*mut Test) }, span: $DIR/receiver_ptr_mutability.rs:18:18: 18:31, inferred_ty: &&&&*mut Test
+| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:14:14: 14:23, inferred_ty: *mut Test
+| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:14:14: 14:23, inferred_ty: *mut Test
+| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/receiver_ptr_mutability.rs:18:18: 18:31, inferred_ty: &&&&*mut Test
+| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/receiver_ptr_mutability.rs:18:18: 18:31, inferred_ty: &&&&*mut Test
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/receiver_ptr_mutability.rs:+0:11: +0:11
diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir
index ed72726c5ae0..54f0ea2d8942 100644
--- a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir
+++ b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir
@@ -95,15 +95,15 @@ fn move_out_by_subslice() -> () {
     }
 
     bb9 (cleanup): {
-        drop(_1) -> bb12;                // scope 0 at $DIR/uniform_array_move_out.rs:+8:1: +8:2
+        drop(_1) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/uniform_array_move_out.rs:+8:1: +8:2
     }
 
     bb10 (cleanup): {
-        drop(_7) -> bb11;                // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
+        drop(_7) -> [return: bb11, unwind terminate]; // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
     }
 
     bb11 (cleanup): {
-        drop(_2) -> bb12;                // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
+        drop(_2) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
     }
 
     bb12 (cleanup): {
diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir
index eca874130f69..5090a4ba6751 100644
--- a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir
+++ b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir
@@ -95,15 +95,15 @@ fn move_out_from_end() -> () {
     }
 
     bb9 (cleanup): {
-        drop(_1) -> bb12;                // scope 0 at $DIR/uniform_array_move_out.rs:+8:1: +8:2
+        drop(_1) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/uniform_array_move_out.rs:+8:1: +8:2
     }
 
     bb10 (cleanup): {
-        drop(_7) -> bb11;                // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
+        drop(_7) -> [return: bb11, unwind terminate]; // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
     }
 
     bb11 (cleanup): {
-        drop(_2) -> bb12;                // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
+        drop(_2) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
     }
 
     bb12 (cleanup): {
diff --git a/tests/mir-opt/combine_array_len.rs b/tests/mir-opt/combine_array_len.rs
index 3ef3bd09afde..08c5f1a1fc55 100644
--- a/tests/mir-opt/combine_array_len.rs
+++ b/tests/mir-opt/combine_array_len.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: InstCombine
 // EMIT_MIR combine_array_len.norm2.InstCombine.diff
 
diff --git a/tests/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff b/tests/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
index 20b0fb9643ee..b715a544ffea 100644
--- a/tests/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
+++ b/tests/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
@@ -72,7 +72,7 @@
       }
   
       bb4 (cleanup): {
-          drop(_2) -> bb5;                 // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15
+          drop(_2) -> [return: bb5, unwind terminate]; // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15
       }
   
       bb5 (cleanup): {
diff --git a/tests/mir-opt/combine_transmutes.adt_transmutes.InstCombine.diff b/tests/mir-opt/combine_transmutes.adt_transmutes.InstCombine.diff
index c44a14075ef6..168e8c610316 100644
--- a/tests/mir-opt/combine_transmutes.adt_transmutes.InstCombine.diff
+++ b/tests/mir-opt/combine_transmutes.adt_transmutes.InstCombine.diff
@@ -128,7 +128,7 @@
           StorageDead(_22);                // scope 10 at $DIR/combine_transmutes.rs:+11:47: +11:48
           StorageLive(_23);                // scope 11 at $DIR/combine_transmutes.rs:+12:9: +12:11
           StorageLive(_24);                // scope 11 at $DIR/combine_transmutes.rs:+12:46: +12:77
-          _24 = MaybeUninit::::uninit() -> bb1; // scope 11 at $DIR/combine_transmutes.rs:+12:46: +12:77
+          _24 = MaybeUninit::::uninit() -> [return: bb1, unwind unreachable]; // scope 11 at $DIR/combine_transmutes.rs:+12:46: +12:77
                                            // mir::Constant
                                            // + span: $DIR/combine_transmutes.rs:46:46: 46:75
                                            // + user_ty: UserType(23)
diff --git a/tests/mir-opt/combine_transmutes.identity_transmutes.InstCombine.diff b/tests/mir-opt/combine_transmutes.identity_transmutes.InstCombine.diff
index c83c9f5acf48..ae1185c7f712 100644
--- a/tests/mir-opt/combine_transmutes.identity_transmutes.InstCombine.diff
+++ b/tests/mir-opt/combine_transmutes.identity_transmutes.InstCombine.diff
@@ -19,7 +19,7 @@
 +         _1 = const 1_i32;                // scope 0 at $DIR/combine_transmutes.rs:+2:14: +2:38
           StorageLive(_2);                 // scope 1 at $DIR/combine_transmutes.rs:+3:9: +3:11
           StorageLive(_3);                 // scope 1 at $DIR/combine_transmutes.rs:+3:46: +3:56
-          _3 = Vec::::new() -> bb1;   // scope 1 at $DIR/combine_transmutes.rs:+3:46: +3:56
+          _3 = Vec::::new() -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/combine_transmutes.rs:+3:46: +3:56
                                            // mir::Constant
                                            // + span: $DIR/combine_transmutes.rs:15:46: 15:54
                                            // + user_ty: UserType(0)
@@ -31,7 +31,7 @@
 +         _2 = move _3;                    // scope 1 at $DIR/combine_transmutes.rs:+3:14: +3:57
           StorageDead(_3);                 // scope 1 at $DIR/combine_transmutes.rs:+3:56: +3:57
           _0 = const ();                   // scope 0 at $DIR/combine_transmutes.rs:+0:37: +4:2
-          drop(_2) -> bb2;                 // scope 1 at $DIR/combine_transmutes.rs:+4:1: +4:2
+          drop(_2) -> [return: bb2, unwind unreachable]; // scope 1 at $DIR/combine_transmutes.rs:+4:1: +4:2
       }
   
       bb2: {
diff --git a/tests/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir b/tests/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir
index 41657b53fc12..19daae86589c 100644
--- a/tests/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir
+++ b/tests/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir
@@ -7,10 +7,10 @@ promoted[0] in FOO: &[&i32; 1] = {
     let mut _3: *const i32;              // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43
 
     bb0: {
-        _3 = const {alloc3: *const i32}; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43
+        _3 = const {alloc2: *const i32}; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43
                                          // mir::Constant
                                          // + span: $DIR/const_promotion_extern_static.rs:13:42: 13:43
-                                         // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) }
+                                         // + literal: Const { ty: *const i32, val: Value(Scalar(alloc2)) }
         _2 = &(*_3);                     // scope 0 at $DIR/const_promotion_extern_static.rs:+0:41: +0:43
         _1 = [move _2];                  // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:46
         _0 = &_1;                        // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
@@ -18,4 +18,4 @@ promoted[0] in FOO: &[&i32; 1] = {
     }
 }
 
-alloc3 (extern static: X)
+alloc2 (extern static: X)
diff --git a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
index 25ba0face6bd..5b13d60052fe 100644
--- a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
+++ b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
@@ -18,11 +18,11 @@
 -         StorageLive(_3);                 // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:46
 -         StorageLive(_4);                 // scope 0 at $DIR/const_promotion_extern_static.rs:+0:32: +0:45
 -         StorageLive(_5);                 // scope 1 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43
--         _5 = const {alloc3: *const i32}; // scope 1 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43
+-         _5 = const {alloc2: *const i32}; // scope 1 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43
 +         _6 = const _;                    // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
                                            // mir::Constant
 -                                          // + span: $DIR/const_promotion_extern_static.rs:13:42: 13:43
--                                          // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) }
+-                                          // + literal: Const { ty: *const i32, val: Value(Scalar(alloc2)) }
 -         _4 = &(*_5);                     // scope 1 at $DIR/const_promotion_extern_static.rs:+0:41: +0:43
 -         _3 = [move _4];                  // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:46
 -         _2 = &_3;                        // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
@@ -50,5 +50,5 @@
       }
   }
 - 
-- alloc3 (extern static: X)
+- alloc2 (extern static: X)
   
diff --git a/tests/mir-opt/const_prop/aggregate.main.ConstProp.diff b/tests/mir-opt/const_prop/aggregate.main.ConstProp.diff
index f6e58955b4f6..0411972661eb 100644
--- a/tests/mir-opt/const_prop/aggregate.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/aggregate.main.ConstProp.diff
@@ -29,7 +29,7 @@
 +         _5 = const 1_u8;                 // scope 1 at $DIR/aggregate.rs:+2:9: +2:10
           _4 = foo(move _5) -> bb1;        // scope 1 at $DIR/aggregate.rs:+2:5: +2:11
                                            // mir::Constant
-                                           // + span: $DIR/aggregate.rs:8:5: 8:8
+                                           // + span: $DIR/aggregate.rs:9:5: 9:8
                                            // + literal: Const { ty: fn(u8) {foo}, val: Value() }
       }
   
diff --git a/tests/mir-opt/const_prop/aggregate.main.PreCodegen.after.mir b/tests/mir-opt/const_prop/aggregate.main.PreCodegen.after.mir
index 4706af92cba9..05d4bf8b52e7 100644
--- a/tests/mir-opt/const_prop/aggregate.main.PreCodegen.after.mir
+++ b/tests/mir-opt/const_prop/aggregate.main.PreCodegen.after.mir
@@ -25,7 +25,7 @@ fn main() -> () {
         _5 = const 1_u8;                 // scope 1 at $DIR/aggregate.rs:+2:9: +2:10
         _4 = foo(move _5) -> bb1;        // scope 1 at $DIR/aggregate.rs:+2:5: +2:11
                                          // mir::Constant
-                                         // + span: $DIR/aggregate.rs:8:5: 8:8
+                                         // + span: $DIR/aggregate.rs:9:5: 9:8
                                          // + literal: Const { ty: fn(u8) {foo}, val: Value() }
     }
 
diff --git a/tests/mir-opt/const_prop/aggregate.rs b/tests/mir-opt/const_prop/aggregate.rs
index aa123b7a8664..ed5a4ab594d5 100644
--- a/tests/mir-opt/const_prop/aggregate.rs
+++ b/tests/mir-opt/const_prop/aggregate.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: ConstProp
 // compile-flags: -O
 
diff --git a/tests/mir-opt/const_prop/array_index.rs b/tests/mir-opt/const_prop/array_index.rs
index d31c2827b4e0..f36cf2213486 100644
--- a/tests/mir-opt/const_prop/array_index.rs
+++ b/tests/mir-opt/const_prop/array_index.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: ConstProp
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
diff --git a/tests/mir-opt/const_prop/bad_op_div_by_zero.rs b/tests/mir-opt/const_prop/bad_op_div_by_zero.rs
index a6fd325ece03..38f1a993dc03 100644
--- a/tests/mir-opt/const_prop/bad_op_div_by_zero.rs
+++ b/tests/mir-opt/const_prop/bad_op_div_by_zero.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: ConstProp
 // EMIT_MIR bad_op_div_by_zero.main.ConstProp.diff
 #[allow(unconditional_panic)]
diff --git a/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs b/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs
index cc16a4a5aa74..a1078472cbf8 100644
--- a/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs
+++ b/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // EMIT_MIR bad_op_mod_by_zero.main.ConstProp.diff
 #[allow(unconditional_panic)]
 fn main() {
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 38d402b8f216..e711babf0357 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
@@ -25,7 +25,7 @@
           StorageLive(_2);                 // 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
+                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:6:25: 6:35
                                            // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
           _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
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 38d402b8f216..e711babf0357 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
@@ -25,7 +25,7 @@
           StorageLive(_2);                 // 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
+                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:6:25: 6:35
                                            // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
           _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
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
index cf22b06d5e57..3d252f2d221b 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR bad_op_unsafe_oob_for_slices.main.ConstProp.diff
 #[allow(unconditional_panic)]
diff --git a/tests/mir-opt/const_prop/checked_add.rs b/tests/mir-opt/const_prop/checked_add.rs
index b9860da4c822..007defd10379 100644
--- a/tests/mir-opt/const_prop/checked_add.rs
+++ b/tests/mir-opt/const_prop/checked_add.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: ConstProp
 // compile-flags: -C overflow-checks=on
 
diff --git a/tests/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/tests/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
index bea7114c7df3..d75fae30b538 100644
--- a/tests/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
@@ -18,7 +18,7 @@
           StorageLive(_3);                 // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
           _3 = const _;                    // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
                                            // mir::Constant
-                                           // + span: $DIR/const_prop_fails_gracefully.rs:8:13: 8:16
+                                           // + span: $DIR/const_prop_fails_gracefully.rs:9:13: 9:16
                                            // + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) }
           _2 = &raw const (*_3);           // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
           _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:39
@@ -29,7 +29,7 @@
           _5 = _1;                         // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:10: +3:11
           _4 = read(move _5) -> bb1;       // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:5: +3:12
                                            // mir::Constant
-                                           // + span: $DIR/const_prop_fails_gracefully.rs:9:5: 9:9
+                                           // + span: $DIR/const_prop_fails_gracefully.rs:10:5: 10:9
                                            // + literal: Const { ty: fn(usize) {read}, val: Value() }
       }
   
diff --git a/tests/mir-opt/const_prop/const_prop_fails_gracefully.rs b/tests/mir-opt/const_prop/const_prop_fails_gracefully.rs
index 0a3dcbd380fa..44d4878424dd 100644
--- a/tests/mir-opt/const_prop/const_prop_fails_gracefully.rs
+++ b/tests/mir-opt/const_prop/const_prop_fails_gracefully.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: ConstProp
 #[inline(never)]
 fn read(_: usize) { }
diff --git a/tests/mir-opt/const_prop/control_flow_simplification.rs b/tests/mir-opt/const_prop/control_flow_simplification.rs
index 7dbe8e7344b1..b2ca045e89f9 100644
--- a/tests/mir-opt/const_prop/control_flow_simplification.rs
+++ b/tests/mir-opt/const_prop/control_flow_simplification.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: ConstProp
 // compile-flags: -Zmir-opt-level=1
 
diff --git a/tests/mir-opt/const_prop/indirect.rs b/tests/mir-opt/const_prop/indirect.rs
index 44916cbfe743..46fd8082d308 100644
--- a/tests/mir-opt/const_prop/indirect.rs
+++ b/tests/mir-opt/const_prop/indirect.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: ConstProp
 // compile-flags: -C overflow-checks=on
 
diff --git a/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.diff b/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.diff
index d03c23a3fb56..0ac7fa43d5b4 100644
--- a/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.diff
@@ -8,7 +8,7 @@
       let mut _3: u8;                      // in scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
       scope 1 {
       }
-      scope 2 (inlined ::add) { // at $DIR/inherit_overflow.rs:8:13: 8:47
+      scope 2 (inlined ::add) { // at $DIR/inherit_overflow.rs:9:13: 9:47
           debug self => _2;                // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           debug other => _3;               // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           let mut _4: (u8, bool);          // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
diff --git a/tests/mir-opt/const_prop/inherit_overflow.rs b/tests/mir-opt/const_prop/inherit_overflow.rs
index 541a8c5c3af2..4e905d00d4d9 100644
--- a/tests/mir-opt/const_prop/inherit_overflow.rs
+++ b/tests/mir-opt/const_prop/inherit_overflow.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: ConstProp
 // compile-flags: -Zmir-enable-passes=+Inline
 
diff --git a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff b/tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff
index a4f9003e1401..2652694097c4 100644
--- a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/issue_66971.main.ConstProp.diff
@@ -11,7 +11,7 @@
           _2 = (const (), const 0_u8, const 0_u8); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
           _1 = encode(move _2) -> bb1;     // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
                                            // mir::Constant
-                                           // + span: $DIR/issue_66971.rs:17:5: 17:11
+                                           // + span: $DIR/issue_66971.rs:18:5: 18:11
                                            // + literal: Const { ty: fn(((), u8, u8)) {encode}, val: Value() }
       }
   
diff --git a/tests/mir-opt/const_prop/issue_66971.rs b/tests/mir-opt/const_prop/issue_66971.rs
index 6ca03438ef39..af95c9ca2838 100644
--- a/tests/mir-opt/const_prop/issue_66971.rs
+++ b/tests/mir-opt/const_prop/issue_66971.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: ConstProp
 // compile-flags: -Z mir-opt-level=3
 
diff --git a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff
index f456a3212049..54c9200d6721 100644
--- a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/issue_67019.main.ConstProp.diff
@@ -16,7 +16,7 @@
           StorageDead(_3);                 // scope 0 at $DIR/issue_67019.rs:+1:18: +1:19
           _1 = test(move _2) -> bb1;       // scope 0 at $DIR/issue_67019.rs:+1:5: +1:20
                                            // mir::Constant
-                                           // + span: $DIR/issue_67019.rs:12:5: 12:9
+                                           // + span: $DIR/issue_67019.rs:13:5: 13:9
                                            // + literal: Const { ty: fn(((u8, u8),)) {test}, val: Value() }
       }
   
diff --git a/tests/mir-opt/const_prop/issue_67019.rs b/tests/mir-opt/const_prop/issue_67019.rs
index ffc6fa1f290f..08c7d4805d61 100644
--- a/tests/mir-opt/const_prop/issue_67019.rs
+++ b/tests/mir-opt/const_prop/issue_67019.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: ConstProp
 // compile-flags: -Z mir-opt-level=3
 
diff --git a/tests/mir-opt/const_prop/large_array_index.rs b/tests/mir-opt/const_prop/large_array_index.rs
index 48d134376db6..073f98495689 100644
--- a/tests/mir-opt/const_prop/large_array_index.rs
+++ b/tests/mir-opt/const_prop/large_array_index.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR large_array_index.main.ConstProp.diff
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
index 149aa6290d0e..75f6ebc58c75 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
@@ -16,7 +16,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+1:9: +1:14
           _1 = foo() -> bb1;               // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+1:29: +1:34
                                            // mir::Constant
-                                           // + span: $DIR/mutable_variable_aggregate_partial_read.rs:6:29: 6:32
+                                           // + span: $DIR/mutable_variable_aggregate_partial_read.rs:7:29: 7:32
                                            // + literal: Const { ty: fn() -> (i32, i32) {foo}, val: Value() }
       }
   
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs b/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
index cb59509ff106..70a287cf381e 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test
 // compile-flags: -O
 
diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
index 4010dd6c6d0d..9582504b25e8 100644
--- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
@@ -26,7 +26,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10
           _1 = foo() -> bb1;               // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:13: +1:18
                                            // mir::Constant
-                                           // + span: $DIR/mutable_variable_unprop_assign.rs:6:13: 6:16
+                                           // + span: $DIR/mutable_variable_unprop_assign.rs:7:13: 7:16
                                            // + literal: Const { ty: fn() -> i32 {foo}, val: Value() }
       }
   
diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs
index b077cfd3e0ae..fabd04e9bd27 100644
--- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs
+++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test
 // compile-flags: -O
 
diff --git a/tests/mir-opt/const_prop/optimizes_into_variable.rs b/tests/mir-opt/const_prop/optimizes_into_variable.rs
index abea07e2025b..5ffa153476d9 100644
--- a/tests/mir-opt/const_prop/optimizes_into_variable.rs
+++ b/tests/mir-opt/const_prop/optimizes_into_variable.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test
 // compile-flags: -C overflow-checks=on
 
diff --git a/tests/mir-opt/const_prop/repeat.rs b/tests/mir-opt/const_prop/repeat.rs
index 36d9b9fc62d5..2f3b7d2c5021 100644
--- a/tests/mir-opt/const_prop/repeat.rs
+++ b/tests/mir-opt/const_prop/repeat.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // compile-flags: -O
 
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
diff --git a/tests/mir-opt/const_prop/return_place.rs b/tests/mir-opt/const_prop/return_place.rs
index 06a853696791..ae119df8518e 100644
--- a/tests/mir-opt/const_prop/return_place.rs
+++ b/tests/mir-opt/const_prop/return_place.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // compile-flags: -C overflow-checks=on
 
 // EMIT_MIR return_place.add.ConstProp.diff
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 1151caaabbc1..a091b4ace20c 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
@@ -15,7 +15,7 @@
 -         _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
+                                           // + span: $DIR/scalar_literal_propagation.rs:5:5: 5:12
                                            // + literal: Const { ty: fn(u32) {consume}, val: Value() }
       }
   
diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.rs b/tests/mir-opt/const_prop/scalar_literal_propagation.rs
index 8724e4d57115..e13e352f8a1d 100644
--- a/tests/mir-opt/const_prop/scalar_literal_propagation.rs
+++ b/tests/mir-opt/const_prop/scalar_literal_propagation.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // EMIT_MIR scalar_literal_propagation.main.ConstProp.diff
 fn main() {
     let x = 1;
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 b99b83b0cba8..8bd2b48d6d6a 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:7:6: 7:19
+                                           // + span: $DIR/slice_len.rs:8:6: 8: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
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 b99b83b0cba8..8bd2b48d6d6a 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:7:6: 7:19
+                                           // + span: $DIR/slice_len.rs:8:6: 8: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
diff --git a/tests/mir-opt/const_prop/slice_len.rs b/tests/mir-opt/const_prop/slice_len.rs
index 8183def0c63d..4499c54f264b 100644
--- a/tests/mir-opt/const_prop/slice_len.rs
+++ b/tests/mir-opt/const_prop/slice_len.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: ConstProp
 // compile-flags: -Zmir-enable-passes=+InstCombine
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
diff --git a/tests/mir-opt/const_prop/switch_int.main.ConstProp.diff b/tests/mir-opt/const_prop/switch_int.main.ConstProp.diff
index ddc1a4493dbb..85704c48a2c3 100644
--- a/tests/mir-opt/const_prop/switch_int.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/switch_int.main.ConstProp.diff
@@ -15,14 +15,14 @@
       bb1: {
           _0 = foo(const -1_i32) -> bb3;   // scope 0 at $DIR/switch_int.rs:+3:14: +3:21
                                            // mir::Constant
-                                           // + span: $DIR/switch_int.rs:9:14: 9:17
+                                           // + span: $DIR/switch_int.rs:10:14: 10:17
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value() }
       }
   
       bb2: {
           _0 = foo(const 0_i32) -> bb3;    // scope 0 at $DIR/switch_int.rs:+2:14: +2:20
                                            // mir::Constant
-                                           // + span: $DIR/switch_int.rs:8:14: 8:17
+                                           // + span: $DIR/switch_int.rs:9:14: 9:17
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value() }
       }
   
diff --git a/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff b/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
index 09c47ee6e830..0864db22523f 100644
--- a/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
+++ b/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
@@ -15,14 +15,14 @@
       bb1: {
           _0 = foo(const -1_i32) -> bb3;   // scope 0 at $DIR/switch_int.rs:+3:14: +3:21
                                            // mir::Constant
-                                           // + span: $DIR/switch_int.rs:9:14: 9:17
+                                           // + span: $DIR/switch_int.rs:10:14: 10:17
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value() }
       }
   
       bb2: {
           _0 = foo(const 0_i32) -> bb3;    // scope 0 at $DIR/switch_int.rs:+2:14: +2:20
                                            // mir::Constant
-                                           // + span: $DIR/switch_int.rs:8:14: 8:17
+                                           // + span: $DIR/switch_int.rs:9:14: 9:17
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value() }
       }
   
diff --git a/tests/mir-opt/const_prop/switch_int.rs b/tests/mir-opt/const_prop/switch_int.rs
index d7319eca18e2..2a2322e43a97 100644
--- a/tests/mir-opt/const_prop/switch_int.rs
+++ b/tests/mir-opt/const_prop/switch_int.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 #[inline(never)]
 fn foo(_: i32) { }
 
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
index d370abce45a4..12313b6c58d7 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
@@ -15,7 +15,7 @@
 +         _1 = const (1_u32, 2_u32);       // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
           _2 = consume(_1) -> bb1;         // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
                                            // mir::Constant
-                                           // + span: $DIR/tuple_literal_propagation.rs:5:5: 5:12
+                                           // + span: $DIR/tuple_literal_propagation.rs:6:5: 6:12
                                            // + literal: Const { ty: fn((u32, u32)) {consume}, val: Value() }
       }
   
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.rs b/tests/mir-opt/const_prop/tuple_literal_propagation.rs
index e644baec4a83..edd748d00ab3 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.rs
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // EMIT_MIR tuple_literal_propagation.main.ConstProp.diff
 fn main() {
     let x = (1, 2);
diff --git a/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff b/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff
index b183865a9bcf..2a0bff57db9c 100644
--- a/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.diff
@@ -15,7 +15,7 @@
           _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
+                                           // + span: $DIR/borrowed_local.rs:24:29: 24:36
                                            // + literal: Const { ty: for<'a, 'b> fn(&'a u8, &'b u8) -> bool {cmp_ref}, val: Value() }
       }
   
@@ -23,7 +23,7 @@
 -         _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
+                                           // + span: $DIR/borrowed_local.rs:28:28: 28:34
                                            // + literal: Const { ty: fn(u8) -> bool {opaque::}, val: Value() }
       }
   
diff --git a/tests/mir-opt/copy-prop/borrowed_local.rs b/tests/mir-opt/copy-prop/borrowed_local.rs
index c4b980e2b351..9186da5af484 100644
--- a/tests/mir-opt/copy-prop/borrowed_local.rs
+++ b/tests/mir-opt/copy-prop/borrowed_local.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: CopyProp
 
 #![feature(custom_mir, core_intrinsics)]
diff --git a/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff b/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff
index 8b116532d9f5..b78c19d78d04 100644
--- a/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/branch.foo.CopyProp.diff
@@ -18,7 +18,7 @@
           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
+                                           // + span: $DIR/branch.rs:14:13: 14:16
                                            // + literal: Const { ty: fn() -> i32 {val}, val: Value() }
       }
   
@@ -27,7 +27,7 @@
           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
+                                           // + span: $DIR/branch.rs:16:16: 16:20
                                            // + literal: Const { ty: fn() -> bool {cond}, val: Value() }
       }
   
@@ -44,7 +44,7 @@
           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
+                                           // + span: $DIR/branch.rs:19:9: 19:12
                                            // + literal: Const { ty: fn() -> i32 {val}, val: Value() }
       }
   
diff --git a/tests/mir-opt/copy-prop/branch.rs b/tests/mir-opt/copy-prop/branch.rs
index 50b1e00fad4f..0a2e16946345 100644
--- a/tests/mir-opt/copy-prop/branch.rs
+++ b/tests/mir-opt/copy-prop/branch.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 //! Tests that we bail out when there are multiple assignments to the same local.
 // unit-test: CopyProp
 fn val() -> i32 {
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
index ac4e9a2bfa73..24bca32207fa 100644
--- a/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.diff
@@ -13,7 +13,7 @@
           _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
+                                           // + span: $DIR/copy_propagation_arg.rs:17:5: 17:10
                                            // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value() }
       }
   
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
index 0a3e985e7c26..87708f340054 100644
--- a/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.diff
@@ -13,7 +13,7 @@
           _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
+                                           // + span: $DIR/copy_propagation_arg.rs:12:9: 12:14
                                            // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value() }
       }
   
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.rs b/tests/mir-opt/copy-prop/copy_propagation_arg.rs
index cc98985f1fda..1b65dcb01ed3 100644
--- a/tests/mir-opt/copy-prop/copy_propagation_arg.rs
+++ b/tests/mir-opt/copy-prop/copy_propagation_arg.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // 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
diff --git a/tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.diff b/tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.diff
index 6ca73ffdde28..160f47bdd8f7 100644
--- a/tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.diff
@@ -11,7 +11,7 @@
 -         _0 = opaque::(move _1) -> bb1; // scope 0 at $DIR/custom_move_arg.rs:+3:9: +3:41
 +         _0 = opaque::(_1) -> bb1; // scope 0 at $DIR/custom_move_arg.rs:+3:9: +3:41
                                            // mir::Constant
-                                           // + span: $DIR/custom_move_arg.rs:15:24: 15:30
+                                           // + span: $DIR/custom_move_arg.rs:16:24: 16:30
                                            // + literal: Const { ty: fn(NotCopy) {opaque::}, val: Value() }
       }
   
@@ -20,7 +20,7 @@
 -         _0 = opaque::(_3) -> bb2; // scope 0 at $DIR/custom_move_arg.rs:+7:9: +7:35
 +         _0 = opaque::(_1) -> bb2; // scope 0 at $DIR/custom_move_arg.rs:+7:9: +7:35
                                            // mir::Constant
-                                           // + span: $DIR/custom_move_arg.rs:19:24: 19:30
+                                           // + span: $DIR/custom_move_arg.rs:20:24: 20:30
                                            // + literal: Const { ty: fn(NotCopy) {opaque::}, val: Value() }
       }
   
diff --git a/tests/mir-opt/copy-prop/custom_move_arg.rs b/tests/mir-opt/copy-prop/custom_move_arg.rs
index 4a591146e619..29c368df82d8 100644
--- a/tests/mir-opt/copy-prop/custom_move_arg.rs
+++ b/tests/mir-opt/copy-prop/custom_move_arg.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: CopyProp
 
 #![feature(custom_mir, core_intrinsics)]
diff --git a/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff b/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff
index 3e61869e82f1..23d92ed1ac5b 100644
--- a/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/cycle.main.CopyProp.diff
@@ -24,7 +24,7 @@
           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
+                                           // + span: $DIR/cycle.rs:10:17: 10:20
                                            // + literal: Const { ty: fn() -> i32 {val}, val: Value() }
       }
   
@@ -43,7 +43,7 @@
           _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
+                                           // + span: $DIR/cycle.rs:15:5: 15:9
                                            // + literal: Const { ty: fn(i32) {std::mem::drop::}, val: Value() }
       }
   
diff --git a/tests/mir-opt/copy-prop/cycle.rs b/tests/mir-opt/copy-prop/cycle.rs
index b74c397269de..da70f6bec2eb 100644
--- a/tests/mir-opt/copy-prop/cycle.rs
+++ b/tests/mir-opt/copy-prop/cycle.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 //! Tests that cyclic assignments don't hang CopyProp, and result in reasonable code.
 // unit-test: CopyProp
 fn val() -> i32 {
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
index d48b04e2de27..c56418d8893f 100644
--- 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
@@ -18,7 +18,7 @@ fn f(_1: usize) -> usize {
         _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
+                                         // + span: $DIR/dead_stores_79191.rs:13:5: 13:7
                                          // + literal: Const { ty: fn(usize) -> usize {id::}, val: Value() }
     }
 
diff --git a/tests/mir-opt/copy-prop/dead_stores_79191.rs b/tests/mir-opt/copy-prop/dead_stores_79191.rs
index e3493b8b7a18..84453c55e3ef 100644
--- a/tests/mir-opt/copy-prop/dead_stores_79191.rs
+++ b/tests/mir-opt/copy-prop/dead_stores_79191.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: CopyProp
 
 fn id(x: T) -> T {
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
index 727791f50a4e..f355421732e4 100644
--- 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
@@ -18,7 +18,7 @@ fn f(_1: usize) -> usize {
         _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
+                                         // + span: $DIR/dead_stores_better.rs:17:5: 17:7
                                          // + literal: Const { ty: fn(usize) -> usize {id::}, val: Value() }
     }
 
diff --git a/tests/mir-opt/copy-prop/dead_stores_better.rs b/tests/mir-opt/copy-prop/dead_stores_better.rs
index 8465b3c98536..87b916fd3ff8 100644
--- a/tests/mir-opt/copy-prop/dead_stores_better.rs
+++ b/tests/mir-opt/copy-prop/dead_stores_better.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // 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.
 
diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.diff
index 97d0a01e00bc..e09ccb831199 100644
--- a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.diff
@@ -51,7 +51,7 @@
           StorageDead(_7);                 // scope 2 at $DIR/issue_107511.rs:+6:17: +6:18
           _5 = core::slice::::len(move _6) -> bb1; // scope 2 at $DIR/issue_107511.rs:+6:17: +6:24
                                            // mir::Constant
-                                           // + span: $DIR/issue_107511.rs:10:19: 10:22
+                                           // + span: $DIR/issue_107511.rs:11:19: 11:22
                                            // + literal: Const { ty: for<'a> fn(&'a [i32]) -> usize {core::slice::::len}, val: Value() }
       }
   
@@ -61,7 +61,7 @@
           StorageDead(_5);                 // scope 2 at $DIR/issue_107511.rs:+6:23: +6:24
           _3 =  as IntoIterator>::into_iter(move _4) -> bb2; // scope 2 at $DIR/issue_107511.rs:+6:14: +6:24
                                            // mir::Constant
-                                           // + span: $DIR/issue_107511.rs:10:14: 10:24
+                                           // + span: $DIR/issue_107511.rs:11:14: 11:24
                                            // + literal: Const { ty: fn(std::ops::Range) ->  as IntoIterator>::IntoIter { as IntoIterator>::into_iter}, val: Value() }
       }
   
@@ -81,7 +81,7 @@
           _12 = &mut (*_13);               // scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
           _11 =  as Iterator>::next(move _12) -> bb4; // scope 3 at $DIR/issue_107511.rs:+6:14: +6:24
                                            // mir::Constant
-                                           // + span: $DIR/issue_107511.rs:10:14: 10:24
+                                           // + span: $DIR/issue_107511.rs:11:14: 11:24
                                            // + literal: Const { ty: for<'a> fn(&'a mut std::ops::Range) -> Option< as Iterator>::Item> { as Iterator>::next}, val: Value() }
       }
   
diff --git a/tests/mir-opt/copy-prop/issue_107511.rs b/tests/mir-opt/copy-prop/issue_107511.rs
index d593f2872ea4..2b00ff15581f 100644
--- a/tests/mir-opt/copy-prop/issue_107511.rs
+++ b/tests/mir-opt/copy-prop/issue_107511.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: CopyProp
 
 // EMIT_MIR issue_107511.main.CopyProp.diff
diff --git a/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff b/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff
index d76bf1cfe7e0..650bd66a7d73 100644
--- a/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/move_arg.f.CopyProp.diff
@@ -24,7 +24,7 @@
 -         _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
+                                           // + span: $DIR/move_arg.rs:8:5: 8:6
                                            // + literal: Const { ty: fn(T, T) {g::}, val: Value() }
       }
   
diff --git a/tests/mir-opt/copy-prop/move_arg.rs b/tests/mir-opt/copy-prop/move_arg.rs
index 40ae1d8f4661..f88d9a9e74bb 100644
--- a/tests/mir-opt/copy-prop/move_arg.rs
+++ b/tests/mir-opt/copy-prop/move_arg.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // Test that we do not move multiple times from the same local.
 // unit-test: CopyProp
 
diff --git a/tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff b/tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff
index 02308beb88af..beb85d68a660 100644
--- a/tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff
@@ -13,14 +13,14 @@
 +         _3 = (_1.0: u8);                 // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
 +         _0 = opaque::(_1) -> bb1;   // scope 0 at $DIR/move_projection.rs:+6:13: +6:44
                                            // mir::Constant
-                                           // + span: $DIR/move_projection.rs:19:28: 19:34
+                                           // + span: $DIR/move_projection.rs:20:28: 20:34
                                            // + literal: Const { ty: fn(Foo) -> bool {opaque::}, val: Value() }
       }
   
       bb1: {
           _0 = opaque::(move _3) -> bb2; // scope 0 at $DIR/move_projection.rs:+9:13: +9:44
                                            // mir::Constant
-                                           // + span: $DIR/move_projection.rs:22:28: 22:34
+                                           // + span: $DIR/move_projection.rs:23:28: 23:34
                                            // + literal: Const { ty: fn(u8) -> bool {opaque::}, val: Value() }
       }
   
diff --git a/tests/mir-opt/copy-prop/move_projection.rs b/tests/mir-opt/copy-prop/move_projection.rs
index 2a1bbae99a4c..c158c69e0cf8 100644
--- a/tests/mir-opt/copy-prop/move_projection.rs
+++ b/tests/mir-opt/copy-prop/move_projection.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: CopyProp
 
 #![feature(custom_mir, core_intrinsics)]
diff --git a/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.diff b/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.diff
index 6c32b675a5bc..b4a248245663 100644
--- a/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.diff
@@ -39,7 +39,7 @@
 -         _6 = opaque::<*mut u8>(move _7) -> bb1; // scope 4 at $DIR/reborrow.rs:+4:5: +4:14
 +         _6 = opaque::<*mut u8>(_2) -> bb1; // scope 4 at $DIR/reborrow.rs:+4:5: +4:14
                                            // mir::Constant
-                                           // + span: $DIR/reborrow.rs:38:5: 38:11
+                                           // + span: $DIR/reborrow.rs:39:5: 39:11
                                            // + literal: Const { ty: fn(*mut u8) {opaque::<*mut u8>}, val: Value() }
       }
   
diff --git a/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.diff b/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.diff
index 2f1b522c2ec7..a6a6c05b24ae 100644
--- a/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.diff
@@ -35,7 +35,7 @@
 -         _5 = opaque::<*mut u8>(move _6) -> bb1; // scope 4 at $DIR/reborrow.rs:+4:5: +4:14
 +         _5 = opaque::<*mut u8>(_2) -> bb1; // scope 4 at $DIR/reborrow.rs:+4:5: +4:14
                                            // mir::Constant
-                                           // + span: $DIR/reborrow.rs:30:5: 30:11
+                                           // + span: $DIR/reborrow.rs:31:5: 31:11
                                            // + literal: Const { ty: fn(*mut u8) {opaque::<*mut u8>}, val: Value() }
       }
   
diff --git a/tests/mir-opt/copy-prop/reborrow.remut.CopyProp.diff b/tests/mir-opt/copy-prop/reborrow.remut.CopyProp.diff
index 9b580c1f4e15..f3d26cc6e2bf 100644
--- a/tests/mir-opt/copy-prop/reborrow.remut.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/reborrow.remut.CopyProp.diff
@@ -33,7 +33,7 @@
 -         _5 = opaque::<&mut u8>(move _6) -> bb1; // scope 3 at $DIR/reborrow.rs:+4:5: +4:14
 +         _5 = opaque::<&mut u8>(move _2) -> bb1; // scope 3 at $DIR/reborrow.rs:+4:5: +4:14
                                            // mir::Constant
-                                           // + span: $DIR/reborrow.rs:14:5: 14:11
+                                           // + span: $DIR/reborrow.rs:15:5: 15:11
                                            // + literal: Const { ty: fn(&mut u8) {opaque::<&mut u8>}, val: Value() }
       }
   
diff --git a/tests/mir-opt/copy-prop/reborrow.reraw.CopyProp.diff b/tests/mir-opt/copy-prop/reborrow.reraw.CopyProp.diff
index cff4a176098b..63e42b4dc771 100644
--- a/tests/mir-opt/copy-prop/reborrow.reraw.CopyProp.diff
+++ b/tests/mir-opt/copy-prop/reborrow.reraw.CopyProp.diff
@@ -33,7 +33,7 @@
 -         _5 = opaque::<&mut u8>(move _6) -> bb1; // scope 3 at $DIR/reborrow.rs:+4:5: +4:14
 +         _5 = opaque::<&mut u8>(move _2) -> bb1; // scope 3 at $DIR/reborrow.rs:+4:5: +4:14
                                            // mir::Constant
-                                           // + span: $DIR/reborrow.rs:22:5: 22:11
+                                           // + span: $DIR/reborrow.rs:23:5: 23:11
                                            // + literal: Const { ty: fn(&mut u8) {opaque::<&mut u8>}, val: Value() }
       }
   
diff --git a/tests/mir-opt/copy-prop/reborrow.rs b/tests/mir-opt/copy-prop/reborrow.rs
index c2926b8fa518..91b77966ba84 100644
--- a/tests/mir-opt/copy-prop/reborrow.rs
+++ b/tests/mir-opt/copy-prop/reborrow.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // Check that CopyProp considers reborrows as not mutating the pointer.
 // unit-test: CopyProp
 
diff --git a/tests/mir-opt/dataflow-const-prop/checked.rs b/tests/mir-opt/dataflow-const-prop/checked.rs
index 0738a4ee53b8..0f9f5a97faca 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.rs
+++ b/tests/mir-opt/dataflow-const-prop/checked.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: DataflowConstProp
 // compile-flags: -Coverflow-checks=on
 
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 29781e9ce188..1edcc28e68c1 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
@@ -8,7 +8,7 @@
       let mut _3: u8;                      // in scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
       scope 1 {
       }
-      scope 2 (inlined ::add) { // at $DIR/inherit_overflow.rs:8:13: 8:47
+      scope 2 (inlined ::add) { // at $DIR/inherit_overflow.rs:9:13: 9:47
           debug self => _2;                // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           debug other => _3;               // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
           let mut _4: (u8, bool);          // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.rs b/tests/mir-opt/dataflow-const-prop/inherit_overflow.rs
index f4aba60f0c80..90349d5270cc 100644
--- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.rs
+++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: DataflowConstProp
 // compile-flags: -Zmir-enable-passes=+Inline
 
diff --git a/tests/mir-opt/dataflow-const-prop/ref_without_sb.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/ref_without_sb.main.DataflowConstProp.diff
index 158f187f1576..70ef17afd659 100644
--- a/tests/mir-opt/dataflow-const-prop/ref_without_sb.main.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/ref_without_sb.main.DataflowConstProp.diff
@@ -26,7 +26,7 @@
           _3 = &(*_4);                     // scope 1 at $DIR/ref_without_sb.rs:+2:12: +2:14
           _2 = escape::(move _3) -> bb1; // scope 1 at $DIR/ref_without_sb.rs:+2:5: +2:15
                                            // mir::Constant
-                                           // + span: $DIR/ref_without_sb.rs:12:5: 12:11
+                                           // + span: $DIR/ref_without_sb.rs:13:5: 13:11
                                            // + literal: Const { ty: for<'a> fn(&'a i32) {escape::}, val: Value() }
       }
   
@@ -38,7 +38,7 @@
           StorageLive(_5);                 // scope 1 at $DIR/ref_without_sb.rs:+4:5: +4:20
           _5 = some_function() -> bb2;     // scope 1 at $DIR/ref_without_sb.rs:+4:5: +4:20
                                            // mir::Constant
-                                           // + span: $DIR/ref_without_sb.rs:14:5: 14:18
+                                           // + span: $DIR/ref_without_sb.rs:15:5: 15:18
                                            // + literal: Const { ty: fn() {some_function}, val: Value() }
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/ref_without_sb.rs b/tests/mir-opt/dataflow-const-prop/ref_without_sb.rs
index 2fd480b0968a..f53de3cf2d4c 100644
--- a/tests/mir-opt/dataflow-const-prop/ref_without_sb.rs
+++ b/tests/mir-opt/dataflow-const-prop/ref_without_sb.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: DataflowConstProp
 
 #[inline(never)]
diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff
index 004643e36f13..6ca569f3d8e5 100644
--- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff
@@ -32,7 +32,7 @@
           _5 = _3;                         // scope 3 at $DIR/sibling_ptr.rs:+4:10: +4:11
           _4 = ptr::mut_ptr::::add(move _5, const 1_usize) -> bb1; // scope 3 at $DIR/sibling_ptr.rs:+4:10: +4:18
                                            // mir::Constant
-                                           // + span: $DIR/sibling_ptr.rs:15:12: 15:15
+                                           // + span: $DIR/sibling_ptr.rs:16:12: 16:15
                                            // + literal: Const { ty: unsafe fn(*mut u8, usize) -> *mut u8 {ptr::mut_ptr::::add}, val: Value() }
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs b/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs
index 6dfb3a4ed309..81fc3c2f49c7 100644
--- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs
+++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // This attempts to modify `x.1` via a pointer derived from `addr_of_mut!(x.0)`.
 // According to Miri, that is UB. However, T-opsem has not finalized that
 // decision and as such we cannot rely on it in optimizations. Consequently,
diff --git a/tests/mir-opt/dataflow-const-prop/terminator.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/terminator.main.DataflowConstProp.diff
index 8018400e798a..9854beaeb217 100644
--- a/tests/mir-opt/dataflow-const-prop/terminator.main.DataflowConstProp.diff
+++ b/tests/mir-opt/dataflow-const-prop/terminator.main.DataflowConstProp.diff
@@ -25,7 +25,7 @@
 -         _2 = foo(move _3) -> bb1;        // scope 1 at $DIR/terminator.rs:+3:5: +3:15
 +         _2 = foo(const 2_i32) -> bb1;    // scope 1 at $DIR/terminator.rs:+3:5: +3:15
                                            // mir::Constant
-                                           // + span: $DIR/terminator.rs:9:5: 9:8
+                                           // + span: $DIR/terminator.rs:10:5: 10:8
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value() }
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/terminator.rs b/tests/mir-opt/dataflow-const-prop/terminator.rs
index d151f666a2dc..4f001df35f14 100644
--- a/tests/mir-opt/dataflow-const-prop/terminator.rs
+++ b/tests/mir-opt/dataflow-const-prop/terminator.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: DataflowConstProp
 
 fn foo(n: i32) {}
diff --git a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff
index cd3b792fb751..2776ff51d85a 100644
--- a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff
+++ b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff
@@ -32,7 +32,7 @@
 +         StorageLive(_4);                 // scope 0 at $DIR/cycle.rs:+3:11: +3:17
 +         _4 = cond() -> bb2;              // scope 0 at $DIR/cycle.rs:+3:11: +3:17
                                            // mir::Constant
-                                           // + span: $DIR/cycle.rs:12:11: 12:15
+                                           // + span: $DIR/cycle.rs:13:11: 13:15
                                            // + literal: Const { ty: fn() -> bool {cond}, val: Value() }
       }
   
diff --git a/tests/mir-opt/dead-store-elimination/cycle.rs b/tests/mir-opt/dead-store-elimination/cycle.rs
index b35ce0bcb5ad..570bfe84d106 100644
--- a/tests/mir-opt/dead-store-elimination/cycle.rs
+++ b/tests/mir-opt/dead-store-elimination/cycle.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: DeadStoreElimination
 
 #[inline(never)]
diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
index 3b1f81175cbf..c4ebf1ca834f 100644
--- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
+++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
@@ -19,7 +19,7 @@
           _3 = &(*_1);                     // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
           _2 = core::str::::as_bytes(move _3) -> bb1; // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
                                            // mir::Constant
-                                           // + span: $DIR/deduplicate_blocks.rs:5:13: 5:21
+                                           // + span: $DIR/deduplicate_blocks.rs:6:13: 6:21
                                            // + literal: Const { ty: for<'a> fn(&'a str) -> &'a [u8] {core::str::::as_bytes}, val: Value() }
       }
   
diff --git a/tests/mir-opt/deduplicate_blocks.rs b/tests/mir-opt/deduplicate_blocks.rs
index 2b9eed99ecdb..46012e19aa4b 100644
--- a/tests/mir-opt/deduplicate_blocks.rs
+++ b/tests/mir-opt/deduplicate_blocks.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: DeduplicateBlocks
 
 // EMIT_MIR deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
diff --git a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir b/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir
index 9597a0c835fd..97826ed19a25 100644
--- a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir
+++ b/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir
@@ -25,19 +25,19 @@ fn foo(_1: Option) -> i32 {
         _7 = const false;                // scope 0 at $DIR/string.rs:+3:9: +3:10
         _6 = move _1;                    // scope 0 at $DIR/string.rs:+3:9: +3:10
         _0 = const 4321_i32;             // scope 1 at $DIR/string.rs:+3:14: +3:18
-        drop(_6) -> bb6;                 // scope 0 at $DIR/string.rs:+3:17: +3:18
+        drop(_6) -> [return: bb6, unwind unreachable]; // scope 0 at $DIR/string.rs:+3:17: +3:18
     }
 
     bb2: {
         _2 = &((_1 as Some).0: std::string::String); // scope 0 at $DIR/string.rs:+2:14: +2:17
-        _3 = ::deref(move _2) -> bb3; // scope 0 at $DIR/string.rs:+2:14: +2:17
+        _3 = ::deref(move _2) -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17
                                          // mir::Constant
                                          // + span: $DIR/string.rs:9:14: 9:17
                                          // + literal: Const { ty: for<'a> fn(&'a String) -> &'a ::Target {::deref}, val: Value() }
     }
 
     bb3: {
-        _4 = ::eq(_3, const "a") -> bb4; // scope 0 at $DIR/string.rs:+2:14: +2:17
+        _4 = ::eq(_3, const "a") -> [return: bb4, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17
                                          // mir::Constant
                                          // + span: $DIR/string.rs:9:14: 9:17
                                          // + literal: Const { ty: for<'a, 'b> fn(&'a str, &'b str) -> bool {::eq}, val: Value() }
@@ -65,7 +65,7 @@ fn foo(_1: Option) -> i32 {
     }
 
     bb8: {
-        drop(_1) -> bb7;                 // scope 0 at $DIR/string.rs:+5:1: +5:2
+        drop(_1) -> [return: bb7, unwind unreachable]; // scope 0 at $DIR/string.rs:+5:1: +5:2
     }
 
     bb9: {
diff --git a/tests/mir-opt/derefer_inline_test.main.Derefer.diff b/tests/mir-opt/derefer_inline_test.main.Derefer.diff
index ec9cbb25322c..426d4fb213cd 100644
--- a/tests/mir-opt/derefer_inline_test.main.Derefer.diff
+++ b/tests/mir-opt/derefer_inline_test.main.Derefer.diff
@@ -35,7 +35,7 @@
       }
   
       bb4 (cleanup): {
-          drop(_2) -> bb5;                 // scope 0 at $DIR/derefer_inline_test.rs:+1:17: +1:18
+          drop(_2) -> [return: bb5, unwind terminate]; // scope 0 at $DIR/derefer_inline_test.rs:+1:17: +1:18
       }
   
       bb5 (cleanup): {
diff --git a/tests/mir-opt/dest-prop/branch.foo.DestinationPropagation.diff b/tests/mir-opt/dest-prop/branch.foo.DestinationPropagation.diff
index 9c729663265e..b7416d389ef7 100644
--- a/tests/mir-opt/dest-prop/branch.foo.DestinationPropagation.diff
+++ b/tests/mir-opt/dest-prop/branch.foo.DestinationPropagation.diff
@@ -22,7 +22,7 @@
 +         nop;                             // scope 0 at $DIR/branch.rs:+1:9: +1:10
 +         _0 = val() -> bb1;               // scope 0 at $DIR/branch.rs:+1:13: +1:18
                                            // mir::Constant
-                                           // + span: $DIR/branch.rs:13:13: 13:16
+                                           // + span: $DIR/branch.rs:14:13: 14:16
                                            // + literal: Const { ty: fn() -> i32 {val}, val: Value() }
       }
   
@@ -32,7 +32,7 @@
           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
+                                           // + span: $DIR/branch.rs:16:16: 16:20
                                            // + literal: Const { ty: fn() -> bool {cond}, val: Value() }
       }
   
@@ -50,7 +50,7 @@
           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
+                                           // + span: $DIR/branch.rs:19:9: 19:12
                                            // + literal: Const { ty: fn() -> i32 {val}, val: Value() }
       }
   
diff --git a/tests/mir-opt/dest-prop/branch.rs b/tests/mir-opt/dest-prop/branch.rs
index 898c908b18c7..7e4276e66922 100644
--- a/tests/mir-opt/dest-prop/branch.rs
+++ b/tests/mir-opt/dest-prop/branch.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 //! Tests that assignment in both branches of an `if` are eliminated.
 // unit-test: DestinationPropagation
 fn val() -> i32 {
diff --git a/tests/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff b/tests/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff
index 298991b5ad1c..a61e741f73dc 100644
--- a/tests/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff
+++ b/tests/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff
@@ -16,7 +16,7 @@
 +         nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:+1:11: +1:12
 +         _2 = dummy(move _1) -> 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
+                                           // + span: $DIR/copy_propagation_arg.rs:17:5: 17:10
                                            // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value() }
       }
   
diff --git a/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff b/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff
index d37a9f71d3eb..c7fbecac5c47 100644
--- a/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff
+++ b/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff
@@ -15,7 +15,7 @@
 -         _2 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:+2:9: +2:17
 +         _1 = 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
+                                           // + span: $DIR/copy_propagation_arg.rs:12:9: 12:14
                                            // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value() }
       }
   
diff --git a/tests/mir-opt/dest-prop/copy_propagation_arg.rs b/tests/mir-opt/dest-prop/copy_propagation_arg.rs
index 31be6c931393..57cb328c231b 100644
--- a/tests/mir-opt/dest-prop/copy_propagation_arg.rs
+++ b/tests/mir-opt/dest-prop/copy_propagation_arg.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // Check that DestinationPropagation does not propagate an assignment to a function argument
 // (doing so can break usages of the original argument value)
 // unit-test: DestinationPropagation
diff --git a/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff b/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff
index cfc203c5f89a..b06f069a2e4f 100644
--- a/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff
+++ b/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff
@@ -28,7 +28,7 @@
 +         nop;                             // scope 0 at $DIR/cycle.rs:+1:9: +1:14
 +         _6 = val() -> bb1;               // scope 0 at $DIR/cycle.rs:+1:17: +1:22
                                            // mir::Constant
-                                           // + span: $DIR/cycle.rs:9:17: 9:20
+                                           // + span: $DIR/cycle.rs:10:17: 10:20
                                            // + literal: Const { ty: fn() -> i32 {val}, val: Value() }
       }
   
@@ -56,7 +56,7 @@
 +         nop;                             // 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
+                                           // + span: $DIR/cycle.rs:15:5: 15:9
                                            // + literal: Const { ty: fn(i32) {std::mem::drop::}, val: Value() }
       }
   
diff --git a/tests/mir-opt/dest-prop/cycle.rs b/tests/mir-opt/dest-prop/cycle.rs
index 6182878f3413..3aea19d80dc7 100644
--- a/tests/mir-opt/dest-prop/cycle.rs
+++ b/tests/mir-opt/dest-prop/cycle.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 //! Tests that cyclic assignments don't hang DestinationPropagation, and result in reasonable code.
 // unit-test: DestinationPropagation
 fn val() -> i32 {
diff --git a/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.mir b/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.mir
index 63cac133b73b..b9d4b59d2f7a 100644
--- a/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.mir
+++ b/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.mir
@@ -22,7 +22,7 @@ fn f(_1: usize) -> usize {
         nop;                             // scope 1 at $DIR/dead_stores_79191.rs:+4:8: +4:9
         _0 = id::(move _1) -> 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
+                                         // + span: $DIR/dead_stores_79191.rs:13:5: 13:7
                                          // + literal: Const { ty: fn(usize) -> usize {id::}, val: Value() }
     }
 
diff --git a/tests/mir-opt/dest-prop/dead_stores_79191.rs b/tests/mir-opt/dest-prop/dead_stores_79191.rs
index 43e0bf66418a..9d4814838d4e 100644
--- a/tests/mir-opt/dest-prop/dead_stores_79191.rs
+++ b/tests/mir-opt/dest-prop/dead_stores_79191.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: DestinationPropagation
 
 fn id(x: T) -> T {
diff --git a/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.mir b/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.mir
index 26068931aaf2..9eb0e09bf1b2 100644
--- a/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.mir
+++ b/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.mir
@@ -21,7 +21,7 @@ fn f(_1: usize) -> usize {
         nop;                             // scope 1 at $DIR/dead_stores_better.rs:+4:8: +4:9
         _0 = id::(move _1) -> 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
+                                         // + span: $DIR/dead_stores_better.rs:17:5: 17:7
                                          // + literal: Const { ty: fn(usize) -> usize {id::}, val: Value() }
     }
 
diff --git a/tests/mir-opt/dest-prop/dead_stores_better.rs b/tests/mir-opt/dest-prop/dead_stores_better.rs
index 003ad57d83ea..72d406bfd40a 100644
--- a/tests/mir-opt/dest-prop/dead_stores_better.rs
+++ b/tests/mir-opt/dest-prop/dead_stores_better.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // 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.
 
diff --git a/tests/mir-opt/dest-prop/simple.rs b/tests/mir-opt/dest-prop/simple.rs
index d4c27228fe42..3a4aec34e8cc 100644
--- a/tests/mir-opt/dest-prop/simple.rs
+++ b/tests/mir-opt/dest-prop/simple.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 //! Copy of `nrvo-simple.rs`, to ensure that full dest-prop handles it too.
 // unit-test: DestinationPropagation
 // EMIT_MIR simple.nrvo.DestinationPropagation.diff
diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.diff
index fbed3178801f..457fc830874d 100644
--- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.diff
+++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.diff
@@ -10,7 +10,7 @@
           debug un => _1;                  // in scope 1 at $DIR/union.rs:+5:9: +5:11
           scope 2 {
           }
-          scope 3 (inlined std::mem::drop::) { // at $DIR/union.rs:15:5: 15:27
+          scope 3 (inlined std::mem::drop::) { // at $DIR/union.rs:16:5: 16:27
               debug _x => _3;              // in scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL
           }
       }
@@ -20,7 +20,7 @@
           StorageLive(_2);                 // scope 0 at $DIR/union.rs:+5:23: +5:28
           _2 = val() -> bb1;               // scope 0 at $DIR/union.rs:+5:23: +5:28
                                            // mir::Constant
-                                           // + span: $DIR/union.rs:13:23: 13:26
+                                           // + span: $DIR/union.rs:14:23: 14:26
                                            // + literal: Const { ty: fn() -> u32 {val}, val: Value() }
       }
   
diff --git a/tests/mir-opt/dest-prop/union.rs b/tests/mir-opt/dest-prop/union.rs
index eb6cb09fc455..062d02d06731 100644
--- a/tests/mir-opt/dest-prop/union.rs
+++ b/tests/mir-opt/dest-prop/union.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 //! Tests that we can propagate into places that are projections into unions
 // compile-flags: -Zunsound-mir-opts
 fn val() -> u32 {
diff --git a/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.diff b/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.diff
index 9ea756c27129..ae63d724d0a5 100644
--- a/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.diff
+++ b/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.diff
@@ -36,7 +36,7 @@
 -         _6 = _2;                         // scope 1 at $DIR/unreachable.rs:+3:14: +3:15
 -         _4 = g::(move _5, move _6) -> bb2; // scope 1 at $DIR/unreachable.rs:+3:9: +3:16
 -                                          // mir::Constant
--                                          // + span: $DIR/unreachable.rs:11:9: 11:10
+-                                          // + span: $DIR/unreachable.rs:12:9: 12:10
 -                                          // + literal: Const { ty: fn(T, T) {g::}, val: Value() }
 -     }
 - 
@@ -60,7 +60,7 @@
 +         _9 = _1;                         // scope 1 at $DIR/unreachable.rs:+5:14: +5:15
 +         _7 = g::(move _1, move _9) -> bb2; // scope 1 at $DIR/unreachable.rs:+5:9: +5:16
                                            // mir::Constant
-                                           // + span: $DIR/unreachable.rs:13:9: 13:10
+                                           // + span: $DIR/unreachable.rs:14:9: 14:10
                                            // + literal: Const { ty: fn(T, T) {g::}, val: Value() }
       }
   
diff --git a/tests/mir-opt/dest-prop/unreachable.rs b/tests/mir-opt/dest-prop/unreachable.rs
index 32b5def984a8..c73d11ae3baf 100644
--- a/tests/mir-opt/dest-prop/unreachable.rs
+++ b/tests/mir-opt/dest-prop/unreachable.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // Check that unreachable code is removed after the destination propagation.
 // Regression test for issue #105428.
 //
diff --git a/tests/mir-opt/div_overflow.rs b/tests/mir-opt/div_overflow.rs
index 10ce5bc0f4f0..fe34a865b93f 100644
--- a/tests/mir-opt/div_overflow.rs
+++ b/tests/mir-opt/div_overflow.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // compile-flags: -Copt-level=0 -Coverflow-checks=yes
 
 // Tests that division with a const does not emit a panicking branch for overflow
diff --git a/tests/mir-opt/dont_yeet_assert.generic.InstCombine.diff b/tests/mir-opt/dont_yeet_assert.generic.InstCombine.diff
index c1a42a47ed21..c0fc1fb1df37 100644
--- a/tests/mir-opt/dont_yeet_assert.generic.InstCombine.diff
+++ b/tests/mir-opt/dont_yeet_assert.generic.InstCombine.diff
@@ -7,7 +7,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/dont_yeet_assert.rs:+1:5: +1:61
-          _1 = assert_mem_uninitialized_valid::<&T>() -> bb1; // scope 0 at $DIR/dont_yeet_assert.rs:+1:5: +1:61
+          _1 = assert_mem_uninitialized_valid::<&T>() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/dont_yeet_assert.rs:+1:5: +1:61
                                            // mir::Constant
                                            // + span: $DIR/dont_yeet_assert.rs:10:5: 10:59
                                            // + user_ty: UserType(0)
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 ec063294856c..8a4a16825195 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
@@ -40,7 +40,7 @@
           _5 = &(*_1);                     // scope 0 at $DIR/funky_arms.rs:+4:22: +4:37
           _4 = Formatter::<'_>::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:+4:22: +4:37
                                            // mir::Constant
-                                           // + span: $DIR/funky_arms.rs:15:26: 15:35
+                                           // + span: $DIR/funky_arms.rs:16:26: 16:35
                                            // + literal: Const { ty: for<'a> fn(&'a Formatter<'_>) -> bool {Formatter::<'_>::sign_plus}, val: Value() }
       }
   
@@ -74,7 +74,7 @@
           _8 = &(*_1);                     // scope 3 at $DIR/funky_arms.rs:+13:30: +13:45
           _7 = Formatter::<'_>::precision(move _8) -> bb5; // scope 3 at $DIR/funky_arms.rs:+13:30: +13:45
                                            // mir::Constant
-                                           // + span: $DIR/funky_arms.rs:24:34: 24:43
+                                           // + span: $DIR/funky_arms.rs:25:34: 25:43
                                            // + literal: Const { ty: for<'a> fn(&'a Formatter<'_>) -> Option {Formatter::<'_>::precision}, val: Value() }
       }
   
@@ -95,7 +95,7 @@
           StorageDead(_15);                // scope 3 at $DIR/funky_arms.rs:+15:78: +15:79
           _0 = float_to_exponential_common_exact::(_1, _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
+                                           // + span: $DIR/funky_arms.rs:27:9: 27: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() }
       }
   
@@ -110,7 +110,7 @@
           _20 = _6;                        // scope 2 at $DIR/funky_arms.rs:+17:56: +17:60
           _0 = float_to_exponential_common_shortest::(_1, _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
+                                           // + span: $DIR/funky_arms.rs:29:9: 29: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() }
       }
   
diff --git a/tests/mir-opt/funky_arms.rs b/tests/mir-opt/funky_arms.rs
index 3e70d85e0d47..c4f75b5df6d8 100644
--- a/tests/mir-opt/funky_arms.rs
+++ b/tests/mir-opt/funky_arms.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // compile-flags: --crate-type lib -Cdebug-assertions=no
 
 #![feature(flt2dec)]
diff --git a/tests/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir b/tests/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
index cfbe0aaf252d..32b472ebeeb5 100644
--- a/tests/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
+++ b/tests/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
@@ -110,7 +110,7 @@ yields ()
 
     bb13 (cleanup): {
         StorageDead(_3);                 // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
-        drop(_1) -> bb14;                // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
+        drop(_1) -> [return: bb14, unwind terminate]; // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
     }
 
     bb14 (cleanup): {
@@ -119,6 +119,6 @@ yields ()
 
     bb15 (cleanup): {
         StorageDead(_3);                 // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
-        drop(_1) -> bb14;                // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
+        drop(_1) -> [return: bb14, unwind terminate]; // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
     }
 }
diff --git a/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir b/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
index 7efda05d2b88..dc9bb533f132 100644
--- a/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
+++ b/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
@@ -63,7 +63,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator_tiny.rs:19:16: 19:24
         StorageDead(_7);                 // scope 1 at $DIR/generator_tiny.rs:+3:17: +3:18
         StorageDead(_6);                 // scope 1 at $DIR/generator_tiny.rs:+3:18: +3:19
         StorageLive(_8);                 // scope 1 at $DIR/generator_tiny.rs:+4:13: +4:21
-        _8 = callee() -> bb4;            // scope 1 at $DIR/generator_tiny.rs:+4:13: +4:21
+        _8 = callee() -> [return: bb4, unwind unreachable]; // scope 1 at $DIR/generator_tiny.rs:+4:13: +4:21
                                          // mir::Constant
                                          // + span: $DIR/generator_tiny.rs:23:13: 23:19
                                          // + literal: Const { ty: fn() {callee}, val: Value() }
diff --git a/tests/mir-opt/inline/asm_unwind.main.Inline.diff b/tests/mir-opt/inline/asm_unwind.main.Inline.diff
index ed290063a930..ba1bfec05d21 100644
--- a/tests/mir-opt/inline/asm_unwind.main.Inline.diff
+++ b/tests/mir-opt/inline/asm_unwind.main.Inline.diff
@@ -35,7 +35,7 @@
 +     }
 + 
 +     bb3 (cleanup): {
-+         drop(_2) -> bb4;                 // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2
++         drop(_2) -> [return: bb4, unwind terminate]; // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2
 +     }
 + 
 +     bb4 (cleanup): {
diff --git a/tests/mir-opt/inline/cycle.f.Inline.diff b/tests/mir-opt/inline/cycle.f.Inline.diff
index 501390c3bf10..8da597577431 100644
--- a/tests/mir-opt/inline/cycle.f.Inline.diff
+++ b/tests/mir-opt/inline/cycle.f.Inline.diff
@@ -33,7 +33,7 @@
       }
   
       bb3 (cleanup): {
-          drop(_1) -> bb4;                 // scope 0 at $DIR/cycle.rs:+2:1: +2:2
+          drop(_1) -> [return: bb4, unwind terminate]; // scope 0 at $DIR/cycle.rs:+2:1: +2:2
       }
   
       bb4 (cleanup): {
diff --git a/tests/mir-opt/inline/cycle.g.Inline.diff b/tests/mir-opt/inline/cycle.g.Inline.diff
index 20d313aecf58..1e6e30f9e9be 100644
--- a/tests/mir-opt/inline/cycle.g.Inline.diff
+++ b/tests/mir-opt/inline/cycle.g.Inline.diff
@@ -42,7 +42,7 @@
 +     }
 + 
 +     bb2 (cleanup): {
-+         drop(_2) -> bb3;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++         drop(_2) -> [return: bb3, unwind terminate]; // scope 1 at $DIR/cycle.rs:7:1: 7:2
 +     }
 + 
 +     bb3 (cleanup): {
diff --git a/tests/mir-opt/inline/cycle.main.Inline.diff b/tests/mir-opt/inline/cycle.main.Inline.diff
index dacc5f4be9d7..315634945e43 100644
--- a/tests/mir-opt/inline/cycle.main.Inline.diff
+++ b/tests/mir-opt/inline/cycle.main.Inline.diff
@@ -42,7 +42,7 @@
 +     }
 + 
 +     bb2 (cleanup): {
-+         drop(_2) -> bb3;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++         drop(_2) -> [return: bb3, unwind terminate]; // scope 1 at $DIR/cycle.rs:7:1: 7:2
 +     }
 + 
 +     bb3 (cleanup): {
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 64c3e47ff46e..75d9bd54d5ba 100644
--- a/tests/mir-opt/inline/dyn_trait.get_query.Inline.diff
+++ b/tests/mir-opt/inline/dyn_trait.get_query.Inline.diff
@@ -9,11 +9,11 @@
       let mut _4: &::C;        // in scope 0 at $DIR/dyn_trait.rs:+2:23: +2:24
       scope 1 {
           debug c => _2;                   // in scope 1 at $DIR/dyn_trait.rs:+1:9: +1:10
-+         scope 2 (inlined try_execute_query::<::C>) { // at $DIR/dyn_trait.rs:34:5: 34:25
-+             debug c => _4;               // in scope 2 at $DIR/dyn_trait.rs:26:36: 26:37
-+             let mut _5: &dyn Cache::V>; // in scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
-+             scope 3 (inlined mk_cycle::<::V>) { // at $DIR/dyn_trait.rs:27:5: 27:16
-+                 debug c => _5;           // in scope 3 at $DIR/dyn_trait.rs:20:27: 20:28
++         scope 2 (inlined try_execute_query::<::C>) { // at $DIR/dyn_trait.rs:35:5: 35:25
++             debug c => _4;               // in scope 2 at $DIR/dyn_trait.rs:27:36: 27:37
++             let mut _5: &dyn Cache::V>; // in scope 2 at $DIR/dyn_trait.rs:28:14: 28:15
++             scope 3 (inlined mk_cycle::<::V>) { // at $DIR/dyn_trait.rs:28:5: 28:16
++                 debug c => _5;           // in scope 3 at $DIR/dyn_trait.rs:21:27: 21:28
 +             }
 +         }
       }
@@ -24,7 +24,7 @@
           _3 = &(*_1);                     // scope 0 at $DIR/dyn_trait.rs:+1:22: +1:23
           _2 = ::cache::(move _3) -> bb1; // scope 0 at $DIR/dyn_trait.rs:+1:13: +1:24
                                            // mir::Constant
-                                           // + span: $DIR/dyn_trait.rs:33:13: 33:21
+                                           // + span: $DIR/dyn_trait.rs:34:13: 34:21
                                            // + user_ty: UserType(0)
                                            // + literal: Const { ty: for<'a> fn(&'a T) -> &'a ::C {::cache::}, val: Value() }
       }
@@ -34,18 +34,18 @@
           StorageLive(_4);                 // scope 1 at $DIR/dyn_trait.rs:+2:23: +2:24
           _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 = _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
++         StorageLive(_5);                 // scope 2 at $DIR/dyn_trait.rs:28:14: 28:15
++         _5 = _4 as &dyn Cache::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn_trait.rs:28:14: 28:15
++         _0 = ::V> as Cache>::store_nocache(_5) -> bb2; // scope 3 at $DIR/dyn_trait.rs:22:5: 22:22
                                            // mir::Constant
--                                          // + span: $DIR/dyn_trait.rs:34:5: 34:22
+-                                          // + span: $DIR/dyn_trait.rs:35:5: 35:22
 -                                          // + literal: Const { ty: for<'a> fn(&'a ::C) {try_execute_query::<::C>}, val: Value() }
-+                                          // + span: $DIR/dyn_trait.rs:21:7: 21:20
++                                          // + span: $DIR/dyn_trait.rs:22:7: 22:20
 +                                          // + literal: Const { ty: for<'a> fn(&'a dyn Cache::V>) {::V> as Cache>::store_nocache}, val: Value() }
       }
   
       bb2: {
-+         StorageDead(_5);                 // scope 2 at $DIR/dyn_trait.rs:27:15: 27:16
++         StorageDead(_5);                 // scope 2 at $DIR/dyn_trait.rs:28:15: 28:16
           StorageDead(_4);                 // scope 1 at $DIR/dyn_trait.rs:+2:24: +2:25
           StorageDead(_2);                 // scope 0 at $DIR/dyn_trait.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/dyn_trait.rs:+3:2: +3:2
diff --git a/tests/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff b/tests/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff
index 7653a5ded440..925c95988b79 100644
--- a/tests/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff
+++ b/tests/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff
@@ -11,7 +11,7 @@
           _2 = &(*_1);                     // scope 0 at $DIR/dyn_trait.rs:+1:5: +1:22
           _0 =  as Cache>::store_nocache(move _2) -> bb1; // scope 0 at $DIR/dyn_trait.rs:+1:5: +1:22
                                            // mir::Constant
-                                           // + span: $DIR/dyn_trait.rs:21:7: 21:20
+                                           // + span: $DIR/dyn_trait.rs:22:7: 22:20
                                            // + literal: Const { ty: for<'a> fn(&'a dyn Cache) { as Cache>::store_nocache}, val: Value() }
       }
   
diff --git a/tests/mir-opt/inline/dyn_trait.rs b/tests/mir-opt/inline/dyn_trait.rs
index 6a46e1e07b1a..2af81f825705 100644
--- a/tests/mir-opt/inline/dyn_trait.rs
+++ b/tests/mir-opt/inline/dyn_trait.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 #![crate_type = "lib"]
 
 use std::fmt::Debug;
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 3fa9c3e88f63..f4e5272abfc8 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
@@ -6,8 +6,8 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/dyn_trait.rs:+0:43: +0:43
       let mut _2: &dyn Cache::V>; // in scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
       let mut _3: &C;                      // in scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
-+     scope 1 (inlined mk_cycle::<::V>) { // at $DIR/dyn_trait.rs:27:5: 27:16
-+         debug c => _2;                   // in scope 1 at $DIR/dyn_trait.rs:20:27: 20:28
++     scope 1 (inlined mk_cycle::<::V>) { // at $DIR/dyn_trait.rs:28:5: 28:16
++         debug c => _2;                   // in scope 1 at $DIR/dyn_trait.rs:21:27: 21:28
 +     }
   
       bb0: {
@@ -17,11 +17,11 @@
           _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(_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:22:5: 22:22
                                            // mir::Constant
--                                          // + span: $DIR/dyn_trait.rs:27:5: 27:13
+-                                          // + span: $DIR/dyn_trait.rs:28:5: 28:13
 -                                          // + literal: Const { ty: for<'a> fn(&'a (dyn Cache::V> + 'a)) {mk_cycle::<::V>}, val: Value() }
-+                                          // + span: $DIR/dyn_trait.rs:21:7: 21:20
++                                          // + span: $DIR/dyn_trait.rs:22:7: 22:20
 +                                          // + literal: Const { ty: for<'a> fn(&'a dyn Cache::V>) {::V> as Cache>::store_nocache}, val: Value() }
       }
   
diff --git a/tests/mir-opt/inline/exponential_runtime.main.Inline.diff b/tests/mir-opt/inline/exponential_runtime.main.Inline.diff
index dd1f253cb47d..30af8661dec7 100644
--- a/tests/mir-opt/inline/exponential_runtime.main.Inline.diff
+++ b/tests/mir-opt/inline/exponential_runtime.main.Inline.diff
@@ -4,14 +4,14 @@
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/exponential_runtime.rs:+0:11: +0:11
       let _1: ();                          // in scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
-+     scope 1 (inlined <() as G>::call) {  // at $DIR/exponential_runtime.rs:86:5: 86:22
-+         let _2: ();                      // in scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+         let _3: ();                      // in scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+         let _4: ();                      // in scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
-+         scope 2 (inlined <() as F>::call) { // at $DIR/exponential_runtime.rs:73:9: 73:25
-+             let _5: ();                  // in scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
-+             let _6: ();                  // in scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
-+             let _7: ();                  // in scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++     scope 1 (inlined <() as G>::call) {  // at $DIR/exponential_runtime.rs:87:5: 87:22
++         let _2: ();                      // in scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         let _3: ();                      // in scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++         let _4: ();                      // in scope 1 at $DIR/exponential_runtime.rs:76:9: 76:25
++         scope 2 (inlined <() as F>::call) { // at $DIR/exponential_runtime.rs:74:9: 74:25
++             let _5: ();                  // in scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++             let _6: ();                  // in scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++             let _7: ();                  // in scope 2 at $DIR/exponential_runtime.rs:64:9: 64:25
 +         }
 +     }
   
@@ -21,14 +21,14 @@
 +         StorageLive(_2);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
 +         StorageLive(_3);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
 +         StorageLive(_4);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
-+         StorageLive(_5);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+         StorageLive(_6);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+         StorageLive(_7);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+         _5 = <() as E>::call() -> bb4;   // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
++         StorageLive(_5);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         StorageLive(_6);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         StorageLive(_7);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         _5 = <() as E>::call() -> bb4;   // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
                                            // mir::Constant
--                                          // + span: $DIR/exponential_runtime.rs:86:5: 86:20
+-                                          // + span: $DIR/exponential_runtime.rs:87:5: 87:20
 -                                          // + literal: Const { ty: fn() {<() as G>::call}, val: Value() }
-+                                          // + span: $DIR/exponential_runtime.rs:61:9: 61:23
++                                          // + span: $DIR/exponential_runtime.rs:62:9: 62:23
 +                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value() }
       }
   
@@ -42,33 +42,33 @@
 +     }
 + 
 +     bb2: {
-+         StorageDead(_7);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+         StorageDead(_6);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+         StorageDead(_5);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+         _3 = <() as F>::call() -> bb3;   // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+                                          // mir::Constant
-+                                          // + span: $DIR/exponential_runtime.rs:74:9: 74:23
-+                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value() }
-+     }
-+ 
-+     bb3: {
-+         _4 = <() as F>::call() -> bb1;   // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++         StorageDead(_7);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         StorageDead(_6);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         StorageDead(_5);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         _3 = <() as F>::call() -> bb3;   // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
 +                                          // mir::Constant
 +                                          // + span: $DIR/exponential_runtime.rs:75:9: 75:23
 +                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value() }
 +     }
 + 
-+     bb4: {
-+         _6 = <() as E>::call() -> bb5;   // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++     bb3: {
++         _4 = <() as F>::call() -> bb1;   // scope 1 at $DIR/exponential_runtime.rs:76:9: 76:25
 +                                          // mir::Constant
-+                                          // + span: $DIR/exponential_runtime.rs:62:9: 62:23
++                                          // + span: $DIR/exponential_runtime.rs:76:9: 76:23
++                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value() }
++     }
++ 
++     bb4: {
++         _6 = <() as E>::call() -> bb5;   // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:63:9: 63:23
 +                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value() }
 +     }
 + 
 +     bb5: {
-+         _7 = <() as E>::call() -> bb2;   // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++         _7 = <() as E>::call() -> bb2;   // scope 2 at $DIR/exponential_runtime.rs:64:9: 64:25
 +                                          // mir::Constant
-+                                          // + span: $DIR/exponential_runtime.rs:63:9: 63:23
++                                          // + span: $DIR/exponential_runtime.rs:64:9: 64:23
 +                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value() }
       }
   }
diff --git a/tests/mir-opt/inline/exponential_runtime.rs b/tests/mir-opt/inline/exponential_runtime.rs
index d9219d76a98b..39985528f462 100644
--- a/tests/mir-opt/inline/exponential_runtime.rs
+++ b/tests/mir-opt/inline/exponential_runtime.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // Checks that code with exponential runtime does not have exponential behavior in inlining.
 
 trait A {
diff --git a/tests/mir-opt/inline/inline_closure.foo.Inline.after.mir b/tests/mir-opt/inline/inline_closure.foo.Inline.after.mir
index fff8d0171277..1d2f99cbe68e 100644
--- a/tests/mir-opt/inline/inline_closure.foo.Inline.after.mir
+++ b/tests/mir-opt/inline/inline_closure.foo.Inline.after.mir
@@ -23,7 +23,7 @@ fn foo(_1: T, _2: i32) -> i32 {
         StorageLive(_3);                 // scope 0 at $DIR/inline_closure.rs:+1:9: +1:10
         _3 = [closure@foo::::{closure#0}]; // scope 0 at $DIR/inline_closure.rs:+1:13: +1:24
                                          // closure
-                                         // + def_id: DefId(0:6 ~ inline_closure[92ba]::foo::{closure#0})
+                                         // + def_id: DefId(0:6 ~ inline_closure[8f32]::foo::{closure#0})
                                          // + substs: [
                                          //     T,
                                          //     i8,
diff --git a/tests/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/tests/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
index dab2043064f3..80274bb7e7ef 100644
--- a/tests/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
+++ b/tests/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
@@ -26,7 +26,7 @@ fn foo(_1: T, _2: &i32) -> i32 {
         StorageLive(_3);                 // scope 0 at $DIR/inline_closure_borrows_arg.rs:+1:9: +1:10
         _3 = [closure@foo::::{closure#0}]; // scope 0 at $DIR/inline_closure_borrows_arg.rs:+1:13: +4:6
                                          // closure
-                                         // + def_id: DefId(0:6 ~ inline_closure_borrows_arg[96e9]::foo::{closure#0})
+                                         // + def_id: DefId(0:6 ~ inline_closure_borrows_arg[f89f]::foo::{closure#0})
                                          // + substs: [
                                          //     T,
                                          //     i8,
diff --git a/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
index 84fd051e0a35..b36711f82f40 100644
--- a/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
+++ b/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
@@ -32,7 +32,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         _5 = &_1;                        // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
         _3 = [closure@foo::::{closure#0}] { q: move _4, t: move _5 }; // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
                                          // closure
-                                         // + def_id: DefId(0:6 ~ inline_closure_captures[8bc0]::foo::{closure#0})
+                                         // + def_id: DefId(0:6 ~ inline_closure_captures[63a5]::foo::{closure#0})
                                          // + substs: [
                                          //     T,
                                          //     i8,
diff --git a/tests/mir-opt/inline/inline_cycle.one.Inline.diff b/tests/mir-opt/inline/inline_cycle.one.Inline.diff
index 5510cd7bc8ce..f6ba69a1d294 100644
--- a/tests/mir-opt/inline/inline_cycle.one.Inline.diff
+++ b/tests/mir-opt/inline/inline_cycle.one.Inline.diff
@@ -4,9 +4,9 @@
   fn one() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
       let _1: ();                          // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
-+     scope 1 (inlined ::call) { // at $DIR/inline_cycle.rs:14:5: 14:24
-+         scope 2 (inlined  as Call>::call) { // at $DIR/inline_cycle.rs:43:9: 43:23
-+             scope 3 (inlined  as Call>::call) { // at $DIR/inline_cycle.rs:28:9: 28:31
++     scope 1 (inlined ::call) { // at $DIR/inline_cycle.rs:15:5: 15:24
++         scope 2 (inlined  as Call>::call) { // at $DIR/inline_cycle.rs:44:9: 44:23
++             scope 3 (inlined  as Call>::call) { // at $DIR/inline_cycle.rs:29:9: 29:31
 +             }
 +         }
 +     }
@@ -14,10 +14,10 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
 -         _1 = ::call() -> bb1; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
-+         _1 = ::call() -> bb1; // scope 3 at $DIR/inline_cycle.rs:36:9: 36:28
++         _1 = ::call() -> bb1; // scope 3 at $DIR/inline_cycle.rs:37:9: 37:28
                                            // mir::Constant
--                                          // + span: $DIR/inline_cycle.rs:14:5: 14:22
-+                                          // + span: $DIR/inline_cycle.rs:36:9: 36:26
+-                                          // + span: $DIR/inline_cycle.rs:15:5: 15:22
++                                          // + span: $DIR/inline_cycle.rs:37:9: 37:26
                                            // + literal: Const { ty: fn() {::call}, val: Value() }
       }
   
diff --git a/tests/mir-opt/inline/inline_cycle.rs b/tests/mir-opt/inline/inline_cycle.rs
index 63ad57de1d46..2f81696cf03e 100644
--- a/tests/mir-opt/inline/inline_cycle.rs
+++ b/tests/mir-opt/inline/inline_cycle.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // Check that inliner handles various forms of recursion and doesn't fall into
 // an infinite inlining cycle. The particular outcome of inlining is not
 // crucial otherwise.
diff --git a/tests/mir-opt/inline/inline_cycle.two.Inline.diff b/tests/mir-opt/inline/inline_cycle.two.Inline.diff
index 0215b3d93f9e..c8f58111da7d 100644
--- a/tests/mir-opt/inline/inline_cycle.two.Inline.diff
+++ b/tests/mir-opt/inline/inline_cycle.two.Inline.diff
@@ -5,11 +5,11 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
       let _1: ();                          // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
 +     let mut _2: fn() {f};                // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
-+     let mut _4: ();                      // in scope 0 at $DIR/inline_cycle.rs:54:5: 54:8
-+     scope 1 (inlined call::) { // at $DIR/inline_cycle.rs:49:5: 49:12
-+         debug f => _2;                   // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23
-+         let _3: ();                      // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+         scope 2 (inlined >::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8
++     let mut _4: ();                      // in scope 0 at $DIR/inline_cycle.rs:55:5: 55:8
++     scope 1 (inlined call::) { // at $DIR/inline_cycle.rs:50:5: 50:12
++         debug f => _2;                   // in scope 1 at $DIR/inline_cycle.rs:54:22: 54:23
++         let _3: ();                      // in scope 1 at $DIR/inline_cycle.rs:55:5: 55:8
++         scope 2 (inlined >::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:55:5: 55:8
 +         }
 +     }
   
@@ -19,19 +19,19 @@
 +         StorageLive(_2);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
 +         _2 = f;                          // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
                                            // mir::Constant
--                                          // + span: $DIR/inline_cycle.rs:49:5: 49:9
+-                                          // + span: $DIR/inline_cycle.rs:50:5: 50:9
 -                                          // + literal: Const { ty: fn(fn() {f}) {call::}, val: Value() }
 -                                          // mir::Constant
-                                           // + span: $DIR/inline_cycle.rs:49:10: 49:11
+                                           // + span: $DIR/inline_cycle.rs:50:10: 50:11
                                            // + literal: Const { ty: fn() {f}, val: Value() }
 +         StorageLive(_3);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
-+         StorageLive(_4);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+         _4 = const ();                   // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++         StorageLive(_4);                 // scope 1 at $DIR/inline_cycle.rs:55:5: 55:8
++         _4 = const ();                   // scope 1 at $DIR/inline_cycle.rs:55:5: 55:8
 +         _3 = move _2() -> bb1;           // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
-+         StorageDead(_4);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++         StorageDead(_4);                 // scope 1 at $DIR/inline_cycle.rs:55:5: 55:8
 +         StorageDead(_3);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
 +         StorageDead(_2);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
           StorageDead(_1);                 // scope 0 at $DIR/inline_cycle.rs:+1:12: +1:13
diff --git a/tests/mir-opt/inline/inline_cycle_generic.main.Inline.diff b/tests/mir-opt/inline/inline_cycle_generic.main.Inline.diff
index 52debab4dd1c..9429ca593646 100644
--- a/tests/mir-opt/inline/inline_cycle_generic.main.Inline.diff
+++ b/tests/mir-opt/inline/inline_cycle_generic.main.Inline.diff
@@ -4,23 +4,20 @@
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/inline_cycle_generic.rs:+0:11: +0:11
       let _1: ();                          // in scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
-+     scope 1 (inlined ::call) { // at $DIR/inline_cycle_generic.rs:9:5: 9:24
-+         scope 2 (inlined  as Call>::call) { // at $DIR/inline_cycle_generic.rs:38:9: 38:31
-+             scope 3 (inlined ::call) { // at $DIR/inline_cycle_generic.rs:31:9: 31:28
-+                 scope 4 (inlined  as Call>::call) { // at $DIR/inline_cycle_generic.rs:23:9: 23:31
-+                 }
-+             }
++     scope 1 (inlined ::call) { // at $DIR/inline_cycle_generic.rs:10:5: 10:24
++         scope 2 (inlined  as Call>::call) { // at $DIR/inline_cycle_generic.rs:39:9: 39:31
 +         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
 -         _1 = ::call() -> bb1; // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
-+         _1 = ::call() -> bb1; // scope 4 at $DIR/inline_cycle_generic.rs:31:9: 31:28
++         _1 = ::call() -> bb1; // scope 2 at $DIR/inline_cycle_generic.rs:32:9: 32:28
                                            // mir::Constant
--                                          // + span: $DIR/inline_cycle_generic.rs:9:5: 9:22
-+                                          // + span: $DIR/inline_cycle_generic.rs:31:9: 31:26
-                                           // + literal: Const { ty: fn() {::call}, val: Value() }
+-                                          // + span: $DIR/inline_cycle_generic.rs:10:5: 10:22
+-                                          // + literal: Const { ty: fn() {::call}, val: Value() }
++                                          // + span: $DIR/inline_cycle_generic.rs:32:9: 32:26
++                                          // + literal: Const { ty: fn() {::call}, val: Value() }
       }
   
       bb1: {
diff --git a/tests/mir-opt/inline/inline_cycle_generic.rs b/tests/mir-opt/inline/inline_cycle_generic.rs
index 24b4f37939ad..84e6e4005a6e 100644
--- a/tests/mir-opt/inline/inline_cycle_generic.rs
+++ b/tests/mir-opt/inline/inline_cycle_generic.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // Check that inliner handles various forms of recursion and doesn't fall into
 // an infinite inlining cycle. The particular outcome of inlining is not
 // crucial otherwise.
diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.diff
index 31208e0052c6..d501b6ca8d2c 100644
--- a/tests/mir-opt/inline/inline_diverging.h.Inline.diff
+++ b/tests/mir-opt/inline/inline_diverging.h.Inline.diff
@@ -58,11 +58,11 @@
 +     }
 + 
 +     bb3 (cleanup): {
-+         drop(_3) -> bb4;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         drop(_3) -> [return: bb4, unwind terminate]; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +     }
 + 
 +     bb4 (cleanup): {
-+         drop(_2) -> bb5;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         drop(_2) -> [return: bb5, unwind terminate]; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +     }
 + 
 +     bb5 (cleanup): {
diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.diff b/tests/mir-opt/inline/inline_generator.main.Inline.diff
index 01f5052b6528..c3ca2d7d42c2 100644
--- a/tests/mir-opt/inline/inline_generator.main.Inline.diff
+++ b/tests/mir-opt/inline/inline_generator.main.Inline.diff
@@ -44,7 +44,7 @@
 -     bb1: {
 +         _4 = [generator@$DIR/inline_generator.rs:15:5: 15:8 (#0)]; // scope 2 at $DIR/inline_generator.rs:15:5: 15:41
 +                                          // generator
-+                                          // + def_id: DefId(0:7 ~ inline_generator[ea31]::g::{closure#0})
++                                          // + def_id: DefId(0:7 ~ inline_generator[e37e]::g::{closure#0})
 +                                          // + substs: [
 +                                          //     bool,
 +                                          //     i32,
diff --git a/tests/mir-opt/inline/inline_instruction_set.default.Inline.diff b/tests/mir-opt/inline/inline_instruction_set.default.Inline.diff
index f1988ea4bd67..a1d2423ae270 100644
--- a/tests/mir-opt/inline/inline_instruction_set.default.Inline.diff
+++ b/tests/mir-opt/inline/inline_instruction_set.default.Inline.diff
@@ -16,7 +16,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
-          _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
+          _1 = instruction_set_a32() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
                                            // mir::Constant
                                            // + span: $DIR/inline_instruction_set.rs:57:5: 57:24
                                            // + literal: Const { ty: fn() {instruction_set_a32}, val: Value() }
@@ -25,7 +25,7 @@
       bb1: {
           StorageDead(_1);                 // scope 0 at $DIR/inline_instruction_set.rs:+1:26: +1:27
           StorageLive(_2);                 // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
-          _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
+          _2 = instruction_set_t32() -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
                                            // mir::Constant
                                            // + span: $DIR/inline_instruction_set.rs:58:5: 58:24
                                            // + literal: Const { ty: fn() {instruction_set_t32}, val: Value() }
@@ -34,7 +34,7 @@
       bb2: {
           StorageDead(_2);                 // scope 0 at $DIR/inline_instruction_set.rs:+2:26: +2:27
           StorageLive(_3);                 // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
--         _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
+-         _3 = instruction_set_default() -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline_instruction_set.rs:59:5: 59:28
 -                                          // + literal: Const { ty: fn() {instruction_set_default}, val: Value() }
@@ -43,11 +43,11 @@
 -     bb3: {
           StorageDead(_3);                 // scope 0 at $DIR/inline_instruction_set.rs:+3:30: +3:31
           StorageLive(_4);                 // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
--         _4 = inline_always_and_using_inline_asm() -> bb4; // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
+-         _4 = inline_always_and_using_inline_asm() -> [return: bb4, unwind unreachable]; // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline_instruction_set.rs:60:5: 60:39
 -                                          // + literal: Const { ty: fn() {inline_always_and_using_inline_asm}, val: Value() }
-+         asm!("/* do nothing */", options((empty))) -> bb3; // scope 3 at $DIR/inline_instruction_set.rs:43:14: 43:38
++         asm!("/* do nothing */", options((empty))) -> [return: bb3, unwind unreachable]; // scope 3 at $DIR/inline_instruction_set.rs:43:14: 43:38
       }
   
 -     bb4: {
diff --git a/tests/mir-opt/inline/inline_instruction_set.t32.Inline.diff b/tests/mir-opt/inline/inline_instruction_set.t32.Inline.diff
index e777b2cc29eb..36aec4f47b08 100644
--- a/tests/mir-opt/inline/inline_instruction_set.t32.Inline.diff
+++ b/tests/mir-opt/inline/inline_instruction_set.t32.Inline.diff
@@ -14,7 +14,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
-          _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
+          _1 = instruction_set_a32() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
                                            // mir::Constant
                                            // + span: $DIR/inline_instruction_set.rs:49:5: 49:24
                                            // + literal: Const { ty: fn() {instruction_set_a32}, val: Value() }
@@ -23,7 +23,7 @@
       bb1: {
           StorageDead(_1);                 // scope 0 at $DIR/inline_instruction_set.rs:+1:26: +1:27
           StorageLive(_2);                 // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
--         _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
+-         _2 = instruction_set_t32() -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline_instruction_set.rs:50:5: 50:24
 -                                          // + literal: Const { ty: fn() {instruction_set_t32}, val: Value() }
@@ -32,7 +32,7 @@
 -     bb2: {
           StorageDead(_2);                 // scope 0 at $DIR/inline_instruction_set.rs:+2:26: +2:27
           StorageLive(_3);                 // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
--         _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
+-         _3 = instruction_set_default() -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline_instruction_set.rs:51:5: 51:28
 -                                          // + literal: Const { ty: fn() {instruction_set_default}, val: Value() }
@@ -41,8 +41,8 @@
 -     bb3: {
           StorageDead(_3);                 // scope 0 at $DIR/inline_instruction_set.rs:+3:30: +3:31
           StorageLive(_4);                 // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
--         _4 = inline_always_and_using_inline_asm() -> bb4; // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
-+         _4 = inline_always_and_using_inline_asm() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
+-         _4 = inline_always_and_using_inline_asm() -> [return: bb4, unwind unreachable]; // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
++         _4 = inline_always_and_using_inline_asm() -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/inline_instruction_set.rs:+4:5: +4:41
                                            // mir::Constant
                                            // + span: $DIR/inline_instruction_set.rs:52:5: 52:39
                                            // + literal: Const { ty: fn() {inline_always_and_using_inline_asm}, val: Value() }
diff --git a/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff b/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff
index a4f0ad465e21..a5129e0e8c8e 100644
--- a/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff
+++ b/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff
@@ -75,7 +75,7 @@
   
       bb4 (cleanup): {
 -         resume;                          // scope 0 at $DIR/inline_into_box_place.rs:+0:1: +2:2
-+         drop(_2) -> bb2;                 // scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
++         drop(_2) -> [return: bb2, unwind terminate]; // scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
       }
   }
   
diff --git a/tests/mir-opt/inline/inline_options.main.Inline.after.mir b/tests/mir-opt/inline/inline_options.main.Inline.after.mir
index abe26bd8ce36..a2938ead0dc1 100644
--- a/tests/mir-opt/inline/inline_options.main.Inline.after.mir
+++ b/tests/mir-opt/inline/inline_options.main.Inline.after.mir
@@ -4,17 +4,17 @@ fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/inline_options.rs:+0:11: +0:11
     let _1: ();                          // in scope 0 at $DIR/inline_options.rs:+1:5: +1:18
     let _2: ();                          // in scope 0 at $DIR/inline_options.rs:+2:5: +2:21
-    scope 1 (inlined inlined::) {   // at $DIR/inline_options.rs:10:5: 10:21
-        let _3: ();                      // in scope 1 at $DIR/inline_options.rs:16:23: 16:26
-        let _4: ();                      // in scope 1 at $DIR/inline_options.rs:16:28: 16:31
-        let _5: ();                      // in scope 1 at $DIR/inline_options.rs:16:33: 16:36
+    scope 1 (inlined inlined::) {   // at $DIR/inline_options.rs:11:5: 11:21
+        let _3: ();                      // in scope 1 at $DIR/inline_options.rs:17:23: 17:26
+        let _4: ();                      // in scope 1 at $DIR/inline_options.rs:17:28: 17:31
+        let _5: ();                      // in scope 1 at $DIR/inline_options.rs:17:33: 17:36
     }
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/inline_options.rs:+1:5: +1:18
         _1 = not_inlined() -> bb1;       // scope 0 at $DIR/inline_options.rs:+1:5: +1:18
                                          // mir::Constant
-                                         // + span: $DIR/inline_options.rs:9:5: 9:16
+                                         // + span: $DIR/inline_options.rs:10:5: 10:16
                                          // + literal: Const { ty: fn() {not_inlined}, val: Value() }
     }
 
@@ -24,9 +24,9 @@ fn main() -> () {
         StorageLive(_3);                 // scope 0 at $DIR/inline_options.rs:+2:5: +2:21
         StorageLive(_4);                 // scope 0 at $DIR/inline_options.rs:+2:5: +2:21
         StorageLive(_5);                 // scope 0 at $DIR/inline_options.rs:+2:5: +2:21
-        _3 = g() -> bb3;                 // scope 1 at $DIR/inline_options.rs:16:23: 16:26
+        _3 = g() -> bb3;                 // scope 1 at $DIR/inline_options.rs:17:23: 17:26
                                          // mir::Constant
-                                         // + span: $DIR/inline_options.rs:16:23: 16:24
+                                         // + span: $DIR/inline_options.rs:17:23: 17:24
                                          // + literal: Const { ty: fn() {g}, val: Value() }
     }
 
@@ -40,16 +40,16 @@ fn main() -> () {
     }
 
     bb3: {
-        _4 = g() -> bb4;                 // scope 1 at $DIR/inline_options.rs:16:28: 16:31
+        _4 = g() -> bb4;                 // scope 1 at $DIR/inline_options.rs:17:28: 17:31
                                          // mir::Constant
-                                         // + span: $DIR/inline_options.rs:16:28: 16:29
+                                         // + span: $DIR/inline_options.rs:17:28: 17:29
                                          // + literal: Const { ty: fn() {g}, val: Value() }
     }
 
     bb4: {
-        _5 = g() -> bb2;                 // scope 1 at $DIR/inline_options.rs:16:33: 16:36
+        _5 = g() -> bb2;                 // scope 1 at $DIR/inline_options.rs:17:33: 17:36
                                          // mir::Constant
-                                         // + span: $DIR/inline_options.rs:16:33: 16:34
+                                         // + span: $DIR/inline_options.rs:17:33: 17:34
                                          // + literal: Const { ty: fn() {g}, val: Value() }
     }
 }
diff --git a/tests/mir-opt/inline/inline_options.rs b/tests/mir-opt/inline/inline_options.rs
index 477f050b69e4..f0a898832392 100644
--- a/tests/mir-opt/inline/inline_options.rs
+++ b/tests/mir-opt/inline/inline_options.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // Checks that inlining threshold can be controlled with
 // inline-mir-threshold and inline-hint-threshold options.
 //
diff --git a/tests/mir-opt/inline/inline_specialization.main.Inline.diff b/tests/mir-opt/inline/inline_specialization.main.Inline.diff
index af08296edea5..9dde9994d1d1 100644
--- a/tests/mir-opt/inline/inline_specialization.main.Inline.diff
+++ b/tests/mir-opt/inline/inline_specialization.main.Inline.diff
@@ -7,19 +7,19 @@
       scope 1 {
           debug x => _1;                   // in scope 1 at $DIR/inline_specialization.rs:+1:9: +1:10
       }
-+     scope 2 (inlined  as Foo>::bar) { // at $DIR/inline_specialization.rs:5:13: 5:38
++     scope 2 (inlined  as Foo>::bar) { // at $DIR/inline_specialization.rs:6:13: 6:38
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_specialization.rs:+1:9: +1:10
 -         _1 =  as Foo>::bar() -> bb1; // scope 0 at $DIR/inline_specialization.rs:+1:13: +1:38
 -                                          // mir::Constant
--                                          // + span: $DIR/inline_specialization.rs:5:13: 5:36
+-                                          // + span: $DIR/inline_specialization.rs:6:13: 6:36
 -                                          // + literal: Const { ty: fn() -> u32 { as Foo>::bar}, val: Value() }
 -     }
 - 
 -     bb1: {
-+         _1 = const 123_u32;              // scope 2 at $DIR/inline_specialization.rs:14:31: 14:34
++         _1 = const 123_u32;              // scope 2 at $DIR/inline_specialization.rs:15:31: 15:34
           _0 = const ();                   // scope 0 at $DIR/inline_specialization.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/inline_specialization.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/inline_specialization.rs:+2:2: +2:2
diff --git a/tests/mir-opt/inline/inline_specialization.rs b/tests/mir-opt/inline/inline_specialization.rs
index 87275b4e5146..c24795e05c6d 100644
--- a/tests/mir-opt/inline/inline_specialization.rs
+++ b/tests/mir-opt/inline/inline_specialization.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 #![feature(specialization)]
 
 // EMIT_MIR inline_specialization.main.Inline.diff
diff --git a/tests/mir-opt/inline/inline_trait_method.rs b/tests/mir-opt/inline/inline_trait_method.rs
index 74be53f55129..6aa957eb5349 100644
--- a/tests/mir-opt/inline/inline_trait_method.rs
+++ b/tests/mir-opt/inline/inline_trait_method.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // compile-flags: -Z span_free_formats
 
 fn main() {
diff --git a/tests/mir-opt/inline/inline_trait_method.test.Inline.after.mir b/tests/mir-opt/inline/inline_trait_method.test.Inline.after.mir
index 637bf282a65b..a9020a5bbb7c 100644
--- a/tests/mir-opt/inline/inline_trait_method.test.Inline.after.mir
+++ b/tests/mir-opt/inline/inline_trait_method.test.Inline.after.mir
@@ -10,7 +10,7 @@ fn test(_1: &dyn X) -> u32 {
         _2 = &(*_1);                     // scope 0 at $DIR/inline_trait_method.rs:+1:5: +1:10
         _0 = ::y(move _2) -> bb1; // scope 0 at $DIR/inline_trait_method.rs:+1:5: +1:10
                                          // mir::Constant
-                                         // + span: $DIR/inline_trait_method.rs:9:7: 9:8
+                                         // + span: $DIR/inline_trait_method.rs:10:7: 10:8
                                          // + literal: Const { ty: for<'a> fn(&'a dyn X) -> u32 {::y}, val: Value() }
     }
 
diff --git a/tests/mir-opt/inline/inline_trait_method_2.rs b/tests/mir-opt/inline/inline_trait_method_2.rs
index 378e71a25673..07a601908018 100644
--- a/tests/mir-opt/inline/inline_trait_method_2.rs
+++ b/tests/mir-opt/inline/inline_trait_method_2.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // compile-flags: -Z span_free_formats -Z mir-opt-level=4
 
 // EMIT_MIR inline_trait_method_2.test2.Inline.after.mir
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 b7c5bbecb688..a4bbecf3b876 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
@@ -5,8 +5,8 @@ fn test2(_1: &dyn X) -> bool {
     let mut _0: bool;                    // return place in scope 0 at $DIR/inline_trait_method_2.rs:+0:24: +0:28
     let mut _2: &dyn X;                  // in scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
     let mut _3: &dyn X;                  // in scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
-    scope 1 (inlined test) {             // at $DIR/inline_trait_method_2.rs:5:5: 5:12
-        debug x => _2;                   // in scope 1 at $DIR/inline_trait_method_2.rs:9:9: 9:10
+    scope 1 (inlined test) {             // at $DIR/inline_trait_method_2.rs:6:5: 6:12
+        debug x => _2;                   // in scope 1 at $DIR/inline_trait_method_2.rs:10:9: 10:10
     }
 
     bb0: {
@@ -15,9 +15,9 @@ 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(_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:11:5: 11:10
                                          // mir::Constant
-                                         // + span: $DIR/inline_trait_method_2.rs:10:7: 10:8
+                                         // + span: $DIR/inline_trait_method_2.rs:11:7: 11:8
                                          // + literal: Const { ty: for<'a> fn(&'a dyn X) -> bool {::y}, val: Value() }
     }
 
diff --git a/tests/mir-opt/inline/issue_106141.outer.Inline.diff b/tests/mir-opt/inline/issue_106141.outer.Inline.diff
index 97361fa5f4c3..18df6f9af5fa 100644
--- a/tests/mir-opt/inline/issue_106141.outer.Inline.diff
+++ b/tests/mir-opt/inline/issue_106141.outer.Inline.diff
@@ -3,14 +3,14 @@
   
   fn outer() -> usize {
       let mut _0: usize;                   // return place in scope 0 at $DIR/issue_106141.rs:+0:19: +0:24
-+     scope 1 (inlined inner) {            // at $DIR/issue_106141.rs:2:5: 2:12
-+         let mut _1: bool;                // in scope 1 at $DIR/issue_106141.rs:13:8: 13:21
-+         let mut _2: bool;                // in scope 1 at $DIR/issue_106141.rs:13:8: 13:21
-+         let mut _3: &[bool; 1];          // in scope 1 at $DIR/issue_106141.rs:11:18: 11:25
++     scope 1 (inlined inner) {            // at $DIR/issue_106141.rs:3:5: 3:12
++         let mut _1: bool;                // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21
++         let mut _2: bool;                // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21
++         let mut _3: &[bool; 1];          // in scope 1 at $DIR/issue_106141.rs:12:18: 12:25
 +         scope 2 {
-+             debug buffer => _3;          // in scope 2 at $DIR/issue_106141.rs:11:9: 11:15
++             debug buffer => _3;          // in scope 2 at $DIR/issue_106141.rs:12:9: 12:15
 +             scope 3 {
-+                 debug index => _0;       // in scope 3 at $DIR/issue_106141.rs:12:9: 12:14
++                 debug index => _0;       // in scope 3 at $DIR/issue_106141.rs:13:9: 13:14
 +             }
 +         }
 +     }
@@ -18,36 +18,36 @@
       bb0: {
 -         _0 = inner() -> bb1;             // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
 +         StorageLive(_3);                 // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
-+         _3 = const _;                    // scope 1 at $DIR/issue_106141.rs:11:18: 11:25
++         _3 = const _;                    // scope 1 at $DIR/issue_106141.rs:12:18: 12:25
                                            // mir::Constant
--                                          // + span: $DIR/issue_106141.rs:2:5: 2:10
+-                                          // + span: $DIR/issue_106141.rs:3:5: 3:10
 -                                          // + literal: Const { ty: fn() -> usize {inner}, val: Value() }
-+                                          // + span: $DIR/issue_106141.rs:11:18: 11:25
++                                          // + span: $DIR/issue_106141.rs:12:18: 12:25
 +                                          // + literal: Const { ty: &[bool; 1], val: Unevaluated(inner, [], Some(promoted[0])) }
-+         _0 = index() -> bb1;             // scope 2 at $DIR/issue_106141.rs:12:17: 12:24
++         _0 = index() -> bb1;             // scope 2 at $DIR/issue_106141.rs:13:17: 13:24
 +                                          // mir::Constant
-+                                          // + span: $DIR/issue_106141.rs:12:17: 12:22
++                                          // + span: $DIR/issue_106141.rs:13:17: 13:22
 +                                          // + literal: Const { ty: fn() -> usize {index}, val: Value() }
       }
   
       bb1: {
-+         StorageLive(_1);                 // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
-+         _2 = Lt(_0, const 1_usize);      // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
-+         assert(move _2, "index out of bounds: the length is {} but the index is {}", const 1_usize, _0) -> bb2; // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++         StorageLive(_1);                 // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
++         _2 = Lt(_0, const 1_usize);      // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
++         assert(move _2, "index out of bounds: the length is {} but the index is {}", const 1_usize, _0) -> bb2; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
 +     }
 + 
 +     bb2: {
-+         _1 = (*_3)[_0];                  // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
-+         switchInt(move _1) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++         _1 = (*_3)[_0];                  // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
++         switchInt(move _1) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21
 +     }
 + 
 +     bb3: {
-+         _0 = const 0_usize;              // scope 3 at $DIR/issue_106141.rs:16:9: 16:10
-+         goto -> bb4;                     // scope 3 at $DIR/issue_106141.rs:13:5: 17:6
++         _0 = const 0_usize;              // scope 3 at $DIR/issue_106141.rs:17:9: 17:10
++         goto -> bb4;                     // scope 3 at $DIR/issue_106141.rs:14:5: 18:6
 +     }
 + 
 +     bb4: {
-+         StorageDead(_1);                 // scope 3 at $DIR/issue_106141.rs:17:5: 17:6
++         StorageDead(_1);                 // scope 3 at $DIR/issue_106141.rs:18:5: 18:6
 +         StorageDead(_3);                 // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
           return;                          // scope 0 at $DIR/issue_106141.rs:+2:2: +2:2
       }
diff --git a/tests/mir-opt/inline/issue_106141.rs b/tests/mir-opt/inline/issue_106141.rs
index c8288b7f3419..b6bd806e6fce 100644
--- a/tests/mir-opt/inline/issue_106141.rs
+++ b/tests/mir-opt/inline/issue_106141.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 pub fn outer() -> usize {
     inner()
 }
diff --git a/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir b/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
index a98c294cacbe..1da3c8bb7977 100644
--- a/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
+++ b/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
@@ -21,7 +21,7 @@ fn main() -> () {
         StorageLive(_1);                 // scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:9: +1:10
         _1 = [closure@$DIR/issue_76997_inline_scopes_parenting.rs:5:13: 5:16]; // scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:13: +1:33
                                          // closure
-                                         // + def_id: DefId(0:4 ~ issue_76997_inline_scopes_parenting[bc59]::main::{closure#0})
+                                         // + def_id: DefId(0:4 ~ issue_76997_inline_scopes_parenting[5cd2]::main::{closure#0})
                                          // + substs: [
                                          //     i8,
                                          //     extern "rust-call" fn(((),)),
diff --git a/tests/mir-opt/inline/issue_78442.bar.Inline.diff b/tests/mir-opt/inline/issue_78442.bar.Inline.diff
index aa62e4a165e1..dc3fe75559e9 100644
--- a/tests/mir-opt/inline/issue_78442.bar.Inline.diff
+++ b/tests/mir-opt/inline/issue_78442.bar.Inline.diff
@@ -46,11 +46,11 @@
 -     bb3: {
 -         return;                          // scope 0 at $DIR/issue_78442.rs:+5:2: +5:2
 +     bb3 (cleanup): {
-+         drop(_1) -> bb4;                 // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
++         drop(_1) -> [return: bb4, unwind terminate]; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
       }
   
       bb4 (cleanup): {
--         drop(_1) -> bb5;                 // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
+-         drop(_1) -> [return: bb5, unwind terminate]; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
 +         resume;                          // scope 0 at $DIR/issue_78442.rs:+0:1: +5:2
       }
   
diff --git a/tests/mir-opt/inline/issue_78442.bar.RevealAll.diff b/tests/mir-opt/inline/issue_78442.bar.RevealAll.diff
index 21055c6bfb57..8f56ef2585ce 100644
--- a/tests/mir-opt/inline/issue_78442.bar.RevealAll.diff
+++ b/tests/mir-opt/inline/issue_78442.bar.RevealAll.diff
@@ -47,7 +47,7 @@
       }
   
       bb4 (cleanup): {
-          drop(_1) -> bb5;                 // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
+          drop(_1) -> [return: bb5, unwind terminate]; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
       }
   
       bb5 (cleanup): {
diff --git a/tests/mir-opt/inline/unchecked_shifts.rs b/tests/mir-opt/inline/unchecked_shifts.rs
index e55fa745abce..17724530d657 100644
--- a/tests/mir-opt/inline/unchecked_shifts.rs
+++ b/tests/mir-opt/inline/unchecked_shifts.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 #![crate_type = "lib"]
 #![feature(unchecked_math)]
 
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff
index 5fd918b3aa53..6184a0acd187 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff
@@ -7,43 +7,52 @@
       let mut _0: u16;                     // return place in scope 0 at $DIR/unchecked_shifts.rs:+0:65: +0:68
       let mut _3: u16;                     // in scope 0 at $DIR/unchecked_shifts.rs:+1:5: +1:6
       let mut _4: u32;                     // in scope 0 at $DIR/unchecked_shifts.rs:+1:21: +1:22
-+     scope 1 (inlined core::num::::unchecked_shl) { // at $DIR/unchecked_shifts.rs:10:7: 10:23
++     scope 1 (inlined core::num::::unchecked_shl) { // at $DIR/unchecked_shifts.rs:11:7: 11:23
 +         debug self => _3;                // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
 +         debug rhs => _4;                 // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
 +         let mut _5: u16;                 // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
 +         let mut _6: std::option::Option; // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
 +         let mut _7: std::result::Result; // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
 +         scope 2 {
-+             scope 3 (inlined Result::::ok) { // at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-+                 debug self => _7;        // in scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-+                 let mut _8: isize;       // in scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-+                 let _9: u16;             // in scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-+                 scope 4 {
-+                     debug x => _9;       // in scope 4 at $SRC_DIR/core/src/result.rs:LL:COL
++             scope 3 (inlined >::try_into) { // at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
++                 debug self => _4;        // in scope 3 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
++                 scope 4 (inlined convert::num:: for u16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL
++                     debug u => _4;       // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++                     let mut _8: bool;    // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++                     let mut _9: u32;     // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++                     let mut _10: u16;    // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
 +                 }
-+                 scope 5 {
-+                     scope 6 {
-+                         debug x => const TryFromIntError(()); // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
++             }
++             scope 5 (inlined Result::::ok) { // at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
++                 debug self => _7;        // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++                 let mut _11: isize;      // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++                 let _12: u16;            // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++                 scope 6 {
++                     debug x => _12;      // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
++                 }
++                 scope 7 {
++                     scope 8 {
++                         debug x => const TryFromIntError(()); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
 +                     }
 +                 }
 +             }
-+             scope 7 (inlined #[track_caller] Option::::unwrap_unchecked) { // at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-+                 debug self => _6;        // in scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-+                 let mut _10: &std::option::Option; // in scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-+                 let mut _11: isize;      // in scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-+                 scope 8 {
-+                     debug val => _5;     // in scope 8 at $SRC_DIR/core/src/option.rs:LL:COL
++             scope 9 (inlined #[track_caller] Option::::unwrap_unchecked) { // at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
++                 debug self => _6;        // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
++                 let mut _13: &std::option::Option; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
++                 let mut _14: isize;      // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
++                 scope 10 {
++                     debug val => _5;     // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
 +                 }
-+                 scope 9 {
-+                     scope 11 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL
-+                         scope 12 {
-+                             scope 13 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL
++                 scope 11 {
++                     scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL
++                         scope 14 {
++                             scope 15 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL
 +                             }
 +                         }
 +                     }
 +                 }
-+                 scope 10 (inlined Option::::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL
-+                     debug self => _10;   // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
++                 scope 12 (inlined Option::::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL
++                     debug self => _13;   // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL
 +                 }
 +             }
 +         }
@@ -55,58 +64,78 @@
           StorageLive(_4);                 // scope 0 at $DIR/unchecked_shifts.rs:+1:21: +1:22
           _4 = _2;                         // scope 0 at $DIR/unchecked_shifts.rs:+1:21: +1:22
 -         _0 = core::num::::unchecked_shl(move _3, move _4) -> bb1; // scope 0 at $DIR/unchecked_shifts.rs:+1:5: +1:23
+-                                          // mir::Constant
+-                                          // + span: $DIR/unchecked_shifts.rs:11:7: 11:20
+-                                          // + literal: Const { ty: unsafe fn(u16, u32) -> u16 {core::num::::unchecked_shl}, val: Value() }
 +         StorageLive(_5);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
 +         StorageLive(_6);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
 +         StorageLive(_7);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-+         _7 = >::try_into(_4) -> bb1; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-                                           // mir::Constant
--                                          // + span: $DIR/unchecked_shifts.rs:10:7: 10:20
--                                          // + literal: Const { ty: unsafe fn(u16, u32) -> u16 {core::num::::unchecked_shl}, val: Value() }
-+                                          // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-+                                          // + literal: Const { ty: fn(u32) -> Result>::Error> {>::try_into}, val: Value() }
++         StorageLive(_8);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         StorageLive(_9);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         _9 = const 65535_u32;            // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         _8 = Gt(_4, move _9);            // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         StorageDead(_9);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         switchInt(move _8) -> [0: bb4, otherwise: bb3]; // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
       }
   
       bb1: {
-+         StorageLive(_9);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-+         _8 = discriminant(_7);           // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-+         switchInt(move _8) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
++         StorageDead(_12);                // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
++         StorageDead(_7);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
++         StorageLive(_13);                // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
++         _14 = discriminant(_6);          // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
++         switchInt(move _14) -> [1: bb9, otherwise: bb7]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
 +     }
 + 
 +     bb2: {
-+         StorageDead(_9);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-+         StorageDead(_7);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-+         StorageLive(_10);                // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-+         _11 = discriminant(_6);          // scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-+         switchInt(move _11) -> [1: bb7, otherwise: bb5]; // scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-+     }
-+ 
-+     bb3: {
 +         StorageDead(_5);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
           StorageDead(_4);                 // scope 0 at $DIR/unchecked_shifts.rs:+1:22: +1:23
           StorageDead(_3);                 // scope 0 at $DIR/unchecked_shifts.rs:+1:22: +1:23
           return;                          // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2
 +     }
 + 
++     bb3: {
++         _7 = Result::::Err(const TryFromIntError(())); // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++                                          // mir::Constant
++                                          // + span: no-location
++                                          // + literal: Const { ty: TryFromIntError, val: Value() }
++         goto -> bb5;                     // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++     }
++ 
 +     bb4: {
-+         _6 = Option::::None;        // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-+         goto -> bb2;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++         StorageLive(_10);                // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         _10 = _4 as u16 (IntToInt);      // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         _7 = Result::::Ok(move _10); // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         StorageDead(_10);                // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         goto -> bb5;                     // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
 +     }
 + 
 +     bb5: {
-+         unreachable;                     // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
++         StorageDead(_8);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         StorageLive(_12);                // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
++         _11 = discriminant(_7);          // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++         switchInt(move _11) -> [0: bb8, 1: bb6, otherwise: bb7]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
 +     }
 + 
 +     bb6: {
-+         _9 = move ((_7 as Ok).0: u16);   // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-+         _6 = Option::::Some(move _9); // scope 4 at $SRC_DIR/core/src/result.rs:LL:COL
-+         goto -> bb2;                     // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
++         _6 = Option::::None;        // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
++         goto -> bb1;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
 +     }
 + 
 +     bb7: {
-+         _5 = move ((_6 as Some).0: u16); // scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-+         StorageDead(_10);                // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
++         unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++     }
++ 
++     bb8: {
++         _12 = move ((_7 as Ok).0: u16);  // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++         _6 = Option::::Some(move _12); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
++         goto -> bb1;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++     }
++ 
++     bb9: {
++         _5 = move ((_6 as Some).0: u16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
++         StorageDead(_13);                // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
 +         StorageDead(_6);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-+         _0 = unchecked_shl::(_3, move _5) -> bb3; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
++         _0 = unchecked_shl::(_3, move _5) -> [return: bb2, unwind unreachable]; // scope 2 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: unsafe extern "rust-intrinsic" fn(u16, u16) -> u16 {unchecked_shl::}, val: Value() }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir
index c5501cef743e..726b6bbf93b5 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir
@@ -4,43 +4,52 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 {
     debug a => _1;                       // in scope 0 at $DIR/unchecked_shifts.rs:+0:46: +0:47
     debug b => _2;                       // in scope 0 at $DIR/unchecked_shifts.rs:+0:54: +0:55
     let mut _0: u16;                     // return place in scope 0 at $DIR/unchecked_shifts.rs:+0:65: +0:68
-    scope 1 (inlined core::num::::unchecked_shl) { // at $DIR/unchecked_shifts.rs:10:7: 10:23
+    scope 1 (inlined core::num::::unchecked_shl) { // at $DIR/unchecked_shifts.rs:11:7: 11:23
         debug self => _1;                // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
         debug rhs => _2;                 // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
         let mut _3: u16;                 // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
         let mut _4: std::option::Option; // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
         let mut _5: std::result::Result; // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
         scope 2 {
-            scope 3 (inlined Result::::ok) { // at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-                debug self => _5;        // in scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-                let mut _6: isize;       // in scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-                let _7: u16;             // in scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-                scope 4 {
-                    debug x => _7;       // in scope 4 at $SRC_DIR/core/src/result.rs:LL:COL
+            scope 3 (inlined >::try_into) { // at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+                debug self => _2;        // in scope 3 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+                scope 4 (inlined convert::num:: for u16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+                    debug u => _2;       // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                    let mut _6: bool;    // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                    let mut _7: u32;     // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                    let mut _8: u16;     // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
                 }
-                scope 5 {
-                    scope 6 {
-                        debug x => const TryFromIntError(()); // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+            }
+            scope 5 (inlined Result::::ok) { // at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+                debug self => _5;        // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+                let mut _9: isize;       // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+                let _10: u16;            // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+                scope 6 {
+                    debug x => _10;      // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+                }
+                scope 7 {
+                    scope 8 {
+                        debug x => const TryFromIntError(()); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
                     }
                 }
             }
-            scope 7 (inlined #[track_caller] Option::::unwrap_unchecked) { // at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-                debug self => _4;        // in scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-                let mut _8: &std::option::Option; // in scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-                let mut _9: isize;       // in scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-                scope 8 {
-                    debug val => _3;     // in scope 8 at $SRC_DIR/core/src/option.rs:LL:COL
+            scope 9 (inlined #[track_caller] Option::::unwrap_unchecked) { // at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+                debug self => _4;        // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+                let mut _11: &std::option::Option; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+                let mut _12: isize;      // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+                scope 10 {
+                    debug val => _3;     // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
                 }
-                scope 9 {
-                    scope 11 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL
-                        scope 12 {
-                            scope 13 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+                scope 11 {
+                    scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL
+                        scope 14 {
+                            scope 15 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL
                             }
                         }
                     }
                 }
-                scope 10 (inlined Option::::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL
-                    debug self => _8;    // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
+                scope 12 (inlined Option::::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL
+                    debug self => _11;   // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL
                 }
             }
         }
@@ -50,51 +59,70 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 {
         StorageLive(_3);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
         StorageLive(_4);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
         StorageLive(_5);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-        _5 = >::try_into(_2) -> bb1; // scope 2 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: fn(u32) -> Result>::Error> {>::try_into}, val: Value() }
+        StorageLive(_6);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageLive(_7);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _7 = const 65535_u32;            // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _6 = Gt(_2, move _7);            // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageDead(_7);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        switchInt(move _6) -> [0: bb4, otherwise: bb3]; // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
     }
 
     bb1: {
-        StorageLive(_7);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-        _6 = discriminant(_5);           // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-        switchInt(move _6) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
+        StorageDead(_10);                // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+        StorageDead(_5);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+        StorageLive(_11);                // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+        _12 = discriminant(_4);          // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+        switchInt(move _12) -> [1: bb9, otherwise: bb7]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
     }
 
     bb2: {
-        StorageDead(_7);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-        StorageDead(_5);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-        StorageLive(_8);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-        _9 = discriminant(_4);           // scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-        switchInt(move _9) -> [1: bb7, otherwise: bb5]; // scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-    }
-
-    bb3: {
         StorageDead(_3);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
         return;                          // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2
     }
 
+    bb3: {
+        _5 = Result::::Err(const TryFromIntError(())); // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                                         // mir::Constant
+                                         // + span: no-location
+                                         // + literal: Const { ty: TryFromIntError, val: Value() }
+        goto -> bb5;                     // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+    }
+
     bb4: {
-        _4 = Option::::None;        // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        goto -> bb2;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+        StorageLive(_8);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _8 = _2 as u16 (IntToInt);       // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _5 = Result::::Ok(move _8); // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageDead(_8);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        goto -> bb5;                     // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
     }
 
     bb5: {
-        unreachable;                     // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
+        StorageDead(_6);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageLive(_10);                // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+        _9 = discriminant(_5);           // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+        switchInt(move _9) -> [0: bb8, 1: bb6, otherwise: bb7]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
     }
 
     bb6: {
-        _7 = move ((_5 as Ok).0: u16);   // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-        _4 = Option::::Some(move _7); // scope 4 at $SRC_DIR/core/src/result.rs:LL:COL
-        goto -> bb2;                     // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
+        _4 = Option::::None;        // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+        goto -> bb1;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
     }
 
     bb7: {
-        _3 = move ((_4 as Some).0: u16); // scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-        StorageDead(_8);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+        unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+    }
+
+    bb8: {
+        _10 = move ((_5 as Ok).0: u16);  // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+        _4 = Option::::Some(move _10); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+        goto -> bb1;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+    }
+
+    bb9: {
+        _3 = move ((_4 as Some).0: u16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+        StorageDead(_11);                // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
         StorageDead(_4);                 // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
-        _0 = unchecked_shl::(_1, move _3) -> bb3; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+        _0 = unchecked_shl::(_1, move _3) -> [return: bb2, unwind unreachable]; // scope 2 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: unsafe extern "rust-intrinsic" fn(u16, u16) -> u16 {unchecked_shl::}, val: Value() }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.diff
index 68d3b21fc2a4..35d5b6e72f28 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.diff
@@ -7,43 +7,52 @@
       let mut _0: i16;                     // return place in scope 0 at $DIR/unchecked_shifts.rs:+0:63: +0:66
       let mut _3: i16;                     // in scope 0 at $DIR/unchecked_shifts.rs:+1:5: +1:6
       let mut _4: u32;                     // in scope 0 at $DIR/unchecked_shifts.rs:+1:21: +1:22
-+     scope 1 (inlined core::num::::unchecked_shr) { // at $DIR/unchecked_shifts.rs:16:7: 16:23
++     scope 1 (inlined core::num::::unchecked_shr) { // at $DIR/unchecked_shifts.rs:17:7: 17:23
 +         debug self => _3;                // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
 +         debug rhs => _4;                 // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
 +         let mut _5: i16;                 // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
 +         let mut _6: std::option::Option; // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
 +         let mut _7: std::result::Result; // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
 +         scope 2 {
-+             scope 3 (inlined Result::::ok) { // at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-+                 debug self => _7;        // in scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-+                 let mut _8: isize;       // in scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-+                 let _9: i16;             // in scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-+                 scope 4 {
-+                     debug x => _9;       // in scope 4 at $SRC_DIR/core/src/result.rs:LL:COL
++             scope 3 (inlined >::try_into) { // at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
++                 debug self => _4;        // in scope 3 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
++                 scope 4 (inlined convert::num:: for i16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL
++                     debug u => _4;       // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++                     let mut _8: bool;    // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++                     let mut _9: u32;     // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++                     let mut _10: i16;    // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
 +                 }
-+                 scope 5 {
-+                     scope 6 {
-+                         debug x => const TryFromIntError(()); // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
++             }
++             scope 5 (inlined Result::::ok) { // at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
++                 debug self => _7;        // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++                 let mut _11: isize;      // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++                 let _12: i16;            // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++                 scope 6 {
++                     debug x => _12;      // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
++                 }
++                 scope 7 {
++                     scope 8 {
++                         debug x => const TryFromIntError(()); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
 +                     }
 +                 }
 +             }
-+             scope 7 (inlined #[track_caller] Option::::unwrap_unchecked) { // at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-+                 debug self => _6;        // in scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-+                 let mut _10: &std::option::Option; // in scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-+                 let mut _11: isize;      // in scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-+                 scope 8 {
-+                     debug val => _5;     // in scope 8 at $SRC_DIR/core/src/option.rs:LL:COL
++             scope 9 (inlined #[track_caller] Option::::unwrap_unchecked) { // at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
++                 debug self => _6;        // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
++                 let mut _13: &std::option::Option; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
++                 let mut _14: isize;      // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
++                 scope 10 {
++                     debug val => _5;     // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
 +                 }
-+                 scope 9 {
-+                     scope 11 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL
-+                         scope 12 {
-+                             scope 13 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL
++                 scope 11 {
++                     scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL
++                         scope 14 {
++                             scope 15 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL
 +                             }
 +                         }
 +                     }
 +                 }
-+                 scope 10 (inlined Option::::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL
-+                     debug self => _10;   // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
++                 scope 12 (inlined Option::::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL
++                     debug self => _13;   // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL
 +                 }
 +             }
 +         }
@@ -55,58 +64,78 @@
           StorageLive(_4);                 // scope 0 at $DIR/unchecked_shifts.rs:+1:21: +1:22
           _4 = _2;                         // scope 0 at $DIR/unchecked_shifts.rs:+1:21: +1:22
 -         _0 = core::num::::unchecked_shr(move _3, move _4) -> bb1; // scope 0 at $DIR/unchecked_shifts.rs:+1:5: +1:23
+-                                          // mir::Constant
+-                                          // + span: $DIR/unchecked_shifts.rs:17:7: 17:20
+-                                          // + literal: Const { ty: unsafe fn(i16, u32) -> i16 {core::num::::unchecked_shr}, val: Value() }
 +         StorageLive(_5);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
 +         StorageLive(_6);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
 +         StorageLive(_7);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-+         _7 = >::try_into(_4) -> bb1; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-                                           // mir::Constant
--                                          // + span: $DIR/unchecked_shifts.rs:16:7: 16:20
--                                          // + literal: Const { ty: unsafe fn(i16, u32) -> i16 {core::num::::unchecked_shr}, val: Value() }
-+                                          // + span: $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-+                                          // + literal: Const { ty: fn(u32) -> Result>::Error> {>::try_into}, val: Value() }
++         StorageLive(_8);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         StorageLive(_9);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         _9 = const 32767_u32;            // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         _8 = Gt(_4, move _9);            // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         StorageDead(_9);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         switchInt(move _8) -> [0: bb4, otherwise: bb3]; // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
       }
   
       bb1: {
-+         StorageLive(_9);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-+         _8 = discriminant(_7);           // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-+         switchInt(move _8) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
++         StorageDead(_12);                // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
++         StorageDead(_7);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
++         StorageLive(_13);                // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
++         _14 = discriminant(_6);          // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
++         switchInt(move _14) -> [1: bb9, otherwise: bb7]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
 +     }
 + 
 +     bb2: {
-+         StorageDead(_9);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-+         StorageDead(_7);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-+         StorageLive(_10);                // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-+         _11 = discriminant(_6);          // scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-+         switchInt(move _11) -> [1: bb7, otherwise: bb5]; // scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-+     }
-+ 
-+     bb3: {
 +         StorageDead(_5);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
           StorageDead(_4);                 // scope 0 at $DIR/unchecked_shifts.rs:+1:22: +1:23
           StorageDead(_3);                 // scope 0 at $DIR/unchecked_shifts.rs:+1:22: +1:23
           return;                          // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2
 +     }
 + 
++     bb3: {
++         _7 = Result::::Err(const TryFromIntError(())); // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++                                          // mir::Constant
++                                          // + span: no-location
++                                          // + literal: Const { ty: TryFromIntError, val: Value() }
++         goto -> bb5;                     // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++     }
++ 
 +     bb4: {
-+         _6 = Option::::None;        // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-+         goto -> bb2;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++         StorageLive(_10);                // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         _10 = _4 as i16 (IntToInt);      // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         _7 = Result::::Ok(move _10); // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         StorageDead(_10);                // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         goto -> bb5;                     // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
 +     }
 + 
 +     bb5: {
-+         unreachable;                     // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
++         StorageDead(_8);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
++         StorageLive(_12);                // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
++         _11 = discriminant(_7);          // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++         switchInt(move _11) -> [0: bb8, 1: bb6, otherwise: bb7]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
 +     }
 + 
 +     bb6: {
-+         _9 = move ((_7 as Ok).0: i16);   // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-+         _6 = Option::::Some(move _9); // scope 4 at $SRC_DIR/core/src/result.rs:LL:COL
-+         goto -> bb2;                     // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
++         _6 = Option::::None;        // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
++         goto -> bb1;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
 +     }
 + 
 +     bb7: {
-+         _5 = move ((_6 as Some).0: i16); // scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-+         StorageDead(_10);                // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
++         unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++     }
++ 
++     bb8: {
++         _12 = move ((_7 as Ok).0: i16);  // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++         _6 = Option::::Some(move _12); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
++         goto -> bb1;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
++     }
++ 
++     bb9: {
++         _5 = move ((_6 as Some).0: i16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
++         StorageDead(_13);                // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
 +         StorageDead(_6);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-+         _0 = unchecked_shr::(_3, move _5) -> bb3; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
++         _0 = unchecked_shr::(_3, move _5) -> [return: bb2, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
 +                                          // mir::Constant
 +                                          // + span: $SRC_DIR/core/src/num/int_macros.rs:LL:COL
 +                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i16, i16) -> i16 {unchecked_shr::}, val: Value() }
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir
index ed3a89ceace1..b006085b54c5 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir
@@ -4,43 +4,52 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 {
     debug a => _1;                       // in scope 0 at $DIR/unchecked_shifts.rs:+0:44: +0:45
     debug b => _2;                       // in scope 0 at $DIR/unchecked_shifts.rs:+0:52: +0:53
     let mut _0: i16;                     // return place in scope 0 at $DIR/unchecked_shifts.rs:+0:63: +0:66
-    scope 1 (inlined core::num::::unchecked_shr) { // at $DIR/unchecked_shifts.rs:16:7: 16:23
+    scope 1 (inlined core::num::::unchecked_shr) { // at $DIR/unchecked_shifts.rs:17:7: 17:23
         debug self => _1;                // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
         debug rhs => _2;                 // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
         let mut _3: i16;                 // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
         let mut _4: std::option::Option; // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
         let mut _5: std::result::Result; // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
         scope 2 {
-            scope 3 (inlined Result::::ok) { // at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-                debug self => _5;        // in scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-                let mut _6: isize;       // in scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-                let _7: i16;             // in scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-                scope 4 {
-                    debug x => _7;       // in scope 4 at $SRC_DIR/core/src/result.rs:LL:COL
+            scope 3 (inlined >::try_into) { // at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
+                debug self => _2;        // in scope 3 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+                scope 4 (inlined convert::num:: for i16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+                    debug u => _2;       // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                    let mut _6: bool;    // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                    let mut _7: u32;     // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                    let mut _8: i16;     // in scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
                 }
-                scope 5 {
-                    scope 6 {
-                        debug x => const TryFromIntError(()); // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+            }
+            scope 5 (inlined Result::::ok) { // at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
+                debug self => _5;        // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+                let mut _9: isize;       // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+                let _10: i16;            // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+                scope 6 {
+                    debug x => _10;      // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+                }
+                scope 7 {
+                    scope 8 {
+                        debug x => const TryFromIntError(()); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
                     }
                 }
             }
-            scope 7 (inlined #[track_caller] Option::::unwrap_unchecked) { // at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-                debug self => _4;        // in scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-                let mut _8: &std::option::Option; // in scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-                let mut _9: isize;       // in scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-                scope 8 {
-                    debug val => _3;     // in scope 8 at $SRC_DIR/core/src/option.rs:LL:COL
+            scope 9 (inlined #[track_caller] Option::::unwrap_unchecked) { // at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
+                debug self => _4;        // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+                let mut _11: &std::option::Option; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+                let mut _12: isize;      // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+                scope 10 {
+                    debug val => _3;     // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
                 }
-                scope 9 {
-                    scope 11 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL
-                        scope 12 {
-                            scope 13 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL
+                scope 11 {
+                    scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL
+                        scope 14 {
+                            scope 15 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL
                             }
                         }
                     }
                 }
-                scope 10 (inlined Option::::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL
-                    debug self => _8;    // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL
+                scope 12 (inlined Option::::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL
+                    debug self => _11;   // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL
                 }
             }
         }
@@ -50,51 +59,70 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 {
         StorageLive(_3);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
         StorageLive(_4);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
         StorageLive(_5);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-        _5 = >::try_into(_2) -> bb1; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-                                         // mir::Constant
-                                         // + span: $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-                                         // + literal: Const { ty: fn(u32) -> Result>::Error> {>::try_into}, val: Value() }
+        StorageLive(_6);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageLive(_7);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _7 = const 32767_u32;            // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _6 = Gt(_2, move _7);            // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageDead(_7);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        switchInt(move _6) -> [0: bb4, otherwise: bb3]; // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
     }
 
     bb1: {
-        StorageLive(_7);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-        _6 = discriminant(_5);           // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-        switchInt(move _6) -> [0: bb6, 1: bb4, otherwise: bb5]; // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
+        StorageDead(_10);                // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
+        StorageDead(_5);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
+        StorageLive(_11);                // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
+        _12 = discriminant(_4);          // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+        switchInt(move _12) -> [1: bb9, otherwise: bb7]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
     }
 
     bb2: {
-        StorageDead(_7);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-        StorageDead(_5);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-        StorageLive(_8);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-        _9 = discriminant(_4);           // scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-        switchInt(move _9) -> [1: bb7, otherwise: bb5]; // scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-    }
-
-    bb3: {
         StorageDead(_3);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
         return;                          // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2
     }
 
+    bb3: {
+        _5 = Result::::Err(const TryFromIntError(())); // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+                                         // mir::Constant
+                                         // + span: no-location
+                                         // + literal: Const { ty: TryFromIntError, val: Value() }
+        goto -> bb5;                     // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+    }
+
     bb4: {
-        _4 = Option::::None;        // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        goto -> bb2;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+        StorageLive(_8);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _8 = _2 as i16 (IntToInt);       // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        _5 = Result::::Ok(move _8); // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageDead(_8);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        goto -> bb5;                     // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
     }
 
     bb5: {
-        unreachable;                     // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
+        StorageDead(_6);                 // scope 4 at $SRC_DIR/core/src/convert/num.rs:LL:COL
+        StorageLive(_10);                // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
+        _9 = discriminant(_5);           // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+        switchInt(move _9) -> [0: bb8, 1: bb6, otherwise: bb7]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
     }
 
     bb6: {
-        _7 = move ((_5 as Ok).0: i16);   // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
-        _4 = Option::::Some(move _7); // scope 4 at $SRC_DIR/core/src/result.rs:LL:COL
-        goto -> bb2;                     // scope 3 at $SRC_DIR/core/src/result.rs:LL:COL
+        _4 = Option::::None;        // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+        goto -> bb1;                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
     }
 
     bb7: {
-        _3 = move ((_4 as Some).0: i16); // scope 7 at $SRC_DIR/core/src/option.rs:LL:COL
-        StorageDead(_8);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
+        unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+    }
+
+    bb8: {
+        _10 = move ((_5 as Ok).0: i16);  // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+        _4 = Option::::Some(move _10); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+        goto -> bb1;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
+    }
+
+    bb9: {
+        _3 = move ((_4 as Some).0: i16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL
+        StorageDead(_11);                // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
         StorageDead(_4);                 // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
-        _0 = unchecked_shr::(_1, move _3) -> bb3; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
+        _0 = unchecked_shr::(_1, move _3) -> [return: bb2, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/num/int_macros.rs:LL:COL
                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i16, i16) -> i16 {unchecked_shr::}, val: Value() }
diff --git a/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
index 2f6f5f87efcc..49006e012dde 100644
--- a/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
@@ -14,7 +14,7 @@
   
       bb1: {
 +         Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:12:5 - 13:17; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
-          falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
+          falseUnwind -> [real: bb2, unwind: bb6]; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
       }
   
       bb2: {
diff --git a/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff
index 7031c3f3e699..09fc145e734d 100644
--- a/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff
+++ b/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff
@@ -9,7 +9,7 @@
   
       bb0: {
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46
-          _1 = assert_inhabited::() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46
+          _1 = assert_inhabited::() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46
                                            // mir::Constant
                                            // + span: $DIR/intrinsic_asserts.rs:25:5: 25:44
                                            // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_inhabited::}, val: Value() }
@@ -18,7 +18,7 @@
       bb1: {
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+1:46: +1:47
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47
-          _2 = assert_zero_valid::() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47
+          _2 = assert_zero_valid::() -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47
                                            // mir::Constant
                                            // + span: $DIR/intrinsic_asserts.rs:26:5: 26:45
                                            // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_zero_valid::}, val: Value() }
@@ -27,7 +27,7 @@
       bb2: {
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+2:47: +2:48
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
-          _3 = assert_mem_uninitialized_valid::() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
+          _3 = assert_mem_uninitialized_valid::() -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
                                            // mir::Constant
                                            // + span: $DIR/intrinsic_asserts.rs:27:5: 27:58
                                            // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_mem_uninitialized_valid::}, val: Value() }
diff --git a/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff
index 4caa9971fef8..c52174ef5ea2 100644
--- a/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff
+++ b/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff
@@ -9,8 +9,8 @@
   
       bb0: {
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
--         _1 = assert_inhabited::() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
-+         _1 = assert_inhabited::(); // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
+-         _1 = assert_inhabited::() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
++         _1 = assert_inhabited::() -> unwind unreachable; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
                                            // mir::Constant
                                            // + span: $DIR/intrinsic_asserts.rs:17:5: 17:48
                                            // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_inhabited::}, val: Value() }
@@ -19,8 +19,8 @@
       bb1: {
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+1:50: +1:51
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
--         _2 = assert_zero_valid::<&u8>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
-+         _2 = assert_zero_valid::<&u8>(); // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
+-         _2 = assert_zero_valid::<&u8>() -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
++         _2 = assert_zero_valid::<&u8>() -> unwind unreachable; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
                                            // mir::Constant
                                            // + span: $DIR/intrinsic_asserts.rs:18:5: 18:47
                                            // + user_ty: UserType(0)
@@ -30,8 +30,8 @@
       bb2: {
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+2:49: +2:50
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
--         _3 = assert_mem_uninitialized_valid::<&u8>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
-+         _3 = assert_mem_uninitialized_valid::<&u8>(); // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
+-         _3 = assert_mem_uninitialized_valid::<&u8>() -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
++         _3 = assert_mem_uninitialized_valid::<&u8>() -> unwind unreachable; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
                                            // mir::Constant
                                            // + span: $DIR/intrinsic_asserts.rs:19:5: 19:60
                                            // + user_ty: UserType(1)
diff --git a/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff
index b0bec9573697..d059d47ee586 100644
--- a/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff
+++ b/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff
@@ -9,7 +9,7 @@
   
       bb0: {
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
--         _1 = assert_inhabited::<()>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
+-         _1 = assert_inhabited::<()>() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
 -                                          // mir::Constant
 -                                          // + span: $DIR/intrinsic_asserts.rs:7:5: 7:45
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_inhabited::<()>}, val: Value() }
@@ -19,7 +19,7 @@
       bb1: {
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+1:47: +1:48
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
--         _2 = assert_zero_valid::() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
+-         _2 = assert_zero_valid::() -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
 -                                          // mir::Constant
 -                                          // + span: $DIR/intrinsic_asserts.rs:8:5: 8:46
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_zero_valid::}, val: Value() }
@@ -29,7 +29,7 @@
       bb2: {
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+2:48: +2:49
           nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
--         _3 = assert_mem_uninitialized_valid::() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
+-         _3 = assert_mem_uninitialized_valid::() -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
 -                                          // mir::Constant
 -                                          // + span: $DIR/intrinsic_asserts.rs:9:5: 9:59
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_mem_uninitialized_valid::}, val: Value() }
diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.diff b/tests/mir-opt/issue_101973.inner.ConstProp.diff
index b377a65b9641..d048b9e65130 100644
--- a/tests/mir-opt/issue_101973.inner.ConstProp.diff
+++ b/tests/mir-opt/issue_101973.inner.ConstProp.diff
@@ -16,15 +16,15 @@
       let mut _11: bool;                   // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       let mut _12: u32;                    // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       let mut _13: 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 => _1;                   // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14
-          let mut _14: u32;                // in scope 1 at $DIR/issue_101973.rs:7:12: 7:27
-          let mut _15: u32;                // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20
+      scope 1 (inlined imm8) {             // at $DIR/issue_101973.rs:15:5: 15:17
+          debug x => _1;                   // in scope 1 at $DIR/issue_101973.rs:6:13: 6:14
+          let mut _14: u32;                // in scope 1 at $DIR/issue_101973.rs:8:12: 8:27
+          let mut _15: u32;                // in scope 1 at $DIR/issue_101973.rs:8:12: 8:20
           scope 2 {
-              debug out => _4;             // in scope 2 at $DIR/issue_101973.rs:6:9: 6:16
+              debug out => _4;             // in scope 2 at $DIR/issue_101973.rs:7:9: 7:16
           }
       }
-      scope 3 (inlined core::num::::rotate_right) { // at $DIR/issue_101973.rs:14:18: 14:58
+      scope 3 (inlined core::num::::rotate_right) { // at $DIR/issue_101973.rs:15:18: 15:58
           debug self => _4;                // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
           debug n => _6;                   // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
       }
@@ -33,13 +33,13 @@
           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(_14);                // scope 2 at $DIR/issue_101973.rs:7:12: 7:27
-          StorageLive(_15);                // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
-          _15 = Shr(_1, const 0_i32);      // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
-          _14 = BitAnd(move _15, const 255_u32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:27
-          StorageDead(_15);                // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
-          _4 = BitOr(const 0_u32, move _14); // scope 2 at $DIR/issue_101973.rs:7:5: 7:27
-          StorageDead(_14);                // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
+          StorageLive(_14);                // scope 2 at $DIR/issue_101973.rs:8:12: 8:27
+          StorageLive(_15);                // scope 2 at $DIR/issue_101973.rs:8:12: 8:20
+          _15 = Shr(_1, const 0_i32);      // scope 2 at $DIR/issue_101973.rs:8:12: 8:20
+          _14 = BitAnd(move _15, const 255_u32); // scope 2 at $DIR/issue_101973.rs:8:12: 8:27
+          StorageDead(_15);                // scope 2 at $DIR/issue_101973.rs:8:26: 8:27
+          _4 = BitOr(const 0_u32, move _14); // scope 2 at $DIR/issue_101973.rs:8:5: 8:27
+          StorageDead(_14);                // scope 2 at $DIR/issue_101973.rs:8:26: 8:27
           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
@@ -66,7 +66,7 @@
       bb2: {
           _6 = Shl(move _7, const 1_i32);  // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
           StorageDead(_7);                 // scope 0 at $DIR/issue_101973.rs:+1:56: +1:57
-          _3 = rotate_right::(_4, _6) -> bb3; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
+          _3 = rotate_right::(_4, _6) -> [return: bb3, unwind unreachable]; // 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() }
diff --git a/tests/mir-opt/issue_101973.rs b/tests/mir-opt/issue_101973.rs
index 216659a235ef..da388f14918f 100644
--- a/tests/mir-opt/issue_101973.rs
+++ b/tests/mir-opt/issue_101973.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // compile-flags: -O -C debug-assertions=on
 // This needs inlining followed by ConstProp to reproduce, so we cannot use "unit-test".
 
diff --git a/tests/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir b/tests/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir
index b0d5b291b6cb..ccaa508c13b5 100644
--- a/tests/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir
@@ -19,7 +19,7 @@ fn main() -> () {
     }
 
     bb1: {
-        falseUnwind -> [real: bb2, cleanup: bb5]; // scope 1 at $DIR/issue_38669.rs:+2:5: +7:6
+        falseUnwind -> [real: bb2, unwind: bb5]; // scope 1 at $DIR/issue_38669.rs:+2:5: +7:6
     }
 
     bb2: {
diff --git a/tests/mir-opt/issue_41110.main.ElaborateDrops.diff b/tests/mir-opt/issue_41110.main.ElaborateDrops.diff
index 7ac75b51a370..ac2520249285 100644
--- a/tests/mir-opt/issue_41110.main.ElaborateDrops.diff
+++ b/tests/mir-opt/issue_41110.main.ElaborateDrops.diff
@@ -46,17 +46,17 @@
       }
   
       bb3 (cleanup): {
--         drop(_3) -> bb5;                 // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
+-         drop(_3) -> [return: bb5, unwind terminate]; // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
 +         goto -> bb5;                     // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
       }
   
       bb4 (cleanup): {
--         drop(_4) -> bb5;                 // scope 0 at $DIR/issue_41110.rs:+1:26: +1:27
+-         drop(_4) -> [return: bb5, unwind terminate]; // scope 0 at $DIR/issue_41110.rs:+1:26: +1:27
 +         goto -> bb5;                     // scope 0 at $DIR/issue_41110.rs:+1:26: +1:27
       }
   
       bb5 (cleanup): {
--         drop(_2) -> bb6;                 // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
+-         drop(_2) -> [return: bb6, unwind terminate]; // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
 +         goto -> bb8;                     // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
       }
   
@@ -65,7 +65,7 @@
 +     }
 + 
 +     bb7 (cleanup): {
-+         drop(_2) -> bb6;                 // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
++         drop(_2) -> [return: bb6, unwind terminate]; // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
 +     }
 + 
 +     bb8 (cleanup): {
diff --git a/tests/mir-opt/issue_41110.test.ElaborateDrops.diff b/tests/mir-opt/issue_41110.test.ElaborateDrops.diff
index 3dd1a9bbab58..a4a07ad12434 100644
--- a/tests/mir-opt/issue_41110.test.ElaborateDrops.diff
+++ b/tests/mir-opt/issue_41110.test.ElaborateDrops.diff
@@ -50,7 +50,7 @@
   
       bb3 (cleanup): {
           _2 = move _5;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
-          drop(_5) -> bb8;                 // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
+          drop(_5) -> [return: bb8, unwind terminate]; // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
       }
   
       bb4: {
@@ -72,18 +72,18 @@
       }
   
       bb7 (cleanup): {
--         drop(_4) -> bb8;                 // scope 2 at $DIR/issue_41110.rs:+3:11: +3:12
+-         drop(_4) -> [return: bb8, unwind terminate]; // scope 2 at $DIR/issue_41110.rs:+3:11: +3:12
 +         goto -> bb8;                     // scope 2 at $DIR/issue_41110.rs:+3:11: +3:12
       }
   
       bb8 (cleanup): {
--         drop(_2) -> bb9;                 // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
+-         drop(_2) -> [return: bb9, unwind terminate]; // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
 +         goto -> bb9;                     // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
       }
   
       bb9 (cleanup): {
--         drop(_1) -> bb10;                // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
-+         goto -> bb12;                    // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
+-         drop(_1) -> [return: bb10, unwind terminate]; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
++         goto -> bb13;                    // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
       }
   
       bb10 (cleanup): {
@@ -91,11 +91,15 @@
 +     }
 + 
 +     bb11 (cleanup): {
-+         drop(_1) -> bb10;                // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
++         unreachable;                     // scope 0 at $DIR/issue_41110.rs:+0:1: +5:2
 +     }
 + 
 +     bb12 (cleanup): {
-+         switchInt(_6) -> [0: bb10, otherwise: bb11]; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
++         drop(_1) -> [return: bb10, unwind terminate]; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
++     }
++ 
++     bb13 (cleanup): {
++         switchInt(_6) -> [0: bb10, otherwise: bb12]; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
       }
   }
   
diff --git a/tests/mir-opt/issue_41888.main.ElaborateDrops.diff b/tests/mir-opt/issue_41888.main.ElaborateDrops.diff
index 4e38659a90be..d98f75e7502d 100644
--- a/tests/mir-opt/issue_41888.main.ElaborateDrops.diff
+++ b/tests/mir-opt/issue_41888.main.ElaborateDrops.diff
@@ -58,7 +58,7 @@
   
       bb4 (cleanup): {
           _1 = move _3;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-          drop(_3) -> bb11;                // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
+          drop(_3) -> [return: bb11, unwind terminate]; // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
       }
   
       bb5: {
@@ -89,7 +89,7 @@
       bb9: {
           StorageDead(_2);                 // scope 1 at $DIR/issue_41888.rs:+8:5: +8:6
 -         drop(_1) -> bb10;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-+         goto -> bb18;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         goto -> bb19;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
       }
   
       bb10: {
@@ -101,7 +101,7 @@
       }
   
       bb11 (cleanup): {
--         drop(_1) -> bb12;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+-         drop(_1) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +         goto -> bb12;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
       }
   
@@ -109,39 +109,43 @@
           resume;                          // scope 0 at $DIR/issue_41888.rs:+0:1: +9:2
 +     }
 + 
-+     bb13: {
++     bb13 (cleanup): {
++         unreachable;                     // scope 0 at $DIR/issue_41888.rs:+0:1: +9:2
++     }
++ 
++     bb14: {
 +         _7 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +         goto -> bb10;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
-+     bb14 (cleanup): {
++     bb15 (cleanup): {
 +         goto -> bb12;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
-+     bb15: {
-+         drop(_1) -> [return: bb13, unwind: bb12]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     bb16: {
++         drop(_1) -> [return: bb14, unwind: bb12]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
-+     bb16 (cleanup): {
-+         drop(_1) -> bb12;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-+     }
-+ 
-+     bb17: {
-+         _10 = discriminant(_1);          // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-+         switchInt(move _10) -> [0: bb13, otherwise: bb15]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     bb17 (cleanup): {
++         drop(_1) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
 +     bb18: {
-+         switchInt(_7) -> [0: bb13, otherwise: bb17]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         _10 = discriminant(_1);          // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         switchInt(move _10) -> [0: bb14, otherwise: bb16]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
-+     bb19 (cleanup): {
-+         _11 = discriminant(_1);          // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-+         switchInt(move _11) -> [0: bb14, otherwise: bb16]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     bb19: {
++         switchInt(_7) -> [0: bb14, otherwise: bb18]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
 +     bb20 (cleanup): {
-+         switchInt(_7) -> [0: bb12, otherwise: bb19]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         _11 = discriminant(_1);          // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         switchInt(move _11) -> [0: bb15, otherwise: bb17]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     }
++ 
++     bb21 (cleanup): {
++         switchInt(_7) -> [0: bb12, otherwise: bb20]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
       }
   }
   
diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.mir
index 22b34975d66a..8ed9101500e4 100644
--- a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.mir
+++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.mir
@@ -109,11 +109,11 @@ fn test() -> Option> {
     }
 
     bb11 (cleanup): {
-        drop(_1) -> bb13;                // scope 0 at $DIR/issue_62289.rs:+4:5: +4:6
+        drop(_1) -> [return: bb13, unwind terminate]; // scope 0 at $DIR/issue_62289.rs:+4:5: +4:6
     }
 
     bb12 (cleanup): {
-        drop(_5) -> bb13;                // scope 0 at $DIR/issue_62289.rs:+3:23: +3:24
+        drop(_5) -> [return: bb13, unwind terminate]; // scope 0 at $DIR/issue_62289.rs:+3:23: +3:24
     }
 
     bb13 (cleanup): {
diff --git a/tests/mir-opt/issue_72181_1.main.built.after.mir b/tests/mir-opt/issue_72181_1.main.built.after.mir
index 2172f3aa9e28..e1d896cbcfbe 100644
--- a/tests/mir-opt/issue_72181_1.main.built.after.mir
+++ b/tests/mir-opt/issue_72181_1.main.built.after.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(Void) }, span: $DIR/issue_72181_1.rs:16:12: 16:16, inferred_ty: Void
-| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(Void) }, span: $DIR/issue_72181_1.rs:16:12: 16:16, inferred_ty: Void
+| 0: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [] }, span: $DIR/issue_72181_1.rs:16:12: 16:16, inferred_ty: Void
+| 1: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [] }, span: $DIR/issue_72181_1.rs:16:12: 16:16, inferred_ty: Void
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/issue_72181_1.rs:+0:11: +0:11
diff --git a/tests/mir-opt/issue_76432.rs b/tests/mir-opt/issue_76432.rs
index fbbfd4ceb112..76bb11aae3d7 100644
--- a/tests/mir-opt/issue_76432.rs
+++ b/tests/mir-opt/issue_76432.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // compile-flags: -Zmir-enable-passes=-NormalizeArrayLen
 // Check that we do not insert StorageDead at each target if StorageDead was never seen
 
diff --git a/tests/mir-opt/issue_91633.bar.built.after.mir b/tests/mir-opt/issue_91633.bar.built.after.mir
index 760e5a8f90a8..88a383015b09 100644
--- a/tests/mir-opt/issue_91633.bar.built.after.mir
+++ b/tests/mir-opt/issue_91633.bar.built.after.mir
@@ -31,7 +31,7 @@ fn bar(_1: Box<[T]>) -> () {
     }
 
     bb3 (cleanup): {
-        drop(_1) -> bb4;                 // scope 0 at $DIR/issue_91633.rs:+5:2: +5:3
+        drop(_1) -> [return: bb4, unwind terminate]; // scope 0 at $DIR/issue_91633.rs:+5:2: +5:3
     }
 
     bb4 (cleanup): {
diff --git a/tests/mir-opt/issue_91633.foo.built.after.mir b/tests/mir-opt/issue_91633.foo.built.after.mir
index 4e3dd365e924..569135803ea3 100644
--- a/tests/mir-opt/issue_91633.foo.built.after.mir
+++ b/tests/mir-opt/issue_91633.foo.built.after.mir
@@ -48,7 +48,7 @@ fn foo(_1: Box<[T]>) -> T {
     }
 
     bb5 (cleanup): {
-        drop(_1) -> bb6;                 // scope 0 at $DIR/issue_91633.rs:+4:2: +4:3
+        drop(_1) -> [return: bb6, unwind terminate]; // scope 0 at $DIR/issue_91633.rs:+4:2: +4:3
     }
 
     bb6 (cleanup): {
diff --git a/tests/mir-opt/issue_99325.main.built.after.mir b/tests/mir-opt/issue_99325.main.built.after.mir
index 3e035c18db86..2324f53566c1 100644
--- a/tests/mir-opt/issue_99325.main.built.after.mir
+++ b/tests/mir-opt/issue_99325.main.built.after.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [], value: TypeOf(DefId(0:3 ~ issue_99325[8f58]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Value(Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)])) }], user_self_ty: None }) }, span: $DIR/issue_99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
-| 1: user_ty: Canonical { max_universe: U0, variables: [], value: TypeOf(DefId(0:3 ~ issue_99325[8f58]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Unevaluated(UnevaluatedConst { def: WithOptConstParam { did: DefId(0:8 ~ issue_99325[8f58]::main::{constant#1}), const_param_did: Some(DefId(0:4 ~ issue_99325[8f58]::function_with_bytes::BYTES)) }, substs: [] }) }], user_self_ty: None }) }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Value(Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)])) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Unevaluated(UnevaluatedConst { def: WithOptConstParam { did: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), const_param_did: Some(DefId(0:4 ~ issue_99325[22bb]::function_with_bytes::BYTES)) }, substs: [] }) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/issue_99325.rs:+0:15: +0:15
diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
index 6e28fb61b6bd..42b605326908 100644
--- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
+++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
@@ -5,7 +5,7 @@ fn num_to_digit(_1: char) -> u32 {
     let mut _0: u32;                     // return place in scope 0 at $DIR/issue_59352.rs:+0:35: +0:38
     let mut _2: std::option::Option; // in scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
     let mut _3: u32;                     // in scope 0 at $DIR/issue_59352.rs:+2:12: +2:23
-    scope 1 (inlined char::methods::::is_digit) { // at $DIR/issue_59352.rs:14:12: 14:23
+    scope 1 (inlined char::methods::::is_digit) { // at $DIR/issue_59352.rs:15:12: 15:23
         debug self => _1;                // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
         debug radix => _3;               // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
         let mut _4: &std::option::Option; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
@@ -15,7 +15,7 @@ fn num_to_digit(_1: char) -> u32 {
             let mut _6: isize;           // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL
         }
     }
-    scope 3 (inlined #[track_caller] Option::::unwrap) { // at $DIR/issue_59352.rs:14:42: 14:50
+    scope 3 (inlined #[track_caller] Option::::unwrap) { // at $DIR/issue_59352.rs:15:42: 15:50
         debug self => _2;                // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
         let mut _7: isize;               // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
         let mut _8: !;                   // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
@@ -38,7 +38,7 @@ fn num_to_digit(_1: char) -> u32 {
         StorageLive(_2);                 // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
         _2 = char::methods::::to_digit(_1, const 8_u32) -> bb2; // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
                                          // mir::Constant
-                                         // + span: $DIR/issue_59352.rs:14:30: 14:38
+                                         // + span: $DIR/issue_59352.rs:15:30: 15:38
                                          // + literal: Const { ty: fn(char, u32) -> Option {char::methods::::to_digit}, val: Value() }
     }
 
diff --git a/tests/mir-opt/issues/issue_59352.rs b/tests/mir-opt/issues/issue_59352.rs
index 1e0045555ab8..92011bd65887 100644
--- a/tests/mir-opt/issues/issue_59352.rs
+++ b/tests/mir-opt/issues/issue_59352.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // This test is a mirror of codegen/issue-59352.rs.
 // The LLVM inliner doesn't inline `char::method::is_digit()` and so it doesn't recognize this case
 // as effectively `if x.is_some() { x.unwrap() } else { 0 }`.
diff --git a/tests/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir b/tests/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir
index 4ee2dae49b3f..43d00b29e74e 100644
--- a/tests/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir
+++ b/tests/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir
@@ -35,7 +35,7 @@ fn main() -> () {
     }
 
     bb3: {
-        falseUnwind -> [real: bb4, cleanup: bb5]; // scope 0 at $DIR/loop_test.rs:+7:5: +10:6
+        falseUnwind -> [real: bb4, unwind: bb5]; // scope 0 at $DIR/loop_test.rs:+7:5: +10:6
     }
 
     bb4: {
diff --git a/tests/mir-opt/lower_array_len.rs b/tests/mir-opt/lower_array_len.rs
index 972d46cb8e2b..e1bb51f2d1d9 100644
--- a/tests/mir-opt/lower_array_len.rs
+++ b/tests/mir-opt/lower_array_len.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: NormalizeArrayLen
 // compile-flags: -Zmir-enable-passes=+LowerSliceLenCalls
 
diff --git a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff
index 3389db733b99..dd742d87a295 100644
--- a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff
@@ -5,7 +5,7 @@
       let mut _0: usize;                   // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:25: +0:30
   
       bb0: {
--         _0 = std::intrinsics::min_align_of::() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42
+-         _0 = std::intrinsics::min_align_of::() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:21:5: 21:40
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::min_align_of::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff
index 5c5a9e90a9da..935eccfc6f4f 100644
--- a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff
@@ -9,7 +9,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
--         _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+-         _1 = std::intrinsics::assume(const true) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:105:9: 105:32
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
index 87960521bb45..1f03b7b0baf4 100644
--- a/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
@@ -29,7 +29,7 @@
           StorageLive(_4);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44
           _4 = &_1;                        // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44
           _3 = &(*_4);                     // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44
--         _2 = discriminant_value::(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
+-         _2 = discriminant_value::(move _3) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:82:5: 82:41
 -                                          // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a T) -> ::Discriminant {discriminant_value::}, val: Value() }
@@ -50,7 +50,7 @@
                                            // + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) }
           _7 = &(*_19);                    // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
           _6 = &(*_7);                     // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
--         _5 = discriminant_value::(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
+-         _5 = discriminant_value::(move _6) -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:83:5: 83:41
 -                                          // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a i32) -> ::Discriminant {discriminant_value::}, val: Value() }
@@ -71,7 +71,7 @@
                                            // + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) }
           _11 = &(*_18);                   // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
           _10 = &(*_11);                   // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
--         _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
+-         _9 = discriminant_value::<()>(move _10) -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:84:5: 84:41
 -                                          // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value() }
@@ -92,7 +92,7 @@
                                            // + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) }
           _15 = &(*_17);                   // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
           _14 = &(*_15);                   // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
--         _13 = discriminant_value::(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
+-         _13 = discriminant_value::(move _14) -> [return: bb4, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:85:5: 85:41
 -                                          // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a E) -> ::Discriminant {discriminant_value::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
index 15cce7f4a2c0..b0c32e4b21a7 100644
--- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
@@ -47,7 +47,7 @@
           _9 = _10;                        // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
           _8 = move _9 as *mut i32 (PtrToPtr); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:91
           StorageDead(_9);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91
--         _3 = copy_nonoverlapping::(move _4, move _8, const 0_usize) -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+-         _3 = copy_nonoverlapping::(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable]; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:98:9: 98:28
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff
index 4cbbc02c9433..bfb000ccdb5c 100644
--- a/tests/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff
@@ -9,7 +9,7 @@
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31
           _2 = move _1;                    // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31
--         _0 = std::intrinsics::forget::(move _2) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32
+-         _0 = std::intrinsics::forget::(move _2) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:26:5: 26:29
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff
index d8cd5f59a353..64d82907c7e3 100644
--- a/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff
@@ -17,7 +17,7 @@
                                            // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}, val: Value() }
           StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14
           _2 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14
--         _0 = move _2() -> bb1;           // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:16
+-         _0 = move _2() -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:16
 +         _0 = SizeOf(T);                  // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:16
 +         goto -> bb1;                     // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:16
       }
diff --git a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff
index c563703b250d..93863fca344a 100644
--- a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff
@@ -22,7 +22,7 @@
           StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:13: +2:15
           StorageLive(_4);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56
           _4 = &raw const (*_1);           // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56
--         _3 = option_payload_ptr::(move _4) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
+-         _3 = option_payload_ptr::(move _4) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:132:18: 132:54
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option) -> *const usize {option_payload_ptr::}, val: Value() }
@@ -35,7 +35,7 @@
           StorageLive(_5);                 // scope 2 at $DIR/lower_intrinsics.rs:+3:13: +3:15
           StorageLive(_6);                 // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56
           _6 = &raw const (*_2);           // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56
--         _5 = option_payload_ptr::(move _6) -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
+-         _5 = option_payload_ptr::(move _6) -> [return: bb2, unwind unreachable]; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:133:18: 133:54
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option) -> *const String {option_payload_ptr::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff
index f2f676843b2c..f816678b4b3a 100644
--- a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff
@@ -11,7 +11,7 @@
       bb0: {
           StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
           _2 = &raw const (*_1);           // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
--         _0 = read_via_copy::(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
+-         _0 = read_via_copy::(move _2) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:118:14: 118:45
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32) -> i32 {read_via_copy::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff
index 3ad21283fa47..f34164189220 100644
--- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff
@@ -11,7 +11,7 @@
       bb0: {
           StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
           _2 = &raw const (*_1);           // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
--         _0 = read_via_copy::(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
+-         _0 = read_via_copy::(move _2) -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:123:14: 123:45
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Never) -> Never {read_via_copy::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff
index cf0ab73a5d4b..27e8accea8be 100644
--- a/tests/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff
@@ -5,7 +5,7 @@
       let mut _0: usize;                   // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:24: +0:29
   
       bb0: {
--         _0 = std::intrinsics::size_of::() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37
+-         _0 = std::intrinsics::size_of::() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:16:5: 16:35
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff
index 814368ec021e..1b3b7685185b 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff
@@ -11,7 +11,7 @@
       bb0: {
           StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
           _2 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
--         _0 = transmute::(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
+-         _0 = transmute::(move _2) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:43:14: 43:33
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(std::cmp::Ordering) -> i8 {transmute::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff
index 5440c7a4c8ec..c6a7d2287e75 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff
@@ -11,7 +11,7 @@
       bb0: {
           StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
           _2 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
--         _0 = transmute::<&T, *const T>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
+-         _0 = transmute::<&T, *const T>(move _2) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:53:14: 53:33
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&T) -> *const T {transmute::<&T, *const T>}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff
index 43ddccc1ef7d..8735a7500603 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff
@@ -13,7 +13,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
           StorageLive(_2);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
--         _2 = transmute::>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
+-         _2 = transmute::>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:70:25: 70:44
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> Box {transmute::>}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff
index bf529a9ca678..a772132770c3 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff
@@ -13,7 +13,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
           StorageLive(_2);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
--         _2 = transmute::(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
+-         _2 = transmute::(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:64:25: 64:44
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &mut Never {transmute::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff
index 4940a99021f4..c4d53d4e8c74 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff
@@ -13,7 +13,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
           StorageLive(_2);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
--         _2 = transmute::(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48
+-         _2 = transmute::(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:58:21: 58:40
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &Never {transmute::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff
index f3a12b9ba5f2..f0b76127dd5e 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff
@@ -11,7 +11,7 @@
       bb0: {
           StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48
           _2 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48
--         _0 = transmute::<(), Never>(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49
+-         _0 = transmute::<(), Never>(move _2) -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:48:14: 48:46
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Never {transmute::<(), Never>}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff
index 6f17d44516de..c0cc698c4818 100644
--- a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff
@@ -12,7 +12,7 @@
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:47
           StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
--         _3 = std::intrinsics::unreachable(); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
+-         _3 = std::intrinsics::unreachable() -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:31:14: 31:43
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff
index 3b9a41249a4b..fb12d3dfa6e9 100644
--- a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff
@@ -30,7 +30,7 @@
           _4 = _1;                         // scope 0 at $DIR/lower_intrinsics.rs:+1:50: +1:51
           StorageLive(_5);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:53: +1:54
           _5 = _2;                         // scope 0 at $DIR/lower_intrinsics.rs:+1:53: +1:54
--         _3 = add_with_overflow::(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55
+-         _3 = add_with_overflow::(move _4, move _5) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:111:14: 111:49
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {add_with_overflow::}, val: Value() }
@@ -46,7 +46,7 @@
           _7 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:+2:50: +2:51
           StorageLive(_8);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:53: +2:54
           _8 = _2;                         // scope 1 at $DIR/lower_intrinsics.rs:+2:53: +2:54
--         _6 = sub_with_overflow::(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55
+-         _6 = sub_with_overflow::(move _7, move _8) -> [return: bb2, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:112:14: 112:49
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {sub_with_overflow::}, val: Value() }
@@ -62,7 +62,7 @@
           _10 = _1;                        // scope 2 at $DIR/lower_intrinsics.rs:+3:50: +3:51
           StorageLive(_11);                // scope 2 at $DIR/lower_intrinsics.rs:+3:53: +3:54
           _11 = _2;                        // scope 2 at $DIR/lower_intrinsics.rs:+3:53: +3:54
--         _9 = mul_with_overflow::(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55
+-         _9 = mul_with_overflow::(move _10, move _11) -> [return: bb3, unwind unreachable]; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:113:14: 113:49
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {mul_with_overflow::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
index 22ef75fd8046..0bfb34acac2d 100644
--- a/tests/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
+++ b/tests/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
@@ -30,7 +30,7 @@
           _4 = _1;                         // scope 0 at $DIR/lower_intrinsics.rs:+1:45: +1:46
           StorageLive(_5);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:48: +1:49
           _5 = _2;                         // scope 0 at $DIR/lower_intrinsics.rs:+1:48: +1:49
--         _3 = wrapping_add::(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50
+-         _3 = wrapping_add::(move _4, move _5) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:9:14: 9:44
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_add::}, val: Value() }
@@ -46,7 +46,7 @@
           _7 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:+2:45: +2:46
           StorageLive(_8);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:48: +2:49
           _8 = _2;                         // scope 1 at $DIR/lower_intrinsics.rs:+2:48: +2:49
--         _6 = wrapping_sub::(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50
+-         _6 = wrapping_sub::(move _7, move _8) -> [return: bb2, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:10:14: 10:44
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_sub::}, val: Value() }
@@ -62,7 +62,7 @@
           _10 = _1;                        // scope 2 at $DIR/lower_intrinsics.rs:+3:45: +3:46
           StorageLive(_11);                // scope 2 at $DIR/lower_intrinsics.rs:+3:48: +3:49
           _11 = _2;                        // scope 2 at $DIR/lower_intrinsics.rs:+3:48: +3:49
--         _9 = wrapping_mul::(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50
+-         _9 = wrapping_mul::(move _10, move _11) -> [return: bb3, unwind unreachable]; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:11:14: 11:44
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_mul::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir b/tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir
index adfc6b2731c1..4f5df1331812 100644
--- a/tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir
+++ b/tests/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir
@@ -12,7 +12,7 @@ fn f_u64() -> () {
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21
-        _2 = f_non_zst::(const 0_u64) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21
+        _2 = f_non_zst::(const 0_u64) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21
                                          // mir::Constant
                                          // + span: $DIR/lower_intrinsics_e2e.rs:23:9: 23:18
                                          // + literal: Const { ty: fn(u64) {f_non_zst::}, val: Value() }
diff --git a/tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir b/tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir
index 302ca09aac4b..8654e80cd7c8 100644
--- a/tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir
+++ b/tests/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir
@@ -10,7 +10,7 @@ fn f_unit() -> () {
     }
 
     bb0: {
-        _1 = f_zst::<()>(const ()) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
+        _1 = f_zst::<()>(const ()) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
                                          // mir::Constant
                                          // + span: $DIR/lower_intrinsics_e2e.rs:21:9: 21:14
                                          // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value() }
diff --git a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff
index 2b0370cf3580..67918e62b9c2 100644
--- a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff
+++ b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff
@@ -22,7 +22,7 @@
           _6 = &(*_2);                     // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27
 -         _5 = core::slice::::len(move _6) -> bb1; // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_slice_len.rs:5:22: 5:25
+-                                          // + span: $DIR/lower_slice_len.rs:6:22: 6:25
 -                                          // + literal: Const { ty: for<'a> fn(&'a [u8]) -> usize {core::slice::::len}, val: Value() }
 +         _5 = Len((*_6));                 // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27
 +         goto -> bb1;                     // scope 0 at $DIR/lower_slice_len.rs:+1:16: +1:27
diff --git a/tests/mir-opt/lower_slice_len.rs b/tests/mir-opt/lower_slice_len.rs
index 12955aed1fbb..9c39c29fc4e4 100644
--- a/tests/mir-opt/lower_slice_len.rs
+++ b/tests/mir-opt/lower_slice_len.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: LowerSliceLenCalls
 
 // EMIT_MIR lower_slice_len.bound.LowerSliceLenCalls.diff
diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff
index 84e4d35f9081..3081e78f26db 100644
--- a/tests/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff
+++ b/tests/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff
@@ -243,7 +243,7 @@
       }
   
 -     bb25 (cleanup): {
--         drop(_2) -> bb26;                // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
+-         drop(_2) -> [return: bb26, unwind terminate]; // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
 +     bb22 (cleanup): {
 +         goto -> bb27;                    // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
       }
diff --git a/tests/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/tests/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir
index 0cb34a2f2747..950f8758e31c 100644
--- a/tests/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir
+++ b/tests/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir
@@ -40,7 +40,7 @@ fn main() -> () {
     }
 
     bb3 (cleanup): {
-        drop(_2) -> bb4;                 // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:34: +1:35
+        drop(_2) -> [return: bb4, unwind terminate]; // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:34: +1:35
     }
 
     bb4 (cleanup): {
diff --git a/tests/mir-opt/nrvo_simple.rs b/tests/mir-opt/nrvo_simple.rs
index 5786ae621270..525dfe4262a4 100644
--- a/tests/mir-opt/nrvo_simple.rs
+++ b/tests/mir-opt/nrvo_simple.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: RenameReturnPlace
 
 // EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff
diff --git a/tests/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir b/tests/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
index 56cb9166c374..81b96e3b6315 100644
--- a/tests/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
+++ b/tests/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
@@ -33,7 +33,7 @@ fn main() -> () {
 
     bb1 (cleanup): {
         (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
-        drop(_1) -> bb3;                 // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:1: +3:2
+        drop(_1) -> [return: bb3, unwind terminate]; // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:1: +3:2
     }
 
     bb2: {
diff --git a/tests/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/tests/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
index a8dd91efc379..0e8309532c2f 100644
--- a/tests/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
+++ b/tests/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
@@ -34,7 +34,7 @@
           _3 = std::ops::Range:: { start: const 0_i32, end: const 10_i32 }; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           _2 =  as IntoIterator>::into_iter(move _3) -> bb1; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
                                            // mir::Constant
-                                           // + span: $DIR/remove_storage_markers.rs:10:14: 10:19
+                                           // + span: $DIR/remove_storage_markers.rs:11:14: 11:19
                                            // + literal: Const { ty: fn(std::ops::Range) ->  as IntoIterator>::IntoIter { as IntoIterator>::into_iter}, val: Value() }
       }
   
@@ -54,7 +54,7 @@
           _8 = &mut (*_9);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           _7 =  as Iterator>::next(move _8) -> bb3; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
                                            // mir::Constant
-                                           // + span: $DIR/remove_storage_markers.rs:10:14: 10:19
+                                           // + span: $DIR/remove_storage_markers.rs:11:14: 11:19
                                            // + literal: Const { ty: for<'a> fn(&'a mut std::ops::Range) -> Option< as Iterator>::Item> { as Iterator>::next}, val: Value() }
       }
   
diff --git a/tests/mir-opt/remove_storage_markers.rs b/tests/mir-opt/remove_storage_markers.rs
index f00b826911c6..480db8ac155b 100644
--- a/tests/mir-opt/remove_storage_markers.rs
+++ b/tests/mir-opt/remove_storage_markers.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: RemoveStorageMarkers
 
 // Checks that storage markers are removed at opt-level=0.
diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
index d7b6d64b6b7b..4eef028e1ccb 100644
--- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
+++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
@@ -108,7 +108,7 @@ fn main() -> () {
         StorageLive(_14);                // scope 1 at $DIR/retag.rs:+11:31: +14:6
         _14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:+11:31: +14:6
                                          // closure
-                                         // + def_id: DefId(0:14 ~ retag[4622]::main::{closure#0})
+                                         // + def_id: DefId(0:14 ~ retag[7654]::main::{closure#0})
                                          // + substs: [
                                          //     i8,
                                          //     for<'a> extern "rust-call" fn((&'a i32,)) -> &'a i32,
@@ -186,11 +186,11 @@ fn main() -> () {
     }
 
     bb7 (cleanup): {
-        drop(_21) -> bb9;                // scope 7 at $DIR/retag.rs:+18:24: +18:25
+        drop(_21) -> [return: bb9, unwind terminate]; // scope 7 at $DIR/retag.rs:+18:24: +18:25
     }
 
     bb8 (cleanup): {
-        drop(_5) -> bb9;                 // scope 1 at $DIR/retag.rs:+3:36: +3:37
+        drop(_5) -> [return: bb9, unwind terminate]; // scope 1 at $DIR/retag.rs:+3:36: +3:37
     }
 
     bb9 (cleanup): {
diff --git a/tests/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff b/tests/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
index 1e66b1f703e3..c61107d25e00 100644
--- a/tests/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
+++ b/tests/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
@@ -12,8 +12,8 @@
       }
   
       bb1: {
--         falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/simplify_cfg.rs:+1:5: +5:6
-+         falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at $DIR/simplify_cfg.rs:+1:5: +5:6
+-         falseUnwind -> [real: bb2, unwind: bb11]; // scope 0 at $DIR/simplify_cfg.rs:+1:5: +5:6
++         falseUnwind -> [real: bb2, unwind: bb6]; // scope 0 at $DIR/simplify_cfg.rs:+1:5: +5:6
       }
   
       bb2: {
diff --git a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
index ac79e7270134..b473d0fdecd0 100644
--- a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
+++ b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
@@ -16,7 +16,7 @@
       bb1: {
           _2 = noop() -> bb2;              // scope 0 at $DIR/simplify_if.rs:+2:9: +2:15
                                            // mir::Constant
-                                           // + span: $DIR/simplify_if.rs:7:9: 7:13
+                                           // + span: $DIR/simplify_if.rs:8:9: 8:13
                                            // + literal: Const { ty: fn() {noop}, val: Value() }
       }
   
diff --git a/tests/mir-opt/simplify_if.rs b/tests/mir-opt/simplify_if.rs
index 2d093d9266bb..b86f80a8038b 100644
--- a/tests/mir-opt/simplify_if.rs
+++ b/tests/mir-opt/simplify_if.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 #[inline(never)]
 fn noop() {}
 
diff --git a/tests/mir-opt/simplify_locals_fixedpoint.rs b/tests/mir-opt/simplify_locals_fixedpoint.rs
index 1fdba6e99e3e..7c41e8b7c20e 100644
--- a/tests/mir-opt/simplify_locals_fixedpoint.rs
+++ b/tests/mir-opt/simplify_locals_fixedpoint.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // compile-flags: -Zmir-opt-level=1
 
 fn foo() {
diff --git a/tests/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.diff
index 0f8866f9c2f4..ae2c774f29dc 100644
--- a/tests/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.diff
+++ b/tests/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.diff
@@ -56,7 +56,7 @@
 +         StorageDead(_3);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
 +         _1 = use_zst(move _2) -> bb1;    // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
                                            // mir::Constant
-                                           // + span: $DIR/simplify_locals_removes_unused_consts.rs:15:5: 15:12
+                                           // + span: $DIR/simplify_locals_removes_unused_consts.rs:16:5: 16:12
                                            // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value() }
       }
   
@@ -84,7 +84,7 @@
 +         StorageDead(_7);                 // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:33: +4:34
 +         _5 = use_u8(move _6) -> bb2;     // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
                                            // mir::Constant
-                                           // + span: $DIR/simplify_locals_removes_unused_consts.rs:17:5: 17:11
+                                           // + span: $DIR/simplify_locals_removes_unused_consts.rs:18:5: 18:11
                                            // + literal: Const { ty: fn(u8) {use_u8}, val: Value() }
       }
   
diff --git a/tests/mir-opt/simplify_locals_removes_unused_consts.rs b/tests/mir-opt/simplify_locals_removes_unused_consts.rs
index 7a03a2837ae7..983d8004e2ed 100644
--- a/tests/mir-opt/simplify_locals_removes_unused_consts.rs
+++ b/tests/mir-opt/simplify_locals_removes_unused_consts.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // unit-test: SimplifyLocals-before-const-prop
 // compile-flags: -C overflow-checks=no
 
diff --git a/tests/mir-opt/simplify_match.main.ConstProp.diff b/tests/mir-opt/simplify_match.main.ConstProp.diff
index b700adfb105b..d2b9ac3cc0b9 100644
--- a/tests/mir-opt/simplify_match.main.ConstProp.diff
+++ b/tests/mir-opt/simplify_match.main.ConstProp.diff
@@ -22,7 +22,7 @@
       bb2: {
           _0 = noop() -> bb3;              // scope 0 at $DIR/simplify_match.rs:+2:17: +2:23
                                            // mir::Constant
-                                           // + span: $DIR/simplify_match.rs:7:17: 7:21
+                                           // + span: $DIR/simplify_match.rs:8:17: 8:21
                                            // + literal: Const { ty: fn() {noop}, val: Value() }
       }
   
diff --git a/tests/mir-opt/simplify_match.rs b/tests/mir-opt/simplify_match.rs
index 216203f9ff08..6a2a6f217196 100644
--- a/tests/mir-opt/simplify_match.rs
+++ b/tests/mir-opt/simplify_match.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 #[inline(never)]
 fn noop() {}
 
diff --git a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
index 3884d29db417..11115c96e23e 100644
--- a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
+++ b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
@@ -24,7 +24,7 @@ fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
     bb3 (cleanup): {
         _4 = &raw mut (*_1)[_3];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
         _3 = Add(move _3, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_4)) -> bb4;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        drop((*_4)) -> [return: bb4, unwind terminate]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 
     bb4 (cleanup): {
diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
index f6f2344e82fa..579587a430b2 100644
--- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
+++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
@@ -58,7 +58,7 @@
           StorageLive(_2);                 // scope 0 at $DIR/lifetimes.rs:+2:12: +2:31
           StorageLive(_3);                 // scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
           StorageLive(_4);                 // scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
-          _4 = Box::::new(const 5_u32) -> bb1; // scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+          _4 = Box::::new(const 5_u32) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
                                            // mir::Constant
                                            // + span: $DIR/lifetimes.rs:19:15: 19:23
                                            // + user_ty: UserType(1)
@@ -113,7 +113,7 @@
           StorageLive(_22);                // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23
           _22 = &_8;                       // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23
           _21 = &(*_22);                   // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23
-          _20 = core::fmt::ArgumentV1::<'_>::new_display::>(move _21) -> bb3; // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23
+          _20 = core::fmt::ArgumentV1::<'_>::new_display::>(move _21) -> [return: bb3, unwind unreachable]; // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23
                                            // mir::Constant
                                            // + span: $DIR/lifetimes.rs:27:20: 27:23
                                            // + user_ty: UserType(4)
@@ -127,7 +127,7 @@
           StorageLive(_25);                // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27
           _25 = &_6;                       // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27
           _24 = &(*_25);                   // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27
-          _23 = core::fmt::ArgumentV1::<'_>::new_display::(move _24) -> bb4; // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27
+          _23 = core::fmt::ArgumentV1::<'_>::new_display::(move _24) -> [return: bb4, unwind unreachable]; // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27
                                            // mir::Constant
                                            // + span: $DIR/lifetimes.rs:27:24: 27:27
                                            // + user_ty: UserType(5)
@@ -143,7 +143,7 @@
           _17 = &(*_18);                   // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
           _16 = move _17 as &[core::fmt::ArgumentV1<'_>] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
           StorageDead(_17);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _11 = Arguments::<'_>::new_v1(move _12, move _16) -> bb5; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _11 = Arguments::<'_>::new_v1(move _12, move _16) -> [return: bb5, unwind unreachable]; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/std/src/macros.rs:LL:COL
                                            // + user_ty: UserType(3)
@@ -153,7 +153,7 @@
       bb5: {
           StorageDead(_16);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
           StorageDead(_12);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _10 = _eprint(move _11) -> bb6;  // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _10 = _eprint(move _11) -> [return: bb6, unwind unreachable]; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/std/src/macros.rs:LL:COL
                                            // + literal: Const { ty: for<'a> fn(Arguments<'a>) {_eprint}, val: Value() }
@@ -170,7 +170,7 @@
           _9 = const ();                   // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
           StorageDead(_9);                 // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
           _0 = const ();                   // scope 4 at $DIR/lifetimes.rs:+9:22: +11:6
-          drop(_8) -> bb8;                 // scope 3 at $DIR/lifetimes.rs:+11:5: +11:6
+          drop(_8) -> [return: bb8, unwind unreachable]; // scope 3 at $DIR/lifetimes.rs:+11:5: +11:6
       }
   
       bb7: {
@@ -204,11 +204,11 @@
       }
   
       bb12: {
-          drop(((_5 as Ok).0: std::boxed::Box)) -> bb10; // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+          drop(((_5 as Ok).0: std::boxed::Box)) -> [return: bb10, unwind unreachable]; // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
       }
   
       bb13: {
-          drop(_5) -> bb10;                // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+          drop(_5) -> [return: bb10, unwind unreachable]; // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
       }
   }
   
diff --git a/tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff
index b6439c00a005..d378c260a004 100644
--- a/tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff
+++ b/tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff
@@ -23,11 +23,11 @@
           StorageDead(_4);                 // scope 0 at $DIR/structs.rs:+1:29: +1:30
           StorageDead(_3);                 // scope 0 at $DIR/structs.rs:+1:29: +1:30
           _1 = move (_2.1: Tag);           // scope 0 at $DIR/structs.rs:+1:5: +1:32
-          drop(_1) -> bb1;                 // scope 0 at $DIR/structs.rs:+1:32: +1:33
+          drop(_1) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/structs.rs:+1:32: +1:33
       }
   
       bb1: {
-          drop((_2.0: Tag)) -> bb3;        // scope 0 at $DIR/structs.rs:+1:32: +1:33
+          drop((_2.0: Tag)) -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/structs.rs:+1:32: +1:33
       }
   
       bb2: {
@@ -38,7 +38,7 @@
       }
   
       bb3: {
-          drop((_2.2: Tag)) -> bb2;        // scope 0 at $DIR/structs.rs:+1:32: +1:33
+          drop((_2.2: Tag)) -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/structs.rs:+1:32: +1:33
       }
   }
   
diff --git a/tests/mir-opt/sroa/structs.escaping.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.escaping.ScalarReplacementOfAggregates.diff
index d45823d4bac5..3074fcbdf531 100644
--- a/tests/mir-opt/sroa/structs.escaping.ScalarReplacementOfAggregates.diff
+++ b/tests/mir-opt/sroa/structs.escaping.ScalarReplacementOfAggregates.diff
@@ -15,7 +15,7 @@
           StorageLive(_3);                 // scope 0 at $DIR/structs.rs:+1:7: +1:41
           StorageLive(_4);                 // scope 0 at $DIR/structs.rs:+1:8: +1:39
           StorageLive(_5);                 // scope 0 at $DIR/structs.rs:+1:34: +1:37
-          _5 = g() -> bb1;                 // scope 0 at $DIR/structs.rs:+1:34: +1:37
+          _5 = g() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/structs.rs:+1:34: +1:37
                                            // mir::Constant
                                            // + span: $DIR/structs.rs:78:34: 78:35
                                            // + literal: Const { ty: fn() -> u32 {g}, val: Value() }
@@ -26,7 +26,7 @@
           StorageDead(_5);                 // scope 0 at $DIR/structs.rs:+1:38: +1:39
           _3 = &(_4.0: u32);               // scope 0 at $DIR/structs.rs:+1:7: +1:41
           _2 = &raw const (*_3);           // scope 0 at $DIR/structs.rs:+1:7: +1:41
-          _1 = f(move _2) -> bb2;          // scope 0 at $DIR/structs.rs:+1:5: +1:42
+          _1 = f(move _2) -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/structs.rs:+1:5: +1:42
                                            // mir::Constant
                                            // + span: $DIR/structs.rs:78:5: 78:6
                                            // + literal: Const { ty: fn(*const u32) {f}, val: Value() }
diff --git a/tests/mir-opt/unreachable.main.UnreachablePropagation.diff b/tests/mir-opt/unreachable.main.UnreachablePropagation.diff
index 848bff1d4920..323b61346c00 100644
--- a/tests/mir-opt/unreachable.main.UnreachablePropagation.diff
+++ b/tests/mir-opt/unreachable.main.UnreachablePropagation.diff
@@ -21,7 +21,7 @@
           StorageLive(_1);                 // scope 1 at $DIR/unreachable.rs:+1:23: +1:30
           _1 = empty() -> bb1;             // scope 1 at $DIR/unreachable.rs:+1:23: +1:30
                                            // mir::Constant
-                                           // + span: $DIR/unreachable.rs:9:23: 9:28
+                                           // + span: $DIR/unreachable.rs:10:23: 10:28
                                            // + literal: Const { ty: fn() -> Option {empty}, val: Value() }
       }
   
diff --git a/tests/mir-opt/unreachable.rs b/tests/mir-opt/unreachable.rs
index 6098b525b559..97093729dd13 100644
--- a/tests/mir-opt/unreachable.rs
+++ b/tests/mir-opt/unreachable.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 enum Empty {}
 
 fn empty() -> Option {
diff --git a/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff b/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff
index fb778470e532..94bc633613b7 100644
--- a/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff
+++ b/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff
@@ -23,7 +23,7 @@
           StorageLive(_2);                 // scope 2 at $DIR/unreachable_diverging.rs:+2:25: +2:32
           _2 = empty() -> bb1;             // scope 2 at $DIR/unreachable_diverging.rs:+2:25: +2:32
                                            // mir::Constant
-                                           // + span: $DIR/unreachable_diverging.rs:14:25: 14:30
+                                           // + span: $DIR/unreachable_diverging.rs:15:25: 15:30
                                            // + literal: Const { ty: fn() -> Option {empty}, val: Value() }
       }
   
@@ -44,7 +44,7 @@
       bb3: {
           _5 = loop_forever() -> bb5;      // scope 2 at $DIR/unreachable_diverging.rs:+4:13: +4:27
                                            // mir::Constant
-                                           // + span: $DIR/unreachable_diverging.rs:16:13: 16:25
+                                           // + span: $DIR/unreachable_diverging.rs:17:13: 17:25
                                            // + literal: Const { ty: fn() {loop_forever}, val: Value() }
       }
   
diff --git a/tests/mir-opt/unreachable_diverging.rs b/tests/mir-opt/unreachable_diverging.rs
index bbf28efc7ddd..24e776148c12 100644
--- a/tests/mir-opt/unreachable_diverging.rs
+++ b/tests/mir-opt/unreachable_diverging.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 pub enum Empty {}
 
 fn empty() -> Option {
diff --git a/tests/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir b/tests/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir
index ed9f3bdbdf4d..c27a93e91f89 100644
--- a/tests/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir
+++ b/tests/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir
@@ -22,7 +22,7 @@ fn std::ptr::drop_in_place(_1: *mut Vec) -> () {
     }
 
     bb4 (cleanup): {
-        drop(((*_1).0: alloc::raw_vec::RawVec)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        drop(((*_1).0: alloc::raw_vec::RawVec)) -> [return: bb2, unwind terminate]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
     }
 
     bb5: {
diff --git a/tests/mir-opt/while_storage.rs b/tests/mir-opt/while_storage.rs
index afd083acb340..d10048dd908a 100644
--- a/tests/mir-opt/while_storage.rs
+++ b/tests/mir-opt/while_storage.rs
@@ -1,3 +1,4 @@
+// ignore-wasm32 compiled with panic=abort by default
 // Test that we correctly generate StorageDead statements for while loop
 // conditions on all branches
 
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 318119bd477c..811789a60c3e 100644
--- a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir
+++ b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir
@@ -14,7 +14,7 @@ fn while_loop(_1: bool) -> () {
         StorageLive(_2);                 // 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
+                                         // + span: $DIR/while_storage.rs:11:11: 11:19
                                          // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value() }
     }
 
@@ -26,7 +26,7 @@ fn while_loop(_1: bool) -> () {
         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
+                                         // + span: $DIR/while_storage.rs:12:12: 12:20
                                          // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value() }
     }
 
diff --git a/tests/run-make/coverage-reports/expected_show_coverage.abort.txt b/tests/run-make/coverage-reports/expected_show_coverage.abort.txt
index 00f46f42a078..a71c58d618da 100644
--- a/tests/run-make/coverage-reports/expected_show_coverage.abort.txt
+++ b/tests/run-make/coverage-reports/expected_show_coverage.abort.txt
@@ -32,7 +32,7 @@
    30|       |// Notes:
    31|       |//   1. Compare this program and its coverage results to those of the similar tests
    32|       |//      `panic_unwind.rs` and `try_error_result.rs`.
-   33|       |//   2. This test confirms the coverage generated when a program includes `TerminatorKind::Abort`.
+   33|       |//   2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`.
    34|       |//   3. The test does not invoke the abort. By executing to a successful completion, the coverage
    35|       |//      results show where the program did and did not execute.
    36|       |//   4. If the program actually aborted, the coverage counters would not be saved (which "works as
diff --git a/tests/run-make/coverage/abort.rs b/tests/run-make/coverage/abort.rs
index 3dac43df8f30..98264bdc1afe 100644
--- a/tests/run-make/coverage/abort.rs
+++ b/tests/run-make/coverage/abort.rs
@@ -30,7 +30,7 @@ fn main() -> Result<(), u8> {
 // Notes:
 //   1. Compare this program and its coverage results to those of the similar tests
 //      `panic_unwind.rs` and `try_error_result.rs`.
-//   2. This test confirms the coverage generated when a program includes `TerminatorKind::Abort`.
+//   2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`.
 //   3. The test does not invoke the abort. By executing to a successful completion, the coverage
 //      results show where the program did and did not execute.
 //   4. If the program actually aborted, the coverage counters would not be saved (which "works as
diff --git a/tests/run-make/static-pie/Makefile b/tests/run-make/static-pie/Makefile
index 19c041d94284..8379730cc3df 100644
--- a/tests/run-make/static-pie/Makefile
+++ b/tests/run-make/static-pie/Makefile
@@ -2,7 +2,7 @@ include ../tools.mk
 
 # only-x86_64
 # only-linux
-# ignore-gnux32
+# ignore-32bit
 
 # How to manually run this
 # $ ./x.py test --target x86_64-unknown-linux-[musl,gnu] tests/run-make/static-pie
diff --git a/tests/run-make/use-extern-for-plugins/Makefile b/tests/run-make/use-extern-for-plugins/Makefile
index 6ae53afad207..b8ec7e8dcda9 100644
--- a/tests/run-make/use-extern-for-plugins/Makefile
+++ b/tests/run-make/use-extern-for-plugins/Makefile
@@ -2,7 +2,7 @@ include ../tools.mk
 
 # ignore-freebsd
 # ignore-openbsd
-# ignore-sunos
+# ignore-solaris
 
 HOST := $(shell $(RUSTC) -vV | grep 'host:' | sed 's/host: //')
 ifeq ($(findstring i686,$(HOST)),i686)
diff --git a/tests/run-make/valid-print-requests/valid-print-requests.stderr b/tests/run-make/valid-print-requests/valid-print-requests.stderr
index 5191e4676486..bea6ce067f6e 100644
--- a/tests/run-make/valid-print-requests/valid-print-requests.stderr
+++ b/tests/run-make/valid-print-requests/valid-print-requests.stderr
@@ -1,2 +1,2 @@
-error: unknown print request `uwu`. Valid print requests are: `crate-name`, `file-names`, `sysroot`, `target-libdir`, `cfg`, `calling-conventions`, `target-list`, `target-cpus`, `target-features`, `relocation-models`, `code-models`, `tls-models`, `native-static-libs`, `stack-protector-strategies`, `target-spec-json`, `link-args`, `split-debuginfo`
+error: unknown print request `uwu`. Valid print requests are: `crate-name`, `file-names`, `sysroot`, `target-libdir`, `cfg`, `calling-conventions`, `target-list`, `target-cpus`, `target-features`, `relocation-models`, `code-models`, `tls-models`, `native-static-libs`, `stack-protector-strategies`, `target-spec-json`, `all-target-specs-json`, `link-args`, `split-debuginfo`
 
diff --git a/tests/rustdoc-gui/go-to-collapsed-elem.goml b/tests/rustdoc-gui/go-to-collapsed-elem.goml
index 279048e37c1f..ec4231252364 100644
--- a/tests/rustdoc-gui/go-to-collapsed-elem.goml
+++ b/tests/rustdoc-gui/go-to-collapsed-elem.goml
@@ -9,13 +9,32 @@ property: ("#implementations-list .implementors-toggle", {"open": "false"})
 click: "//*[@class='sidebar']//a[@href='#method.must_use']"
 assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})
 
-// Now we do the same through search result.
-// First we reload the page without the anchor in the URL.
+define-function: ("collapsed-from-search", (), block {
+    // Now we do the same through search result.
+    // First we reload the page without the anchor in the URL.
+    goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
+    // Then we collapse the section again...
+    property: ("#implementations-list .implementors-toggle", {"open": "false"})
+    // Then we run the search.
+    write: (".search-input", "foo::must_use")
+    wait-for: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']"
+    click: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']"
+    assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})
+})
+
+call-function: ("collapsed-from-search", {})
+
+// Now running the same check but with mobile.
+size: (600, 600)
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
-// Then we collapse the section again...
-property: ("#implementations-list .implementors-toggle", {"open": "false"})
-// Then we run the search.
-write: (".search-input", "foo::must_use")
-wait-for: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']"
-click: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']"
+// We check that the implementors block is expanded.
 assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})
+// We now collapse the implementors block.
+property: ("#implementations-list .implementors-toggle", {"open": "false"})
+// First we expand the mobile menu.
+click: ".sidebar-menu-toggle"
+// Then we click on the link to the method to ensure it'll expand the implementors block.
+click: "//*[@class='sidebar shown']//a[@href='#method.must_use']"
+assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})
+
+call-function: ("collapsed-from-search", {})
diff --git a/tests/rustdoc-gui/huge-logo.goml b/tests/rustdoc-gui/huge-logo.goml
index 01f06771c15a..69459bd3e23b 100644
--- a/tests/rustdoc-gui/huge-logo.goml
+++ b/tests/rustdoc-gui/huge-logo.goml
@@ -18,4 +18,6 @@ size: (1280, 1024)
 assert-property: (".sub-logo-container", {"offsetWidth": "60", "offsetHeight": 60})
 
 size: (400, 600)
-assert-property: (".sub-logo-container", {"offsetWidth": "35", "offsetHeight": 35})
+// 43 because 35px + 8px of margin
+assert-css: (".sub-logo-container > img", {"margin-bottom": "8px"})
+assert-property: (".sub-logo-container", {"offsetWidth": "35", "offsetHeight": 43})
diff --git a/tests/rustdoc-gui/source-code-page-code-scroll.goml b/tests/rustdoc-gui/source-code-page-code-scroll.goml
new file mode 100644
index 000000000000..42f1da749e96
--- /dev/null
+++ b/tests/rustdoc-gui/source-code-page-code-scroll.goml
@@ -0,0 +1,8 @@
+// Checks that the scrollbar is visible on the page rather than the code block.
+goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
+size: (800, 1000)
+// "scrollWidth" should be superior than "clientWidth".
+assert-property: ("body", {"scrollWidth": 1047, "clientWidth": 800})
+
+// Both properties should be equal (ie, no scroll on the code block).
+assert-property: (".example-wrap .rust", {"scrollWidth": 933, "clientWidth": 933})
diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml
index 7c35119e6959..ea6ff12328ca 100644
--- a/tests/rustdoc-gui/source-code-page.goml
+++ b/tests/rustdoc-gui/source-code-page.goml
@@ -216,3 +216,8 @@ call-function: ("check-sidebar-dir-entry", {
     "x": 0,
     "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
 })
+
+// Now we check that the logo has a bottom margin so it's not stuck to the search input.
+assert-css: (".sub-logo-container > img", {"margin-bottom": "8px"})
+store-property: (logo_height, ".sub-logo-container", "clientHeight")
+assert-position: (".search-form", {"y": |logo_height| + 8})
diff --git a/tests/rustdoc-gui/theme-defaults.goml b/tests/rustdoc-gui/theme-defaults.goml
new file mode 100644
index 000000000000..d5ed536b1a96
--- /dev/null
+++ b/tests/rustdoc-gui/theme-defaults.goml
@@ -0,0 +1,24 @@
+// Ensure that the theme picker always starts with the actual defaults.
+goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
+click: "#settings-menu"
+wait-for: "#theme-system-preference"
+assert: "#theme-system-preference:checked"
+assert: "#preferred-light-theme-light:checked"
+assert: "#preferred-dark-theme-dark:checked"
+assert-false: "#preferred-dark-theme-ayu:checked"
+
+// Test legacy migration from old theme setup without system-preference matching.
+// See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732
+local-storage: {
+    "rustdoc-preferred-light-theme": null,
+    "rustdoc-preferred-dark-theme": null,
+    "rustdoc-use-system-theme": null,
+    "rustdoc-theme": "ayu"
+}
+goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
+click: "#settings-menu"
+wait-for: "#theme-system-preference"
+assert: "#theme-system-preference:checked"
+assert: "#preferred-light-theme-light:checked"
+assert-false: "#preferred-dark-theme-dark:checked"
+assert: "#preferred-dark-theme-ayu:checked"
diff --git a/tests/rustdoc-ui/c-help.stdout b/tests/rustdoc-ui/c-help.stdout
index 75b2e2a2a43f..0bd2d73efee5 100644
--- a/tests/rustdoc-ui/c-help.stdout
+++ b/tests/rustdoc-ui/c-help.stdout
@@ -3,7 +3,7 @@
     -C            codegen-units=val -- divide crate into N units to optimize in parallel
     -C       control-flow-guard=val -- use Windows Control Flow Guard (default: no)
     -C         debug-assertions=val -- explicitly enable the `cfg(debug_assertions)` directive
-    -C                debuginfo=val -- debug info emission level (0 = no debug info, 1 = line tables only, 2 = full debug info with variable and type information; default: 0)
+    -C                debuginfo=val -- debug info emission level (0-2, none, line-directives-only, line-tables-only, limited, or full; default: 0)
     -C default-linker-libraries=val -- allow the linker to link its default libraries (default: no)
     -C            embed-bitcode=val -- emit bitcode in rlibs (default: yes)
     -C           extra-filename=val -- extra data to put in each output filename
diff --git a/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr b/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr
index 084aefc97c83..ed89fa8391d6 100644
--- a/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr
+++ b/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr
@@ -33,21 +33,6 @@ help: to link to the associated type, prefix with `type@`
 LL | /// [`type@Self::IDENT2`]
    |       +++++
 
-error: `Self::IDENT2` is both an associated constant and an associated type
-  --> $DIR/issue-108653-associated-items.rs:30:7
-   |
-LL | /// [`Self::IDENT2`]
-   |       ^^^^^^^^^^^^ ambiguous link
-   |
-help: to link to the associated constant, prefix with `const@`
-   |
-LL | /// [`const@Self::IDENT2`]
-   |       ++++++
-help: to link to the associated type, prefix with `type@`
-   |
-LL | /// [`type@Self::IDENT2`]
-   |       +++++
-
 error: `Self::IDENT` is both an associated function and a variant
   --> $DIR/issue-108653-associated-items.rs:16:7
    |
@@ -63,5 +48,20 @@ help: to link to the variant, prefix with `type@`
 LL | /// [`type@Self::IDENT`]
    |       +++++
 
+error: `Self::IDENT2` is both an associated constant and an associated type
+  --> $DIR/issue-108653-associated-items.rs:30:7
+   |
+LL | /// [`Self::IDENT2`]
+   |       ^^^^^^^^^^^^ ambiguous link
+   |
+help: to link to the associated constant, prefix with `const@`
+   |
+LL | /// [`const@Self::IDENT2`]
+   |       ++++++
+help: to link to the associated type, prefix with `type@`
+   |
+LL | /// [`type@Self::IDENT2`]
+   |       +++++
+
 error: aborting due to 4 previous errors
 
diff --git a/tests/rustdoc/async-fn-opaque-item.rs b/tests/rustdoc/async-fn-opaque-item.rs
new file mode 100644
index 000000000000..a73e84f3fdc4
--- /dev/null
+++ b/tests/rustdoc/async-fn-opaque-item.rs
@@ -0,0 +1,15 @@
+// compile-flags: --document-private-items --crate-type=lib
+// edition: 2021
+
+// Issue 109931 -- test against accidentally documenting the `impl Future`
+// that comes from an async fn desugaring.
+
+// Check that we don't document an unnamed opaque type
+// @!has async_fn_opaque_item/opaque..html
+
+// Checking there is only a "Functions" header and no "Opaque types".
+// @has async_fn_opaque_item/index.html
+// @count - '//*[@class="small-section-header"]' 1
+// @has - '//*[@class="small-section-header"]' 'Functions'
+
+pub async fn test() {}
diff --git a/tests/rustdoc/generic-associated-types/issue-109488.rs b/tests/rustdoc/generic-associated-types/issue-109488.rs
new file mode 100644
index 000000000000..99ae8a6c36c5
--- /dev/null
+++ b/tests/rustdoc/generic-associated-types/issue-109488.rs
@@ -0,0 +1,18 @@
+// Make sure that we escape the arguments of the GAT projection even if we fail to compute
+// the href of the corresponding trait (in this case it is private).
+// Further, test that we also linkify the GAT arguments.
+
+// @has 'issue_109488/type.A.html'
+// @has - '//pre[@class="rust item-decl"]' '::P>'
+// @has - '//pre[@class="rust item-decl"]//a[@class="enum"]/@href' '{{channel}}/core/option/enum.Option.html'
+pub type A = ::P>;
+
+/*private*/ trait Tr {
+    type P;
+}
+
+pub struct S;
+
+impl Tr for S {
+    type P = ();
+}
diff --git a/tests/rustdoc/issue-25001.rs b/tests/rustdoc/issue-25001.rs
index c97b35adaf22..268fae59496a 100644
--- a/tests/rustdoc/issue-25001.rs
+++ b/tests/rustdoc/issue-25001.rs
@@ -21,14 +21,14 @@ impl Foo {
 }
 
 impl Bar for Foo {
-    // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' 'type Item = T'
+    // @has - '//*[@id="associatedtype.Item-1"]//h4[@class="code-header"]' 'type Item = T'
     type Item=T;
 
     // @has - '//*[@id="method.quux"]//h4[@class="code-header"]' 'fn quux(self)'
     fn quux(self) {}
 }
 impl<'a, T> Bar for &'a Foo {
-    // @has - '//*[@id="associatedtype.Item-1"]//h4[@class="code-header"]' "type Item = &'a T"
+    // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item = &'a T"
     type Item=&'a T;
 
     // @has - '//*[@id="method.quux-1"]//h4[@class="code-header"]' 'fn quux(self)'
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index 3151c712566a..61724c11745c 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -50,7 +50,7 @@ enum DiagnosticOnEnum {
 #[derive(Diagnostic)]
 #[diag(no_crate_example, code = "E0123")]
 #[diag = "E0123"]
-//~^ ERROR `#[diag = ...]` is not a valid attribute
+//~^ ERROR expected parentheses: #[diag(...)]
 struct WrongStructAttrStyle {}
 
 #[derive(Diagnostic)]
@@ -62,8 +62,7 @@ struct InvalidStructAttr {}
 
 #[derive(Diagnostic)]
 #[diag("E0123")]
-//~^ ERROR `#[diag("...")]` is not a valid attribute
-//~^^ ERROR diagnostic slug not specified
+//~^ ERROR diagnostic slug not specified
 struct InvalidLitNestedAttr {}
 
 #[derive(Diagnostic)]
@@ -73,27 +72,25 @@ struct InvalidNestedStructAttr {}
 
 #[derive(Diagnostic)]
 #[diag(nonsense("foo"), code = "E0123", slug = "foo")]
-//~^ ERROR `#[diag(nonsense(...))]` is not a valid attribute
-//~^^ ERROR diagnostic slug not specified
+//~^ ERROR diagnostic slug must be the first argument
+//~| ERROR diagnostic slug not specified
 struct InvalidNestedStructAttr1 {}
 
 #[derive(Diagnostic)]
 #[diag(nonsense = "...", code = "E0123", slug = "foo")]
-//~^ ERROR `#[diag(nonsense = ...)]` is not a valid attribute
-//~| ERROR `#[diag(slug = ...)]` is not a valid attribute
+//~^ ERROR unknown argument
 //~| ERROR diagnostic slug not specified
 struct InvalidNestedStructAttr2 {}
 
 #[derive(Diagnostic)]
 #[diag(nonsense = 4, code = "E0123", slug = "foo")]
-//~^ ERROR `#[diag(nonsense = ...)]` is not a valid attribute
-//~| ERROR `#[diag(slug = ...)]` is not a valid attribute
+//~^ ERROR unknown argument
 //~| ERROR diagnostic slug not specified
 struct InvalidNestedStructAttr3 {}
 
 #[derive(Diagnostic)]
 #[diag(no_crate_example, code = "E0123", slug = "foo")]
-//~^ ERROR `#[diag(slug = ...)]` is not a valid attribute
+//~^ ERROR unknown argument
 struct InvalidNestedStructAttr4 {}
 
 #[derive(Diagnostic)]
@@ -118,7 +115,7 @@ struct CodeSpecifiedTwice {}
 
 #[derive(Diagnostic)]
 #[diag(no_crate_example, no_crate::example, code = "E0456")]
-//~^ ERROR `#[diag(no_crate::example)]` is not a valid attribute
+//~^ ERROR diagnostic slug must be the first argument
 struct SlugSpecifiedTwice {}
 
 #[derive(Diagnostic)]
@@ -232,7 +229,7 @@ struct SuggestWithoutCode {
 #[diag(no_crate_example, code = "E0123")]
 struct SuggestWithBadKey {
     #[suggestion(nonsense = "bar")]
-    //~^ ERROR `#[suggestion(nonsense = ...)]` is not a valid attribute
+    //~^ ERROR invalid nested attribute
     //~| ERROR suggestion without `code = "..."`
     suggestion: (Span, Applicability),
 }
@@ -241,7 +238,7 @@ struct SuggestWithBadKey {
 #[diag(no_crate_example, code = "E0123")]
 struct SuggestWithShorthandMsg {
     #[suggestion(msg = "bar")]
-    //~^ ERROR `#[suggestion(msg = ...)]` is not a valid attribute
+    //~^ ERROR invalid nested attribute
     //~| ERROR suggestion without `code = "..."`
     suggestion: (Span, Applicability),
 }
@@ -530,7 +527,7 @@ struct BoolField {
 #[diag(no_crate_example, code = "E0123")]
 struct LabelWithTrailingPath {
     #[label(no_crate_label, foo)]
-    //~^ ERROR `#[label(foo)]` is not a valid attribute
+    //~^ ERROR a diagnostic slug must be the first argument to the attribute
     span: Span,
 }
 
@@ -538,7 +535,7 @@ struct LabelWithTrailingPath {
 #[diag(no_crate_example, code = "E0123")]
 struct LabelWithTrailingNameValue {
     #[label(no_crate_label, foo = "...")]
-    //~^ ERROR `#[label(foo = ...)]` is not a valid attribute
+    //~^ ERROR invalid nested attribute
     span: Span,
 }
 
@@ -546,7 +543,7 @@ struct LabelWithTrailingNameValue {
 #[diag(no_crate_example, code = "E0123")]
 struct LabelWithTrailingList {
     #[label(no_crate_label, foo("..."))]
-    //~^ ERROR `#[label(foo(...))]` is not a valid attribute
+    //~^ ERROR invalid nested attribute
     span: Span,
 }
 
@@ -643,8 +640,8 @@ struct MissingCodeInSuggestion {
 //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute
 //~| ERROR cannot find attribute `multipart_suggestion` in this scope
 #[multipart_suggestion()]
-//~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute
-//~| ERROR cannot find attribute `multipart_suggestion` in this scope
+//~^ ERROR cannot find attribute `multipart_suggestion` in this scope
+//~| ERROR unexpected end of input, unexpected token in nested attribute, expected ident
 struct MultipartSuggestion {
     #[multipart_suggestion(no_crate_suggestion)]
     //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute
@@ -698,7 +695,7 @@ struct RawIdentDiagnosticArg {
 #[diag(no_crate_example)]
 struct SubdiagnosticBad {
     #[subdiagnostic(bad)]
-    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
+    //~^ ERROR `eager` is the only supported nested attribute for `subdiagnostic`
     note: Note,
 }
 
@@ -714,7 +711,7 @@ struct SubdiagnosticBadStr {
 #[diag(no_crate_example)]
 struct SubdiagnosticBadTwice {
     #[subdiagnostic(bad, bad)]
-    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
+    //~^ ERROR `eager` is the only supported nested attribute for `subdiagnostic`
     note: Note,
 }
 
@@ -722,7 +719,7 @@ struct SubdiagnosticBadTwice {
 #[diag(no_crate_example)]
 struct SubdiagnosticBadLitStr {
     #[subdiagnostic("bad")]
-    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
+    //~^ ERROR `eager` is the only supported nested attribute for `subdiagnostic`
     note: Note,
 }
 
@@ -797,14 +794,15 @@ struct SuggestionsNoItem {
 struct SuggestionsInvalidItem {
     #[suggestion(code(foo))]
     //~^ ERROR `code(...)` must contain only string literals
+    //~| ERROR unexpected token
     sub: Span,
 }
 
-#[derive(Diagnostic)]
+#[derive(Diagnostic)] //~ ERROR cannot find value `__code_34` in this scope
 #[diag(no_crate_example)]
 struct SuggestionsInvalidLiteral {
     #[suggestion(code = 3)]
-    //~^ ERROR `code = "..."`/`code(...)` must contain only string literals
+    //~^ ERROR expected string literal
     sub: Span,
 }
 
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index 513b675e5dd4..cd14c7496b37 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -20,11 +20,11 @@ LL |     Bar,
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[diag = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:52:1
+error: expected parentheses: #[diag(...)]
+  --> $DIR/diagnostic-derive.rs:52:8
    |
 LL | #[diag = "E0123"]
-   | ^^^^^^^^^^^^^^^^^
+   |        ^
 
 error: `#[nonsense(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:57:1
@@ -44,35 +44,24 @@ LL | | struct InvalidStructAttr {}
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[diag("...")]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:64:8
-   |
-LL | #[diag("E0123")]
-   |        ^^^^^^^
-   |
-   = help: a diagnostic slug is required as the first argument
-
 error: diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:64:1
    |
 LL | / #[diag("E0123")]
 LL | |
-LL | |
 LL | | struct InvalidLitNestedAttr {}
    | |______________________________^
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[diag(nonsense(...))]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:75:8
+error: diagnostic slug must be the first argument
+  --> $DIR/diagnostic-derive.rs:74:16
    |
 LL | #[diag(nonsense("foo"), code = "E0123", slug = "foo")]
-   |        ^^^^^^^^^^^^^^^
-   |
-   = help: a diagnostic slug is required as the first argument
+   |                ^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:75:1
+  --> $DIR/diagnostic-derive.rs:74:1
    |
 LL | / #[diag(nonsense("foo"), code = "E0123", slug = "foo")]
 LL | |
@@ -82,120 +71,102 @@ LL | | struct InvalidNestedStructAttr1 {}
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[diag(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:81:8
+error: unknown argument
+  --> $DIR/diagnostic-derive.rs:80:8
    |
 LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")]
-   |        ^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^
    |
-   = help: only `code` is a valid nested attributes following the slug
-
-error: `#[diag(slug = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:81:42
-   |
-LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")]
-   |                                          ^^^^^^^^^^^^
-   |
-   = help: only `code` is a valid nested attributes following the slug
+   = note: only the `code` parameter is valid after the slug
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:81:1
+  --> $DIR/diagnostic-derive.rs:80:1
    |
 LL | / #[diag(nonsense = "...", code = "E0123", slug = "foo")]
 LL | |
 LL | |
-LL | |
 LL | | struct InvalidNestedStructAttr2 {}
    | |__________________________________^
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[diag(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:88:8
+error: unknown argument
+  --> $DIR/diagnostic-derive.rs:86:8
    |
 LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")]
-   |        ^^^^^^^^^^^^
-
-error: `#[diag(slug = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:88:38
+   |        ^^^^^^^^
    |
-LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")]
-   |                                      ^^^^^^^^^^^^
-   |
-   = help: only `code` is a valid nested attributes following the slug
+   = note: only the `code` parameter is valid after the slug
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:88:1
+  --> $DIR/diagnostic-derive.rs:86:1
    |
 LL | / #[diag(nonsense = 4, code = "E0123", slug = "foo")]
 LL | |
 LL | |
-LL | |
 LL | | struct InvalidNestedStructAttr3 {}
    | |__________________________________^
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[diag(slug = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:95:42
+error: unknown argument
+  --> $DIR/diagnostic-derive.rs:92:42
    |
 LL | #[diag(no_crate_example, code = "E0123", slug = "foo")]
-   |                                          ^^^^^^^^^^^^
+   |                                          ^^^^
    |
-   = help: only `code` is a valid nested attributes following the slug
+   = note: only the `code` parameter is valid after the slug
 
 error: `#[suggestion = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:102:5
+  --> $DIR/diagnostic-derive.rs:99:5
    |
 LL |     #[suggestion = "bar"]
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:109:8
+  --> $DIR/diagnostic-derive.rs:106:8
    |
 LL | #[diag(no_crate_example, code = "E0456")]
    |        ^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:108:8
+  --> $DIR/diagnostic-derive.rs:105:8
    |
 LL | #[diag(no_crate_example, code = "E0123")]
    |        ^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:109:33
+  --> $DIR/diagnostic-derive.rs:106:26
    |
 LL | #[diag(no_crate_example, code = "E0456")]
-   |                                 ^^^^^^^
+   |                          ^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:108:33
+  --> $DIR/diagnostic-derive.rs:105:26
    |
 LL | #[diag(no_crate_example, code = "E0123")]
-   |                                 ^^^^^^^
+   |                          ^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:115:49
+  --> $DIR/diagnostic-derive.rs:112:42
    |
 LL | #[diag(no_crate_example, code = "E0456", code = "E0457")]
-   |                                                 ^^^^^^^
+   |                                          ^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:115:33
+  --> $DIR/diagnostic-derive.rs:112:26
    |
 LL | #[diag(no_crate_example, code = "E0456", code = "E0457")]
-   |                                 ^^^^^^^
+   |                          ^^^^
 
-error: `#[diag(no_crate::example)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:120:26
+error: diagnostic slug must be the first argument
+  --> $DIR/diagnostic-derive.rs:117:43
    |
 LL | #[diag(no_crate_example, no_crate::example, code = "E0456")]
-   |                          ^^^^^^^^^^^^^^^^^
-   |
-   = help: diagnostic slug must be the first argument
+   |                                           ^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:125:1
+  --> $DIR/diagnostic-derive.rs:122:1
    |
 LL | struct KindNotProvided {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -203,7 +174,7 @@ LL | struct KindNotProvided {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:128:1
+  --> $DIR/diagnostic-derive.rs:125:1
    |
 LL | / #[diag(code = "E0456")]
 LL | |
@@ -213,31 +184,31 @@ LL | | struct SlugNotProvided {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/diagnostic-derive.rs:139:5
+  --> $DIR/diagnostic-derive.rs:136:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: `#[nonsense]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:147:5
+  --> $DIR/diagnostic-derive.rs:144:5
    |
 LL |     #[nonsense]
    |     ^^^^^^^^^^^
 
 error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/diagnostic-derive.rs:164:5
+  --> $DIR/diagnostic-derive.rs:161:5
    |
 LL |     #[label(no_crate_label)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `name` doesn't refer to a field on this type
-  --> $DIR/diagnostic-derive.rs:172:46
+  --> $DIR/diagnostic-derive.rs:169:46
    |
 LL |     #[suggestion(no_crate_suggestion, code = "{name}")]
    |                                              ^^^^^^^^
 
 error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/diagnostic-derive.rs:177:10
+  --> $DIR/diagnostic-derive.rs:174:10
    |
 LL | #[derive(Diagnostic)]
    |          ^^^^^^^^^^ expected `'}'` in format string
@@ -246,7 +217,7 @@ LL | #[derive(Diagnostic)]
    = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: invalid format string: unmatched `}` found
-  --> $DIR/diagnostic-derive.rs:187:10
+  --> $DIR/diagnostic-derive.rs:184:10
    |
 LL | #[derive(Diagnostic)]
    |          ^^^^^^^^^^ unmatched `}` in format string
@@ -255,47 +226,47 @@ LL | #[derive(Diagnostic)]
    = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/diagnostic-derive.rs:207:5
+  --> $DIR/diagnostic-derive.rs:204:5
    |
 LL |     #[label(no_crate_label)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: suggestion without `code = "..."`
-  --> $DIR/diagnostic-derive.rs:226:5
+  --> $DIR/diagnostic-derive.rs:223:5
    |
 LL |     #[suggestion(no_crate_suggestion)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `#[suggestion(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:234:18
+error: invalid nested attribute
+  --> $DIR/diagnostic-derive.rs:231:18
    |
 LL |     #[suggestion(nonsense = "bar")]
-   |                  ^^^^^^^^^^^^^^^^
+   |                  ^^^^^^^^
    |
    = help: only `style`, `code` and `applicability` are valid nested attributes
 
 error: suggestion without `code = "..."`
-  --> $DIR/diagnostic-derive.rs:234:5
+  --> $DIR/diagnostic-derive.rs:231:5
    |
 LL |     #[suggestion(nonsense = "bar")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `#[suggestion(msg = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:243:18
+error: invalid nested attribute
+  --> $DIR/diagnostic-derive.rs:240:18
    |
 LL |     #[suggestion(msg = "bar")]
-   |                  ^^^^^^^^^^^
+   |                  ^^^
    |
    = help: only `style`, `code` and `applicability` are valid nested attributes
 
 error: suggestion without `code = "..."`
-  --> $DIR/diagnostic-derive.rs:243:5
+  --> $DIR/diagnostic-derive.rs:240:5
    |
 LL |     #[suggestion(msg = "bar")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: wrong field type for suggestion
-  --> $DIR/diagnostic-derive.rs:266:5
+  --> $DIR/diagnostic-derive.rs:263:5
    |
 LL | /     #[suggestion(no_crate_suggestion, code = "This is suggested code")]
 LL | |
@@ -305,81 +276,79 @@ LL | |     suggestion: Applicability,
    = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:282:24
+  --> $DIR/diagnostic-derive.rs:279:24
    |
 LL |     suggestion: (Span, Span, Applicability),
    |                        ^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:282:18
+  --> $DIR/diagnostic-derive.rs:279:18
    |
 LL |     suggestion: (Span, Span, Applicability),
    |                  ^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:290:33
+  --> $DIR/diagnostic-derive.rs:287:33
    |
 LL |     suggestion: (Applicability, Applicability, Span),
    |                                 ^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:290:18
+  --> $DIR/diagnostic-derive.rs:287:18
    |
 LL |     suggestion: (Applicability, Applicability, Span),
    |                  ^^^^^^^^^^^^^
 
 error: `#[label = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:297:5
+  --> $DIR/diagnostic-derive.rs:294:5
    |
 LL |     #[label = "bar"]
    |     ^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:448:53
+  --> $DIR/diagnostic-derive.rs:445:5
    |
 LL |     #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")]
-   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:450:24
+  --> $DIR/diagnostic-derive.rs:447:24
    |
 LL |     suggestion: (Span, Applicability),
    |                        ^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/diagnostic-derive.rs:456:53
+  --> $DIR/diagnostic-derive.rs:453:69
    |
 LL |     #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")]
-   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                                                     ^^^^^^^^
 
 error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `bool` or `()`
-  --> $DIR/diagnostic-derive.rs:523:5
+  --> $DIR/diagnostic-derive.rs:520:5
    |
 LL |     #[help(no_crate_help)]
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: `#[label(foo)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:532:29
+error: a diagnostic slug must be the first argument to the attribute
+  --> $DIR/diagnostic-derive.rs:529:32
    |
 LL |     #[label(no_crate_label, foo)]
-   |                             ^^^
-   |
-   = help: a diagnostic slug must be the first argument to the attribute
+   |                                ^
 
-error: `#[label(foo = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:540:29
+error: invalid nested attribute
+  --> $DIR/diagnostic-derive.rs:537:29
    |
 LL |     #[label(no_crate_label, foo = "...")]
-   |                             ^^^^^^^^^^^
+   |                             ^^^
 
-error: `#[label(foo(...))]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:548:29
+error: invalid nested attribute
+  --> $DIR/diagnostic-derive.rs:545:29
    |
 LL |     #[label(no_crate_label, foo("..."))]
-   |                             ^^^^^^^^^^
+   |                             ^^^
 
 error: `#[primary_span]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:560:5
+  --> $DIR/diagnostic-derive.rs:557:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
@@ -387,13 +356,13 @@ LL |     #[primary_span]
    = help: the `primary_span` field attribute is not valid for lint diagnostics
 
 error: `#[error(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:580:1
+  --> $DIR/diagnostic-derive.rs:577:1
    |
 LL | #[error(no_crate_example, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:580:1
+  --> $DIR/diagnostic-derive.rs:577:1
    |
 LL | / #[error(no_crate_example, code = "E0123")]
 LL | |
@@ -405,13 +374,13 @@ LL | | struct ErrorAttribute {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[warn_(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:587:1
+  --> $DIR/diagnostic-derive.rs:584:1
    |
 LL | #[warn_(no_crate_example, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:587:1
+  --> $DIR/diagnostic-derive.rs:584:1
    |
 LL | / #[warn_(no_crate_example, code = "E0123")]
 LL | |
@@ -423,13 +392,13 @@ LL | | struct WarnAttribute {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[lint(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:594:1
+  --> $DIR/diagnostic-derive.rs:591:1
    |
 LL | #[lint(no_crate_example, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:594:1
+  --> $DIR/diagnostic-derive.rs:591:1
    |
 LL | / #[lint(no_crate_example, code = "E0123")]
 LL | |
@@ -441,19 +410,19 @@ LL | | struct LintAttributeOnSessionDiag {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[lint(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:601:1
+  --> $DIR/diagnostic-derive.rs:598:1
    |
 LL | #[lint(no_crate_example, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[lint(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:601:1
+  --> $DIR/diagnostic-derive.rs:598:1
    |
 LL | #[lint(no_crate_example, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:601:1
+  --> $DIR/diagnostic-derive.rs:598:1
    |
 LL | / #[lint(no_crate_example, code = "E0123")]
 LL | |
@@ -466,19 +435,19 @@ LL | | struct LintAttributeOnLintDiag {}
    = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]`
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:611:53
+  --> $DIR/diagnostic-derive.rs:608:53
    |
 LL |     #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
-   |                                                     ^^^^^^^^^^^^
+   |                                                     ^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:611:39
+  --> $DIR/diagnostic-derive.rs:608:39
    |
 LL |     #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
-   |                                       ^^^^^^^^^^^^
+   |                                       ^^^^
 
 error: wrong types for suggestion
-  --> $DIR/diagnostic-derive.rs:620:24
+  --> $DIR/diagnostic-derive.rs:617:24
    |
 LL |     suggestion: (Span, usize),
    |                        ^^^^^
@@ -486,7 +455,7 @@ LL |     suggestion: (Span, usize),
    = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
 
 error: wrong types for suggestion
-  --> $DIR/diagnostic-derive.rs:628:17
+  --> $DIR/diagnostic-derive.rs:625:17
    |
 LL |     suggestion: (Span,),
    |                 ^^^^^^^
@@ -494,13 +463,13 @@ LL |     suggestion: (Span,),
    = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
 
 error: suggestion without `code = "..."`
-  --> $DIR/diagnostic-derive.rs:635:5
+  --> $DIR/diagnostic-derive.rs:632:5
    |
 LL |     #[suggestion(no_crate_suggestion)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[multipart_suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:642:1
+  --> $DIR/diagnostic-derive.rs:639:1
    |
 LL | #[multipart_suggestion(no_crate_suggestion)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -508,23 +477,21 @@ LL | #[multipart_suggestion(no_crate_suggestion)]
    = help: consider creating a `Subdiagnostic` instead
 
 error: `#[multipart_suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:645:1
-   |
-LL | #[multipart_suggestion()]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider creating a `Subdiagnostic` instead
-
-error: `#[multipart_suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:649:5
+  --> $DIR/diagnostic-derive.rs:646:5
    |
 LL |     #[multipart_suggestion(no_crate_suggestion)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider creating a `Subdiagnostic` instead
 
+error: unexpected end of input, unexpected token in nested attribute, expected ident
+  --> $DIR/diagnostic-derive.rs:642:24
+   |
+LL | #[multipart_suggestion()]
+   |                        ^
+
 error: `#[suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:657:1
+  --> $DIR/diagnostic-derive.rs:654:1
    |
 LL | #[suggestion(no_crate_suggestion, code = "...")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -532,45 +499,39 @@ LL | #[suggestion(no_crate_suggestion, code = "...")]
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
 error: `#[label]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:666:1
+  --> $DIR/diagnostic-derive.rs:663:1
    |
 LL | #[label]
    | ^^^^^^^^
    |
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:700:5
+error: `eager` is the only supported nested attribute for `subdiagnostic`
+  --> $DIR/diagnostic-derive.rs:697:7
    |
 LL |     #[subdiagnostic(bad)]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: `eager` is the only supported nested attribute for `subdiagnostic`
+   |       ^^^^^^^^^^^^^^^^^^
 
 error: `#[subdiagnostic = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:708:5
+  --> $DIR/diagnostic-derive.rs:705:5
    |
 LL |     #[subdiagnostic = "bad"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:716:5
+error: `eager` is the only supported nested attribute for `subdiagnostic`
+  --> $DIR/diagnostic-derive.rs:713:7
    |
 LL |     #[subdiagnostic(bad, bad)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: `eager` is the only supported nested attribute for `subdiagnostic`
+   |       ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:724:5
+error: `eager` is the only supported nested attribute for `subdiagnostic`
+  --> $DIR/diagnostic-derive.rs:721:7
    |
 LL |     #[subdiagnostic("bad")]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: `eager` is the only supported nested attribute for `subdiagnostic`
+   |       ^^^^^^^^^^^^^^^^^^^^
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:732:5
+  --> $DIR/diagnostic-derive.rs:729:5
    |
 LL |     #[subdiagnostic(eager)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -578,25 +539,31 @@ LL |     #[subdiagnostic(eager)]
    = help: eager subdiagnostics are not supported on lints
 
 error: expected at least one string literal for `code(...)`
-  --> $DIR/diagnostic-derive.rs:790:18
+  --> $DIR/diagnostic-derive.rs:787:23
    |
 LL |     #[suggestion(code())]
-   |                  ^^^^^^
+   |                       ^
 
 error: `code(...)` must contain only string literals
-  --> $DIR/diagnostic-derive.rs:798:23
+  --> $DIR/diagnostic-derive.rs:795:23
    |
 LL |     #[suggestion(code(foo))]
    |                       ^^^
 
-error: `code = "..."`/`code(...)` must contain only string literals
-  --> $DIR/diagnostic-derive.rs:806:18
+error: unexpected token
+  --> $DIR/diagnostic-derive.rs:795:23
+   |
+LL |     #[suggestion(code(foo))]
+   |                       ^^^
+
+error: expected string literal
+  --> $DIR/diagnostic-derive.rs:804:25
    |
 LL |     #[suggestion(code = 3)]
-   |                  ^^^^^^^^
+   |                         ^
 
 error: `#[suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:821:5
+  --> $DIR/diagnostic-derive.rs:819:5
    |
 LL |     #[suggestion(no_crate_suggestion, code = "")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -612,61 +579,69 @@ LL | #[nonsense(no_crate_example, code = "E0123")]
    |   ^^^^^^^^
 
 error: cannot find attribute `nonsense` in this scope
-  --> $DIR/diagnostic-derive.rs:147:7
+  --> $DIR/diagnostic-derive.rs:144:7
    |
 LL |     #[nonsense]
    |       ^^^^^^^^
 
 error: cannot find attribute `error` in this scope
-  --> $DIR/diagnostic-derive.rs:580:3
+  --> $DIR/diagnostic-derive.rs:577:3
    |
 LL | #[error(no_crate_example, code = "E0123")]
    |   ^^^^^
 
 error: cannot find attribute `warn_` in this scope
-  --> $DIR/diagnostic-derive.rs:587:3
+  --> $DIR/diagnostic-derive.rs:584:3
    |
 LL | #[warn_(no_crate_example, code = "E0123")]
    |   ^^^^^ help: a built-in attribute with a similar name exists: `warn`
 
 error: cannot find attribute `lint` in this scope
-  --> $DIR/diagnostic-derive.rs:594:3
+  --> $DIR/diagnostic-derive.rs:591:3
    |
 LL | #[lint(no_crate_example, code = "E0123")]
    |   ^^^^ help: a built-in attribute with a similar name exists: `link`
 
 error: cannot find attribute `lint` in this scope
-  --> $DIR/diagnostic-derive.rs:601:3
+  --> $DIR/diagnostic-derive.rs:598:3
    |
 LL | #[lint(no_crate_example, code = "E0123")]
    |   ^^^^ help: a built-in attribute with a similar name exists: `link`
 
 error: cannot find attribute `multipart_suggestion` in this scope
-  --> $DIR/diagnostic-derive.rs:642:3
+  --> $DIR/diagnostic-derive.rs:639:3
    |
 LL | #[multipart_suggestion(no_crate_suggestion)]
    |   ^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find attribute `multipart_suggestion` in this scope
-  --> $DIR/diagnostic-derive.rs:645:3
+  --> $DIR/diagnostic-derive.rs:642:3
    |
 LL | #[multipart_suggestion()]
    |   ^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find attribute `multipart_suggestion` in this scope
-  --> $DIR/diagnostic-derive.rs:649:7
+  --> $DIR/diagnostic-derive.rs:646:7
    |
 LL |     #[multipart_suggestion(no_crate_suggestion)]
    |       ^^^^^^^^^^^^^^^^^^^^
 
 error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated`
-  --> $DIR/diagnostic-derive.rs:70:8
+  --> $DIR/diagnostic-derive.rs:69:8
    |
 LL | #[diag(nonsense, code = "E0123")]
    |        ^^^^^^^^ not found in `crate::fluent_generated`
 
+error[E0425]: cannot find value `__code_34` in this scope
+  --> $DIR/diagnostic-derive.rs:801:10
+   |
+LL | #[derive(Diagnostic)]
+   |          ^^^^^^^^^^ not found in this scope
+   |
+   = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied
-  --> $DIR/diagnostic-derive.rs:341:10
+  --> $DIR/diagnostic-derive.rs:338:10
    |
 LL | #[derive(Diagnostic)]
    |          ^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
@@ -676,7 +651,7 @@ note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
   --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
    = note: this error originates in the derive macro `Diagnostic` which comes from the expansion of the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 85 previous errors
+error: aborting due to 84 previous errors
 
 Some errors have detailed explanations: E0277, E0425.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
index c882f7792d5b..1d928ca93f9c 100644
--- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
+++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
@@ -82,7 +82,7 @@ struct F {
 
 #[derive(Subdiagnostic)]
 #[label(bug = "...")]
-//~^ ERROR `#[label(bug = ...)]` is not a valid attribute
+//~^ ERROR invalid nested attribute
 //~| ERROR diagnostic slug must be first argument
 struct G {
     #[primary_span]
@@ -92,8 +92,7 @@ struct G {
 
 #[derive(Subdiagnostic)]
 #[label("...")]
-//~^ ERROR `#[label("...")]` is not a valid attribute
-//~| ERROR diagnostic slug must be first argument
+//~^ ERROR unexpected literal in nested attribute, expected ident
 struct H {
     #[primary_span]
     span: Span,
@@ -102,7 +101,7 @@ struct H {
 
 #[derive(Subdiagnostic)]
 #[label(slug = 4)]
-//~^ ERROR `#[label(slug = ...)]` is not a valid attribute
+//~^ ERROR invalid nested attribute
 //~| ERROR diagnostic slug must be first argument
 struct J {
     #[primary_span]
@@ -112,7 +111,7 @@ struct J {
 
 #[derive(Subdiagnostic)]
 #[label(slug("..."))]
-//~^ ERROR `#[label(slug(...))]` is not a valid attribute
+//~^ ERROR invalid nested attribute
 //~| ERROR diagnostic slug must be first argument
 struct K {
     #[primary_span]
@@ -132,7 +131,7 @@ struct L {
 
 #[derive(Subdiagnostic)]
 #[label()]
-//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
+//~^ ERROR unexpected end of input, unexpected token in nested attribute, expected ident
 struct M {
     #[primary_span]
     span: Span,
@@ -141,7 +140,7 @@ struct M {
 
 #[derive(Subdiagnostic)]
 #[label(no_crate_example, code = "...")]
-//~^ ERROR `#[label(code = ...)]` is not a valid attribute
+//~^ ERROR invalid nested attribute
 struct N {
     #[primary_span]
     span: Span,
@@ -150,7 +149,7 @@ struct N {
 
 #[derive(Subdiagnostic)]
 #[label(no_crate_example, applicability = "machine-applicable")]
-//~^ ERROR `#[label(applicability = ...)]` is not a valid attribute
+//~^ ERROR invalid nested attribute
 struct O {
     #[primary_span]
     span: Span,
@@ -222,7 +221,7 @@ enum T {
 enum U {
     #[label(code = "...")]
     //~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
-    //~| ERROR `#[label(code = ...)]` is not a valid attribute
+    //~| ERROR invalid nested attribute
     A {
         #[primary_span]
         span: Span,
@@ -323,7 +322,7 @@ struct AD {
 
 #[derive(Subdiagnostic)]
 #[label(no_crate_example, no_crate::example)]
-//~^ ERROR `#[label(no_crate::example)]` is not a valid attribute
+//~^ ERROR a diagnostic slug must be the first argument to the attribute
 struct AE {
     #[primary_span]
     span: Span,
@@ -537,7 +536,7 @@ struct BA {
 #[derive(Subdiagnostic)]
 #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
 //~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields
-//~| ERROR `#[multipart_suggestion(code = ...)]` is not a valid attribute
+//~| ERROR invalid nested attribute
 struct BBa {
     var: String,
 }
@@ -554,7 +553,7 @@ struct BBb {
 #[multipart_suggestion(no_crate_example, applicability = "machine-applicable")]
 struct BBc {
     #[suggestion_part()]
-    //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
+    //~^ ERROR unexpected end of input, unexpected token in nested attribute, expected ident
     span1: Span,
 }
 
@@ -574,10 +573,11 @@ struct BD {
     //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
     span1: Span,
     #[suggestion_part()]
-    //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
+    //~^ ERROR unexpected end of input, unexpected token in nested attribute, expected ident
     span2: Span,
     #[suggestion_part(foo = "bar")]
-    //~^ ERROR `#[suggestion_part(foo = ...)]` is not a valid attribute
+    //~^ ERROR `code` is the only valid nested attribute
+    //~| ERROR expected `,`
     span4: Span,
     #[suggestion_part(code = "...")]
     //~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
@@ -669,6 +669,7 @@ enum BL {
 struct BM {
     #[suggestion_part(code("foo"))]
     //~^ ERROR expected exactly one string literal for `code = ...`
+    //~| ERROR unexpected token
     span: Span,
     r#type: String,
 }
@@ -678,6 +679,7 @@ struct BM {
 struct BN {
     #[suggestion_part(code("foo", "bar"))]
     //~^ ERROR expected exactly one string literal for `code = ...`
+    //~| ERROR unexpected token
     span: Span,
     r#type: String,
 }
@@ -687,6 +689,7 @@ struct BN {
 struct BO {
     #[suggestion_part(code(3))]
     //~^ ERROR expected exactly one string literal for `code = ...`
+    //~| ERROR unexpected token
     span: Span,
     r#type: String,
 }
@@ -701,10 +704,13 @@ struct BP {
 }
 
 #[derive(Subdiagnostic)]
+//~^ ERROR cannot find value `__code_29` in this scope
+//~| NOTE in this expansion
+//~| NOTE not found in this scope
 #[multipart_suggestion(no_crate_example)]
 struct BQ {
     #[suggestion_part(code = 3)]
-    //~^ ERROR `code = "..."`/`code(...)` must contain only string literals
+    //~^ ERROR expected string literal
     span: Span,
     r#type: String,
 }
@@ -779,7 +785,7 @@ struct SuggestionStyleInvalid1 {
 
 #[derive(Subdiagnostic)]
 #[suggestion(no_crate_example, code = "", style = 42)]
-//~^ ERROR `#[suggestion(style = ...)]` is not a valid attribute
+//~^ ERROR expected `= "xxx"`
 struct SuggestionStyleInvalid2 {
     #[primary_span]
     sub: Span,
@@ -787,7 +793,7 @@ struct SuggestionStyleInvalid2 {
 
 #[derive(Subdiagnostic)]
 #[suggestion(no_crate_example, code = "", style)]
-//~^ ERROR `#[suggestion(style)]` is not a valid attribute
+//~^ ERROR a diagnostic slug must be the first argument to the attribute
 struct SuggestionStyleInvalid3 {
     #[primary_span]
     sub: Span,
@@ -795,7 +801,8 @@ struct SuggestionStyleInvalid3 {
 
 #[derive(Subdiagnostic)]
 #[suggestion(no_crate_example, code = "", style("foo"))]
-//~^ ERROR `#[suggestion(style(...))]` is not a valid attribute
+//~^ ERROR expected `= "xxx"`
+//~| ERROr expected `,`
 struct SuggestionStyleInvalid4 {
     #[primary_span]
     sub: Span,
diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
index 343134af6bc1..4211b91f04a0 100644
--- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
@@ -26,11 +26,11 @@ error: `#[label = ...]` is not a valid attribute
 LL | #[label = "..."]
    | ^^^^^^^^^^^^^^^^
 
-error: `#[label(bug = ...)]` is not a valid attribute
+error: invalid nested attribute
   --> $DIR/subdiagnostic-derive.rs:84:9
    |
 LL | #[label(bug = "...")]
-   |         ^^^^^^^^^^^
+   |         ^^^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:84:1
@@ -38,110 +38,104 @@ error: diagnostic slug must be first argument of a `#[label(...)]` attribute
 LL | #[label(bug = "...")]
    | ^^^^^^^^^^^^^^^^^^^^^
 
-error: `#[label("...")]` is not a valid attribute
+error: unexpected literal in nested attribute, expected ident
   --> $DIR/subdiagnostic-derive.rs:94:9
    |
 LL | #[label("...")]
    |         ^^^^^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:94:1
-   |
-LL | #[label("...")]
-   | ^^^^^^^^^^^^^^^
-
-error: `#[label(slug = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:104:9
+error: invalid nested attribute
+  --> $DIR/subdiagnostic-derive.rs:103:9
    |
 LL | #[label(slug = 4)]
-   |         ^^^^^^^^
+   |         ^^^^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:104:1
+  --> $DIR/subdiagnostic-derive.rs:103:1
    |
 LL | #[label(slug = 4)]
    | ^^^^^^^^^^^^^^^^^^
 
-error: `#[label(slug(...))]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:114:9
+error: invalid nested attribute
+  --> $DIR/subdiagnostic-derive.rs:113:9
    |
 LL | #[label(slug("..."))]
-   |         ^^^^^^^^^^^
+   |         ^^^^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:114:1
+  --> $DIR/subdiagnostic-derive.rs:113:1
    |
 LL | #[label(slug("..."))]
    | ^^^^^^^^^^^^^^^^^^^^^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:134:1
+error: unexpected end of input, unexpected token in nested attribute, expected ident
+  --> $DIR/subdiagnostic-derive.rs:133:9
    |
 LL | #[label()]
-   | ^^^^^^^^^^
+   |         ^
 
-error: `#[label(code = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:143:27
+error: invalid nested attribute
+  --> $DIR/subdiagnostic-derive.rs:142:27
    |
 LL | #[label(no_crate_example, code = "...")]
-   |                           ^^^^^^^^^^^^
+   |                           ^^^^
 
-error: `#[label(applicability = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:152:27
+error: invalid nested attribute
+  --> $DIR/subdiagnostic-derive.rs:151:27
    |
 LL | #[label(no_crate_example, applicability = "machine-applicable")]
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                           ^^^^^^^^^^^^^
 
 error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:161:1
+  --> $DIR/subdiagnostic-derive.rs:160:1
    |
 LL | #[foo]
    | ^^^^^^
 
 error: `#[bar]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:175:5
+  --> $DIR/subdiagnostic-derive.rs:174:5
    |
 LL |     #[bar]
    |     ^^^^^^
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:187:5
+  --> $DIR/subdiagnostic-derive.rs:186:5
    |
 LL |     #[bar = "..."]
    |     ^^^^^^^^^^^^^^
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:199:5
+  --> $DIR/subdiagnostic-derive.rs:198:5
    |
 LL |     #[bar = 4]
    |     ^^^^^^^^^^
 
 error: `#[bar(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:211:5
+  --> $DIR/subdiagnostic-derive.rs:210:5
    |
 LL |     #[bar("...")]
    |     ^^^^^^^^^^^^^
 
-error: `#[label(code = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:223:13
+error: invalid nested attribute
+  --> $DIR/subdiagnostic-derive.rs:222:13
    |
 LL |     #[label(code = "...")]
-   |             ^^^^^^^^^^^^
+   |             ^^^^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:223:5
+  --> $DIR/subdiagnostic-derive.rs:222:5
    |
 LL |     #[label(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/subdiagnostic-derive.rs:252:5
+  --> $DIR/subdiagnostic-derive.rs:251:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: label without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:249:1
+  --> $DIR/subdiagnostic-derive.rs:248:1
    |
 LL | / #[label(no_crate_example)]
 LL | |
@@ -153,13 +147,13 @@ LL | | }
    | |_^
 
 error: `#[applicability]` is only valid on suggestions
-  --> $DIR/subdiagnostic-derive.rs:262:5
+  --> $DIR/subdiagnostic-derive.rs:261:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: `#[bar]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:272:5
+  --> $DIR/subdiagnostic-derive.rs:271:5
    |
 LL |     #[bar]
    |     ^^^^^^
@@ -167,13 +161,13 @@ LL |     #[bar]
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:283:5
+  --> $DIR/subdiagnostic-derive.rs:282:5
    |
 LL |     #[bar = "..."]
    |     ^^^^^^^^^^^^^^
 
 error: `#[bar(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:294:5
+  --> $DIR/subdiagnostic-derive.rs:293:5
    |
 LL |     #[bar("...")]
    |     ^^^^^^^^^^^^^
@@ -181,7 +175,7 @@ LL |     #[bar("...")]
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
 error: unexpected unsupported untagged union
-  --> $DIR/subdiagnostic-derive.rs:310:1
+  --> $DIR/subdiagnostic-derive.rs:309:1
    |
 LL | / union AC {
 LL | |
@@ -190,76 +184,74 @@ LL | |     b: u64,
 LL | | }
    | |_^
 
-error: `#[label(no_crate::example)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:325:27
+error: a diagnostic slug must be the first argument to the attribute
+  --> $DIR/subdiagnostic-derive.rs:324:44
    |
 LL | #[label(no_crate_example, no_crate::example)]
-   |                           ^^^^^^^^^^^^^^^^^
-   |
-   = help: a diagnostic slug must be the first argument to the attribute
+   |                                            ^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:338:5
+  --> $DIR/subdiagnostic-derive.rs:337:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:335:5
+  --> $DIR/subdiagnostic-derive.rs:334:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: subdiagnostic kind not specified
-  --> $DIR/subdiagnostic-derive.rs:344:8
+  --> $DIR/subdiagnostic-derive.rs:343:8
    |
 LL | struct AG {
    |        ^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:381:46
+  --> $DIR/subdiagnostic-derive.rs:380:46
    |
 LL | #[suggestion(no_crate_example, code = "...", code = "...")]
-   |                                              ^^^^^^^^^^^^
+   |                                              ^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:381:32
+  --> $DIR/subdiagnostic-derive.rs:380:32
    |
 LL | #[suggestion(no_crate_example, code = "...", code = "...")]
-   |                                ^^^^^^^^^^^^
+   |                                ^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:399:5
+  --> $DIR/subdiagnostic-derive.rs:398:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:396:5
+  --> $DIR/subdiagnostic-derive.rs:395:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
-  --> $DIR/subdiagnostic-derive.rs:409:5
+  --> $DIR/subdiagnostic-derive.rs:408:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: suggestion without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:422:1
+  --> $DIR/subdiagnostic-derive.rs:421:1
    |
 LL | #[suggestion(no_crate_example)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/subdiagnostic-derive.rs:432:46
+  --> $DIR/subdiagnostic-derive.rs:431:62
    |
 LL | #[suggestion(no_crate_example, code = "...", applicability = "foo")]
-   |                                              ^^^^^^^^^^^^^^^^^^^^^
+   |                                                              ^^^^^
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:450:1
+  --> $DIR/subdiagnostic-derive.rs:449:1
    |
 LL | / #[suggestion(no_crate_example, code = "...")]
 LL | |
@@ -269,25 +261,25 @@ LL | | }
    | |_^
 
 error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:464:1
+  --> $DIR/subdiagnostic-derive.rs:463:1
    |
 LL | #[label]
    | ^^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:484:39
+  --> $DIR/subdiagnostic-derive.rs:483:39
    |
 LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
    |                                       ^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:503:43
+  --> $DIR/subdiagnostic-derive.rs:502:43
    |
 LL |     #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
    |                                           ^^^^^^^
 
 error: `#[suggestion_part]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:526:5
+  --> $DIR/subdiagnostic-derive.rs:525:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
@@ -295,7 +287,7 @@ LL |     #[suggestion_part]
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
 
 error: `#[suggestion_part(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:529:5
+  --> $DIR/subdiagnostic-derive.rs:528:5
    |
 LL |     #[suggestion_part(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -303,7 +295,7 @@ LL |     #[suggestion_part(code = "...")]
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:523:1
+  --> $DIR/subdiagnostic-derive.rs:522:1
    |
 LL | / #[suggestion(no_crate_example, code = "...")]
 LL | |
@@ -314,16 +306,16 @@ LL | |     var: String,
 LL | | }
    | |_^
 
-error: `#[multipart_suggestion(code = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:538:42
+error: invalid nested attribute
+  --> $DIR/subdiagnostic-derive.rs:537:42
    |
 LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
-   |                                          ^^^^^^^^^^^^
+   |                                          ^^^^
    |
    = help: only `style` and `applicability` are valid nested attributes
 
 error: multipart suggestion without any `#[suggestion_part(...)]` fields
-  --> $DIR/subdiagnostic-derive.rs:538:1
+  --> $DIR/subdiagnostic-derive.rs:537:1
    |
 LL | / #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
 LL | |
@@ -334,19 +326,19 @@ LL | | }
    | |_^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:548:5
+  --> $DIR/subdiagnostic-derive.rs:547:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
 
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:556:5
+error: unexpected end of input, unexpected token in nested attribute, expected ident
+  --> $DIR/subdiagnostic-derive.rs:555:23
    |
 LL |     #[suggestion_part()]
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |                       ^
 
 error: `#[primary_span]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:565:5
+  --> $DIR/subdiagnostic-derive.rs:564:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
@@ -354,7 +346,7 @@ LL |     #[primary_span]
    = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
 
 error: multipart suggestion without any `#[suggestion_part(...)]` fields
-  --> $DIR/subdiagnostic-derive.rs:562:1
+  --> $DIR/subdiagnostic-derive.rs:561:1
    |
 LL | / #[multipart_suggestion(no_crate_example)]
 LL | |
@@ -366,24 +358,16 @@ LL | | }
    | |_^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:573:5
+  --> $DIR/subdiagnostic-derive.rs:572:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
 
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:576:5
-   |
-LL |     #[suggestion_part()]
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: `#[suggestion_part(foo = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:579:23
+error: `code` is the only valid nested attribute
+  --> $DIR/subdiagnostic-derive.rs:578:23
    |
 LL |     #[suggestion_part(foo = "bar")]
-   |                       ^^^^^^^^^^^
-   |
-   = help: `code` is the only valid nested attribute
+   |                       ^^^
 
 error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/subdiagnostic-derive.rs:582:5
@@ -397,17 +381,29 @@ error: the `#[suggestion_part(...)]` attribute can only be applied to fields of
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
+error: unexpected end of input, unexpected token in nested attribute, expected ident
+  --> $DIR/subdiagnostic-derive.rs:575:23
+   |
+LL |     #[suggestion_part()]
+   |                       ^
+
+error: expected `,`
+  --> $DIR/subdiagnostic-derive.rs:578:27
+   |
+LL |     #[suggestion_part(foo = "bar")]
+   |                           ^
+
 error: specified multiple times
   --> $DIR/subdiagnostic-derive.rs:593:37
    |
 LL |     #[suggestion_part(code = "...", code = ",,,")]
-   |                                     ^^^^^^^^^^^^
+   |                                     ^^^^
    |
 note: previously specified here
   --> $DIR/subdiagnostic-derive.rs:593:23
    |
 LL |     #[suggestion_part(code = "...", code = ",,,")]
-   |                       ^^^^^^^^^^^^
+   |                       ^^^^
 
 error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
   --> $DIR/subdiagnostic-derive.rs:622:5
@@ -416,49 +412,67 @@ LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: expected exactly one string literal for `code = ...`
-  --> $DIR/subdiagnostic-derive.rs:670:23
+  --> $DIR/subdiagnostic-derive.rs:670:34
    |
 LL |     #[suggestion_part(code("foo"))]
-   |                       ^^^^^^^^^^^
+   |                                  ^
+
+error: unexpected token
+  --> $DIR/subdiagnostic-derive.rs:670:28
+   |
+LL |     #[suggestion_part(code("foo"))]
+   |                            ^^^^^
 
 error: expected exactly one string literal for `code = ...`
-  --> $DIR/subdiagnostic-derive.rs:679:23
+  --> $DIR/subdiagnostic-derive.rs:680:41
    |
 LL |     #[suggestion_part(code("foo", "bar"))]
-   |                       ^^^^^^^^^^^^^^^^^^
+   |                                         ^
+
+error: unexpected token
+  --> $DIR/subdiagnostic-derive.rs:680:28
+   |
+LL |     #[suggestion_part(code("foo", "bar"))]
+   |                            ^^^^^
 
 error: expected exactly one string literal for `code = ...`
-  --> $DIR/subdiagnostic-derive.rs:688:23
+  --> $DIR/subdiagnostic-derive.rs:690:30
    |
 LL |     #[suggestion_part(code(3))]
-   |                       ^^^^^^^
+   |                              ^
+
+error: unexpected token
+  --> $DIR/subdiagnostic-derive.rs:690:28
+   |
+LL |     #[suggestion_part(code(3))]
+   |                            ^
 
 error: expected exactly one string literal for `code = ...`
-  --> $DIR/subdiagnostic-derive.rs:697:23
+  --> $DIR/subdiagnostic-derive.rs:700:29
    |
 LL |     #[suggestion_part(code())]
-   |                       ^^^^^^
+   |                             ^
 
-error: `code = "..."`/`code(...)` must contain only string literals
-  --> $DIR/subdiagnostic-derive.rs:706:23
+error: expected string literal
+  --> $DIR/subdiagnostic-derive.rs:712:30
    |
 LL |     #[suggestion_part(code = 3)]
-   |                       ^^^^^^^^
+   |                              ^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:748:61
+  --> $DIR/subdiagnostic-derive.rs:754:1
    |
 LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")]
-   |                                                             ^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:748:43
+  --> $DIR/subdiagnostic-derive.rs:754:1
    |
 LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")]
-   |                                           ^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_hidden(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:757:1
+  --> $DIR/subdiagnostic-derive.rs:763:1
    |
 LL | #[suggestion_hidden(no_crate_example, code = "")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -466,7 +480,7 @@ LL | #[suggestion_hidden(no_crate_example, code = "")]
    = help: Use `#[suggestion(..., style = "hidden")]` instead
 
 error: `#[suggestion_hidden(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:765:1
+  --> $DIR/subdiagnostic-derive.rs:771:1
    |
 LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -474,35 +488,39 @@ LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")]
    = help: Use `#[suggestion(..., style = "hidden")]` instead
 
 error: invalid suggestion style
-  --> $DIR/subdiagnostic-derive.rs:773:51
+  --> $DIR/subdiagnostic-derive.rs:779:51
    |
 LL | #[suggestion(no_crate_example, code = "", style = "foo")]
    |                                                   ^^^^^
    |
    = help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`
 
-error: `#[suggestion(style = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:781:43
+error: expected `= "xxx"`
+  --> $DIR/subdiagnostic-derive.rs:787:49
    |
 LL | #[suggestion(no_crate_example, code = "", style = 42)]
-   |                                           ^^^^^^^^^^
+   |                                                 ^
 
-error: `#[suggestion(style)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:789:43
+error: a diagnostic slug must be the first argument to the attribute
+  --> $DIR/subdiagnostic-derive.rs:795:48
    |
 LL | #[suggestion(no_crate_example, code = "", style)]
-   |                                           ^^^^^
-   |
-   = help: a diagnostic slug must be the first argument to the attribute
+   |                                                ^
 
-error: `#[suggestion(style(...))]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:797:43
+error: expected `= "xxx"`
+  --> $DIR/subdiagnostic-derive.rs:803:48
    |
 LL | #[suggestion(no_crate_example, code = "", style("foo"))]
-   |                                           ^^^^^^^^^^^^
+   |                                                ^
+
+error: expected `,`
+  --> $DIR/subdiagnostic-derive.rs:803:48
+   |
+LL | #[suggestion(no_crate_example, code = "", style("foo"))]
+   |                                                ^
 
 error: `#[primary_span]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:808:5
+  --> $DIR/subdiagnostic-derive.rs:815:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
@@ -511,7 +529,7 @@ LL |     #[primary_span]
    = help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:805:1
+  --> $DIR/subdiagnostic-derive.rs:812:1
    |
 LL | / #[suggestion(no_crate_example, code = "")]
 LL | |
@@ -529,59 +547,67 @@ LL | #[foo]
    |   ^^^
 
 error: cannot find attribute `foo` in this scope
-  --> $DIR/subdiagnostic-derive.rs:161:3
+  --> $DIR/subdiagnostic-derive.rs:160:3
    |
 LL | #[foo]
    |   ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:175:7
+  --> $DIR/subdiagnostic-derive.rs:174:7
    |
 LL |     #[bar]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:187:7
+  --> $DIR/subdiagnostic-derive.rs:186:7
    |
 LL |     #[bar = "..."]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:199:7
+  --> $DIR/subdiagnostic-derive.rs:198:7
    |
 LL |     #[bar = 4]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:211:7
+  --> $DIR/subdiagnostic-derive.rs:210:7
    |
 LL |     #[bar("...")]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:272:7
+  --> $DIR/subdiagnostic-derive.rs:271:7
    |
 LL |     #[bar]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:283:7
+  --> $DIR/subdiagnostic-derive.rs:282:7
    |
 LL |     #[bar = "..."]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:294:7
+  --> $DIR/subdiagnostic-derive.rs:293:7
    |
 LL |     #[bar("...")]
    |       ^^^
 
 error[E0425]: cannot find value `slug` in module `crate::fluent_generated`
-  --> $DIR/subdiagnostic-derive.rs:124:9
+  --> $DIR/subdiagnostic-derive.rs:123:9
    |
 LL | #[label(slug)]
    |         ^^^^ not found in `crate::fluent_generated`
 
-error: aborting due to 81 previous errors
+error[E0425]: cannot find value `__code_29` in this scope
+  --> $DIR/subdiagnostic-derive.rs:706:10
+   |
+LL | #[derive(Subdiagnostic)]
+   |          ^^^^^^^^^^^^^ not found in this scope
+   |
+   = note: this error originates in the derive macro `Subdiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 86 previous errors
 
 For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index 99b653f20b63..03dab2350402 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -1,7 +1,7 @@
 // run-pass
 // Test that users are able to use stable mir APIs to retrieve information of the current crate
 
-// ignore-stage-1
+// ignore-stage1
 // ignore-cross-compile
 // ignore-remote
 // edition: 2021
diff --git a/tests/ui/abi/stack-probes-lto.rs b/tests/ui/abi/stack-probes-lto.rs
index a455eef42eac..039507d51040 100644
--- a/tests/ui/abi/stack-probes-lto.rs
+++ b/tests/ui/abi/stack-probes-lto.rs
@@ -9,7 +9,6 @@
 // ignore-emscripten no processes
 // ignore-sgx no processes
 // ignore-musl FIXME #31506
-// ignore-pretty
 // ignore-fuchsia no exception handler registered for segfault
 // compile-flags: -C lto
 // no-prefer-dynamic
diff --git a/tests/ui/argument-suggestions/issue-109425.fixed b/tests/ui/argument-suggestions/issue-109425.fixed
new file mode 100644
index 000000000000..143ddf99586f
--- /dev/null
+++ b/tests/ui/argument-suggestions/issue-109425.fixed
@@ -0,0 +1,20 @@
+// run-rustfix
+
+fn f() {}
+fn i(_: u32) {}
+fn is(_: u32, _: &str) {}
+fn s(_: &str) {}
+
+fn main() {
+    // code             expected suggestion
+    f();        // f()
+    //~^ error: this function takes 0 arguments but 2 arguments were supplied
+    i(0,);     // i(0,)
+    //~^ error: this function takes 1 argument but 3 arguments were supplied
+    i(0);      // i(0)
+    //~^ error: this function takes 1 argument but 3 arguments were supplied
+    is(0, ""); // is(0, "")
+    //~^ error: this function takes 2 arguments but 4 arguments were supplied
+    s("");     // s("")
+    //~^ error: this function takes 1 argument but 3 arguments were supplied
+}
diff --git a/tests/ui/argument-suggestions/issue-109425.rs b/tests/ui/argument-suggestions/issue-109425.rs
new file mode 100644
index 000000000000..a845c419555c
--- /dev/null
+++ b/tests/ui/argument-suggestions/issue-109425.rs
@@ -0,0 +1,20 @@
+// run-rustfix
+
+fn f() {}
+fn i(_: u32) {}
+fn is(_: u32, _: &str) {}
+fn s(_: &str) {}
+
+fn main() {
+    // code             expected suggestion
+    f(0, 1,);        // f()
+    //~^ error: this function takes 0 arguments but 2 arguments were supplied
+    i(0, 1, 2,);     // i(0,)
+    //~^ error: this function takes 1 argument but 3 arguments were supplied
+    i(0, 1, 2);      // i(0)
+    //~^ error: this function takes 1 argument but 3 arguments were supplied
+    is(0, 1, 2, ""); // is(0, "")
+    //~^ error: this function takes 2 arguments but 4 arguments were supplied
+    s(0, 1, "");     // s("")
+    //~^ error: this function takes 1 argument but 3 arguments were supplied
+}
diff --git a/tests/ui/argument-suggestions/issue-109425.stderr b/tests/ui/argument-suggestions/issue-109425.stderr
new file mode 100644
index 000000000000..1514f1cb487e
--- /dev/null
+++ b/tests/ui/argument-suggestions/issue-109425.stderr
@@ -0,0 +1,98 @@
+error[E0061]: this function takes 0 arguments but 2 arguments were supplied
+  --> $DIR/issue-109425.rs:10:5
+   |
+LL |     f(0, 1,);        // f()
+   |     ^ -  - unexpected argument of type `{integer}`
+   |       |
+   |       unexpected argument of type `{integer}`
+   |
+note: function defined here
+  --> $DIR/issue-109425.rs:3:4
+   |
+LL | fn f() {}
+   |    ^
+help: remove the extra arguments
+   |
+LL -     f(0, 1,);        // f()
+LL +     f();        // f()
+   |
+
+error[E0061]: this function takes 1 argument but 3 arguments were supplied
+  --> $DIR/issue-109425.rs:12:5
+   |
+LL |     i(0, 1, 2,);     // i(0,)
+   |     ^    -  - unexpected argument of type `{integer}`
+   |          |
+   |          unexpected argument of type `{integer}`
+   |
+note: function defined here
+  --> $DIR/issue-109425.rs:4:4
+   |
+LL | fn i(_: u32) {}
+   |    ^ ------
+help: remove the extra arguments
+   |
+LL -     i(0, 1, 2,);     // i(0,)
+LL +     i(0,);     // i(0,)
+   |
+
+error[E0061]: this function takes 1 argument but 3 arguments were supplied
+  --> $DIR/issue-109425.rs:14:5
+   |
+LL |     i(0, 1, 2);      // i(0)
+   |     ^    -  - unexpected argument of type `{integer}`
+   |          |
+   |          unexpected argument of type `{integer}`
+   |
+note: function defined here
+  --> $DIR/issue-109425.rs:4:4
+   |
+LL | fn i(_: u32) {}
+   |    ^ ------
+help: remove the extra arguments
+   |
+LL -     i(0, 1, 2);      // i(0)
+LL +     i(0);      // i(0)
+   |
+
+error[E0061]: this function takes 2 arguments but 4 arguments were supplied
+  --> $DIR/issue-109425.rs:16:5
+   |
+LL |     is(0, 1, 2, ""); // is(0, "")
+   |     ^^    -  - unexpected argument of type `{integer}`
+   |           |
+   |           unexpected argument of type `{integer}`
+   |
+note: function defined here
+  --> $DIR/issue-109425.rs:5:4
+   |
+LL | fn is(_: u32, _: &str) {}
+   |    ^^ ------  -------
+help: remove the extra arguments
+   |
+LL -     is(0, 1, 2, ""); // is(0, "")
+LL +     is(0, ""); // is(0, "")
+   |
+
+error[E0061]: this function takes 1 argument but 3 arguments were supplied
+  --> $DIR/issue-109425.rs:18:5
+   |
+LL |     s(0, 1, "");     // s("")
+   |     ^ -  - unexpected argument of type `{integer}`
+   |       |
+   |       unexpected argument of type `{integer}`
+   |
+note: function defined here
+  --> $DIR/issue-109425.rs:6:4
+   |
+LL | fn s(_: &str) {}
+   |    ^ -------
+help: remove the extra arguments
+   |
+LL -     s(0, 1, "");     // s("")
+LL +     s("");     // s("")
+   |
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs
index 75aa25906aa0..2f9a1d1c76e0 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs
+++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs
@@ -10,11 +10,13 @@ trait Trait {
 
 fn foo>() {}
 //~^ ERROR argument types not allowed with return type notation
+//~| ERROR associated type bounds are unstable
 
 fn bar (): Send>>() {}
 //~^ ERROR return type not allowed with return type notation
 
 fn baz>() {}
 //~^ ERROR return type notation arguments must be elided with `..`
+//~| ERROR associated type bounds are unstable
 
 fn main() {}
diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr
index 5b075a0fa292..b354a6805d6e 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr
@@ -1,9 +1,27 @@
 error: return type not allowed with return type notation
-  --> $DIR/bad-inputs-and-output.rs:14:28
+  --> $DIR/bad-inputs-and-output.rs:15:28
    |
 LL | fn bar (): Send>>() {}
    |                            ^^^^^ help: remove the return type
 
+error[E0658]: associated type bounds are unstable
+  --> $DIR/bad-inputs-and-output.rs:11:17
+   |
+LL | fn foo>() {}
+   |                 ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #52662  for more information
+   = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
+
+error[E0658]: associated type bounds are unstable
+  --> $DIR/bad-inputs-and-output.rs:18:17
+   |
+LL | fn baz>() {}
+   |                 ^^^^^^^^^^^^^^
+   |
+   = note: see issue #52662  for more information
+   = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
+
 warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/bad-inputs-and-output.rs:3:12
    |
@@ -28,10 +46,11 @@ LL | fn foo>() {}
    |                       ^^^^^ help: remove the input types: `(..)`
 
 error: return type notation arguments must be elided with `..`
-  --> $DIR/bad-inputs-and-output.rs:17:23
+  --> $DIR/bad-inputs-and-output.rs:18:23
    |
 LL | fn baz>() {}
    |                       ^^ help: add `..`: `(..)`
 
-error: aborting due to 3 previous errors; 2 warnings emitted
+error: aborting due to 5 previous errors; 2 warnings emitted
 
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.rs b/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.rs
new file mode 100644
index 000000000000..9129f37e0c6b
--- /dev/null
+++ b/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.rs
@@ -0,0 +1,11 @@
+// edition: 2021
+// compile-flags: -Zunpretty=expanded
+
+trait Trait {
+    async fn method() {}
+}
+
+fn foo>() {}
+//~^ ERROR associated type bounds are unstable
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stderr b/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stderr
new file mode 100644
index 000000000000..77e015b4160b
--- /dev/null
+++ b/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stderr
@@ -0,0 +1,12 @@
+error[E0658]: associated type bounds are unstable
+  --> $DIR/unpretty-parenthesized.rs:8:17
+   |
+LL | fn foo>() {}
+   |                 ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #52662  for more information
+   = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stdout b/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stdout
new file mode 100644
index 000000000000..b3dea8f6eca7
--- /dev/null
+++ b/tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.stdout
@@ -0,0 +1,15 @@
+#![feature(prelude_import)]
+#[prelude_import]
+use std::prelude::rust_2021::*;
+#[macro_use]
+extern crate std;
+// edition: 2021
+// compile-flags: -Zunpretty=expanded
+
+trait Trait {
+    async fn method() {}
+}
+
+fn foo>() {}
+
+fn main() {}
diff --git a/tests/ui/attributes/issue-105594-invalid-attr-validation.rs b/tests/ui/attributes/issue-105594-invalid-attr-validation.rs
index 6c68e6b046f0..096ce97ab048 100644
--- a/tests/ui/attributes/issue-105594-invalid-attr-validation.rs
+++ b/tests/ui/attributes/issue-105594-invalid-attr-validation.rs
@@ -1,7 +1,7 @@
 // This checks that the attribute validation ICE in issue #105594 doesn't
 // recur.
 //
-// ignore-thumbv8m.base
+// ignore-thumbv8m.base-none-eabi
 #![feature(cmse_nonsecure_entry)]
 
 fn main() {}
diff --git a/tests/ui/binding/optional_comma_in_match_arm.rs b/tests/ui/binding/optional_comma_in_match_arm.rs
index fc268bf2a45a..71e2f07bb6b0 100644
--- a/tests/ui/binding/optional_comma_in_match_arm.rs
+++ b/tests/ui/binding/optional_comma_in_match_arm.rs
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(unused_unsafe)]
-// ignore-pretty issue #37199
 #![allow(while_true)]
 
 fn main() {
diff --git a/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
index 5835f06753bb..0ca14c3f3bc6 100644
--- a/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
+++ b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
@@ -2,18 +2,16 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:36:9
    |
 LL |         ref foo @ [.., ref mut bar] => (),
-   |         -------^^^^^^^^-----------^
-   |         |              |
-   |         |              value is mutably borrowed by `bar` here
+   |         ^^^^^^^        ----------- value is mutably borrowed by `bar` here
+   |         |
    |         value is borrowed by `foo` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:120:9
    |
 LL |         ref foo @ Some(box ref mut s) => (),
-   |         -------^^^^^^^^^^^^---------^
-   |         |                  |
-   |         |                  value is mutably borrowed by `s` here
+   |         ^^^^^^^            --------- value is mutably borrowed by `s` here
+   |         |
    |         value is borrowed by `foo` here
 
 error[E0382]: borrow of moved value: `x`
diff --git a/tests/ui/borrowck/borrowck-pat-enum.rs b/tests/ui/borrowck/borrowck-pat-enum.rs
index 7f9c5544d0bd..6e51a2b2e027 100644
--- a/tests/ui/borrowck/borrowck-pat-enum.rs
+++ b/tests/ui/borrowck/borrowck-pat-enum.rs
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(dead_code)]
-// ignore-pretty issue #37199
 
 fn match_ref(v: Option) -> isize {
     match v {
diff --git a/tests/ui/chalkify/bugs/async.stderr b/tests/ui/chalkify/bugs/async.stderr
index 9c559640b230..36606fd49f27 100644
--- a/tests/ui/chalkify/bugs/async.stderr
+++ b/tests/ui/chalkify/bugs/async.stderr
@@ -14,14 +14,15 @@ LL | async fn foo(x: u32) -> u32 {
    |                         ^^^query stack during panic:
 #0 [typeck] type-checking `foo`
 #1 [thir_body] building THIR for `foo`
-#2 [mir_built] building MIR for `foo`
-#3 [unsafety_check_result] unsafety-checking `foo`
-#4 [mir_const] preparing `foo` for borrow checking
-#5 [mir_promoted] processing MIR for `foo`
-#6 [mir_borrowck] borrow-checking `foo`
-#7 [type_of] computing type of `foo::{opaque#0}`
-#8 [check_mod_item_types] checking item types in top-level module
-#9 [analysis] running analysis passes on this crate
+#2 [check_match] match-checking `foo`
+#3 [mir_built] building MIR for `foo`
+#4 [unsafety_check_result] unsafety-checking `foo`
+#5 [mir_const] preparing `foo` for borrow checking
+#6 [mir_promoted] processing MIR for `foo`
+#7 [mir_borrowck] borrow-checking `foo`
+#8 [type_of] computing type of `foo::{opaque#0}`
+#9 [check_mod_item_types] checking item types in top-level module
+#10 [analysis] running analysis passes on this crate
 end of query stack
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/command/command-exec.rs b/tests/ui/command/command-exec.rs
index 032dad1840d4..edc33446d79b 100644
--- a/tests/ui/command/command-exec.rs
+++ b/tests/ui/command/command-exec.rs
@@ -2,7 +2,6 @@
 
 #![allow(stable_features)]
 // ignore-windows - this is a unix-specific test
-// ignore-pretty issue #37199
 // ignore-emscripten no processes
 // ignore-sgx no processes
 // ignore-fuchsia no execvp syscall provided
diff --git a/tests/ui/const-generics/defaults/doesnt_infer.stderr b/tests/ui/const-generics/defaults/doesnt_infer.stderr
index 227b2f402236..a61411d6eb6e 100644
--- a/tests/ui/const-generics/defaults/doesnt_infer.stderr
+++ b/tests/ui/const-generics/defaults/doesnt_infer.stderr
@@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `Foo`
 LL |     let foo = Foo::foo();
    |         ^^^
    |
-help: consider giving `foo` an explicit type, where the the value of const parameter `N` is specified
+help: consider giving `foo` an explicit type, where the value of const parameter `N` is specified
    |
 LL |     let foo: Foo = Foo::foo();
    |            ++++++++
diff --git a/tests/ui/const-generics/transmute-fail.rs b/tests/ui/const-generics/transmute-fail.rs
new file mode 100644
index 000000000000..d7bf1b47fb5a
--- /dev/null
+++ b/tests/ui/const-generics/transmute-fail.rs
@@ -0,0 +1,35 @@
+#![feature(transmute_generic_consts)]
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo(v: [[u32;H+1]; W]) -> [[u32; W+1]; H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute
+  }
+}
+
+fn bar(v: [[u32; H]; W]) -> [[u32; W]; H] {
+  //~^ ERROR mismatched types
+  //~| ERROR mismatched types
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute between types
+  }
+}
+
+fn baz(v: [[u32; H]; W]) -> [u32; W * H * H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute
+  }
+}
+
+fn overflow(v: [[[u32; 8888888]; 9999999]; 777777777]) -> [[[u32; 9999999]; 777777777]; 8888888] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute
+  }
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr
new file mode 100644
index 000000000000..41b098135e81
--- /dev/null
+++ b/tests/ui/const-generics/transmute-fail.stderr
@@ -0,0 +1,52 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:7:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[u32; H+1]; W]` (generic size [const expr])
+   = note: target type: `[[u32; W+1]; H]` (generic size [const expr])
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:16:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[u32; H]; W]` (this type does not have a fixed size)
+   = note: target type: `[[u32; W]; H]` (size can vary because of [u32; W])
+
+error[E0308]: mismatched types
+  --> $DIR/transmute-fail.rs:12:53
+   |
+LL | fn bar(v: [[u32; H]; W]) -> [[u32; W]; H] {
+   |                                                     ^ expected `usize`, found `bool`
+
+error[E0308]: mismatched types
+  --> $DIR/transmute-fail.rs:12:67
+   |
+LL | fn bar(v: [[u32; H]; W]) -> [[u32; W]; H] {
+   |                                                                   ^ expected `usize`, found `bool`
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:23:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[u32; H]; W]` (generic size [const expr])
+   = note: target type: `[u32; W * H * H]` (generic size [const expr])
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:30:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[[u32; 8888888]; 9999999]; 777777777]` are too big for the current architecture)
+   = note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[[u32; 9999999]; 777777777]; 8888888]` are too big for the current architecture)
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0512.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/transmute.rs b/tests/ui/const-generics/transmute.rs
new file mode 100644
index 000000000000..30560a95b5e1
--- /dev/null
+++ b/tests/ui/const-generics/transmute.rs
@@ -0,0 +1,83 @@
+// run-pass
+#![feature(generic_const_exprs)]
+#![feature(transmute_generic_consts)]
+#![allow(incomplete_features)]
+
+fn transpose(v: [[u32;H]; W]) -> [[u32; W]; H] {
+  unsafe {
+    std::mem::transmute(v)
+  }
+}
+
+fn ident(v: [[u32; H]; W]) -> [[u32; H]; W] {
+  unsafe {
+    std::mem::transmute(v)
+  }
+}
+
+fn flatten(v: [[u32; H]; W]) -> [u32; W * H] {
+  unsafe {
+    std::mem::transmute(v)
+  }
+}
+
+fn coagulate(v: [u32; H*W]) -> [[u32; W];H] {
+  unsafe {
+    std::mem::transmute(v)
+  }
+}
+
+fn flatten_3d(
+  v: [[[u32; D]; H]; W]
+) -> [u32; D * W * H] {
+  unsafe {
+    std::mem::transmute(v)
+  }
+}
+
+fn flatten_somewhat(
+  v: [[[u32; D]; H]; W]
+) -> [[u32; D * W]; H] {
+  unsafe {
+    std::mem::transmute(v)
+  }
+}
+
+fn known_size(v: [u16; L]) -> [u8; L * 2] {
+  unsafe {
+    std::mem::transmute(v)
+  }
+}
+
+fn condense_bytes(v: [u8; L * 2]) -> [u16; L] {
+  unsafe {
+    std::mem::transmute(v)
+  }
+}
+
+fn singleton_each(v: [u8; L]) -> [[u8;1]; L] {
+  unsafe {
+    std::mem::transmute(v)
+  }
+}
+
+fn transpose_with_const(
+  v: [[u32; 2 * H]; W + W]
+) -> [[u32; W + W]; 2 * H] {
+  unsafe {
+    std::mem::transmute(v)
+  }
+}
+
+fn main() {
+  let _ = transpose([[0; 8]; 16]);
+  let _ = transpose_with_const::<8,4>([[0; 8]; 16]);
+  let _ = ident([[0; 8]; 16]);
+  let _ = flatten([[0; 13]; 5]);
+  let _: [[_; 5]; 13] = coagulate([0; 65]);
+  let _ = flatten_3d([[[0; 3]; 13]; 5]);
+  let _ = flatten_somewhat([[[0; 3]; 13]; 5]);
+  let _ = known_size([16; 13]);
+  let _: [u16; 5] = condense_bytes([16u8; 10]);
+  let _ = singleton_each([16; 10]);
+}
diff --git a/tests/ui/const-generics/transmute_no_gate.rs b/tests/ui/const-generics/transmute_no_gate.rs
new file mode 100644
index 000000000000..e1ac44390a5f
--- /dev/null
+++ b/tests/ui/const-generics/transmute_no_gate.rs
@@ -0,0 +1,91 @@
+// gate-test-transmute_generic_consts
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn transpose(v: [[u32;H]; W]) -> [[u32; W]; H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute
+  }
+}
+
+fn ident(v: [[u32; H]; W]) -> [[u32; H]; W] {
+  unsafe {
+    std::mem::transmute(v)
+  }
+}
+
+fn flatten(v: [[u32; H]; W]) -> [u32; W * H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute
+  }
+}
+
+fn coagulate(v: [u32; H*W]) -> [[u32; W];H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute
+  }
+}
+
+fn flatten_3d(
+  v: [[[u32; D]; H]; W]
+) -> [u32; D * W * H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute
+  }
+}
+
+fn flatten_somewhat(
+  v: [[[u32; D]; H]; W]
+) -> [[u32; D * W]; H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute
+  }
+}
+
+fn known_size(v: [u16; L]) -> [u8; L * 2] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute
+  }
+}
+
+fn condense_bytes(v: [u8; L * 2]) -> [u16; L] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute
+  }
+}
+
+fn singleton_each(v: [u8; L]) -> [[u8;1]; L] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute
+  }
+}
+
+fn transpose_with_const(
+  v: [[u32; 2 * H]; W + W]
+) -> [[u32; W + W]; 2 * H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR cannot transmute
+  }
+}
+
+fn main() {
+  let _ = transpose([[0; 8]; 16]);
+  let _ = transpose_with_const::<8,4>([[0; 8]; 16]);
+  let _ = ident([[0; 8]; 16]);
+  let _ = flatten([[0; 13]; 5]);
+  let _: [[_; 5]; 13] = coagulate([0; 65]);
+  let _ = flatten_3d([[[0; 3]; 13]; 5]);
+  let _ = flatten_somewhat([[[0; 3]; 13]; 5]);
+  let _ = known_size([16; 13]);
+  let _: [u16; 5] = condense_bytes([16u8; 10]);
+  let _ = singleton_each([16; 10]);
+}
diff --git a/tests/ui/const-generics/transmute_no_gate.stderr b/tests/ui/const-generics/transmute_no_gate.stderr
new file mode 100644
index 000000000000..9c271b34849c
--- /dev/null
+++ b/tests/ui/const-generics/transmute_no_gate.stderr
@@ -0,0 +1,84 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute_no_gate.rs:7:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[u32; H]; W]` (this type does not have a fixed size)
+   = note: target type: `[[u32; W]; H]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute_no_gate.rs:20:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[u32; H]; W]` (this type does not have a fixed size)
+   = note: target type: `[u32; W * H]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute_no_gate.rs:27:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u32; H*W]` (this type does not have a fixed size)
+   = note: target type: `[[u32; W]; H]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute_no_gate.rs:36:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[[u32; D]; H]; W]` (this type does not have a fixed size)
+   = note: target type: `[u32; D * W * H]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute_no_gate.rs:45:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[[u32; D]; H]; W]` (this type does not have a fixed size)
+   = note: target type: `[[u32; D * W]; H]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute_no_gate.rs:52:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u16; L]` (this type does not have a fixed size)
+   = note: target type: `[u8; L * 2]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute_no_gate.rs:59:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; L * 2]` (this type does not have a fixed size)
+   = note: target type: `[u16; L]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute_no_gate.rs:66:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; L]` (this type does not have a fixed size)
+   = note: target type: `[[u8; 1]; L]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute_no_gate.rs:75:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[u32; 2 * H]; W + W]` (this type does not have a fixed size)
+   = note: target type: `[[u32; W + W]; 2 * H]` (this type does not have a fixed size)
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0512`.
diff --git a/tests/ui/const_prop/issue-86351.rs b/tests/ui/const_prop/issue-86351.rs
new file mode 100644
index 000000000000..b5f1e7f7449a
--- /dev/null
+++ b/tests/ui/const_prop/issue-86351.rs
@@ -0,0 +1,22 @@
+// compile-flags: --crate-type=lib -Zmir-opt-level=2
+// build-pass
+// ^-- Must be build-pass, because check-pass will not run const prop.
+
+pub trait TestTrait {
+    type MyType;
+    fn func() -> Option
+    where
+        Self: Sized;
+}
+
+impl dyn TestTrait
+where
+    Self: Sized,
+{
+    pub fn other_func() -> Option {
+        match Self::func() {
+            Some(me) => Some(me),
+            None => None,
+        }
+    }
+}
diff --git a/tests/ui/const_prop/unreachable-bounds.rs b/tests/ui/const_prop/unreachable-bounds.rs
new file mode 100644
index 000000000000..8cf98e154eaa
--- /dev/null
+++ b/tests/ui/const_prop/unreachable-bounds.rs
@@ -0,0 +1,6 @@
+// Use `build-pass` to ensure const-prop lint runs.
+// build-pass
+
+fn main() {
+    [()][if false { 1 } else { return }]
+}
diff --git a/tests/ui/const_prop/unreachable-overflow.rs b/tests/ui/const_prop/unreachable-overflow.rs
new file mode 100644
index 000000000000..2875135424d2
--- /dev/null
+++ b/tests/ui/const_prop/unreachable-overflow.rs
@@ -0,0 +1,10 @@
+// Use `build-pass` to ensure const-prop lint runs.
+// build-pass
+
+fn main() {
+    let x = 2u32;
+    let y = 3u32;
+    if y <= x {
+        dbg!(x - y);
+    }
+}
diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.rs b/tests/ui/consts/const-eval/const-eval-overflow-2.rs
index 535d91359163..c19a0c443ec5 100644
--- a/tests/ui/consts/const-eval/const-eval-overflow-2.rs
+++ b/tests/ui/consts/const-eval/const-eval-overflow-2.rs
@@ -14,7 +14,6 @@ fn main() {
     match -128i8 {
         NEG_NEG_128 => println!("A"),
         //~^ ERROR could not evaluate constant pattern
-        //~| ERROR could not evaluate constant pattern
         _ => println!("B"),
     }
 }
diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr
index 7b1fe49d4346..fc0baf11051b 100644
--- a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr
+++ b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr
@@ -10,12 +10,6 @@ error: could not evaluate constant pattern
 LL |         NEG_NEG_128 => println!("A"),
    |         ^^^^^^^^^^^
 
-error: could not evaluate constant pattern
-  --> $DIR/const-eval-overflow-2.rs:15:9
-   |
-LL |         NEG_NEG_128 => println!("A"),
-   |         ^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr
index 032ceb2467c2..eaa2d6b27945 100644
--- a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr
+++ b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ref_to_int_match.rs:25:27
+  --> $DIR/ref_to_int_match.rs:24:27
    |
 LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
    |                           ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -13,12 +13,6 @@ error: could not evaluate constant pattern
 LL |         10..=BAR => {},
    |              ^^^
 
-error: could not evaluate constant pattern
-  --> $DIR/ref_to_int_match.rs:7:14
-   |
-LL |         10..=BAR => {},
-   |              ^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr
index 032ceb2467c2..eaa2d6b27945 100644
--- a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr
+++ b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ref_to_int_match.rs:25:27
+  --> $DIR/ref_to_int_match.rs:24:27
    |
 LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
    |                           ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -13,12 +13,6 @@ error: could not evaluate constant pattern
 LL |         10..=BAR => {},
    |              ^^^
 
-error: could not evaluate constant pattern
-  --> $DIR/ref_to_int_match.rs:7:14
-   |
-LL |         10..=BAR => {},
-   |              ^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/ref_to_int_match.rs b/tests/ui/consts/const-eval/ref_to_int_match.rs
index 70c6e7d94ae0..a2dabde25bc8 100644
--- a/tests/ui/consts/const-eval/ref_to_int_match.rs
+++ b/tests/ui/consts/const-eval/ref_to_int_match.rs
@@ -5,7 +5,6 @@ fn main() {
     match n {
         0..=10 => {},
         10..=BAR => {}, //~ ERROR could not evaluate constant pattern
-                        //~| ERROR could not evaluate constant pattern
         _ => {},
     }
 }
diff --git a/tests/ui/consts/const-fn-error.rs b/tests/ui/consts/const-fn-error.rs
index 50b7ce1f8c01..dabbd58dbe0a 100644
--- a/tests/ui/consts/const-fn-error.rs
+++ b/tests/ui/consts/const-fn-error.rs
@@ -7,6 +7,7 @@ const fn f(x: usize) -> usize {
         //~| ERROR `for` is not allowed in a `const fn`
         //~| ERROR mutable references are not allowed in constant functions
         //~| ERROR cannot call non-const fn
+        //~| ERROR the trait bound
         sum += i;
     }
     sum
diff --git a/tests/ui/consts/const-fn-error.stderr b/tests/ui/consts/const-fn-error.stderr
index f735b3d53ce4..73d235d6aec5 100644
--- a/tests/ui/consts/const-fn-error.stderr
+++ b/tests/ui/consts/const-fn-error.stderr
@@ -5,7 +5,7 @@ LL | /     for i in 0..x {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |         sum += i;
 LL | |     }
    | |_____^
@@ -33,6 +33,19 @@ LL |     for i in 0..x {
    = note: see issue #57349  for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
+error[E0277]: the trait bound `std::ops::Range: Iterator` is not satisfied
+  --> $DIR/const-fn-error.rs:5:14
+   |
+LL |     for i in 0..x {
+   |              ^^^^ `std::ops::Range` is not an iterator
+   |
+   = help: the trait `~const Iterator` is not implemented for `std::ops::Range`
+note: the trait `Iterator` is implemented for `std::ops::Range`, but that implementation is not `const`
+  --> $DIR/const-fn-error.rs:5:14
+   |
+LL |     for i in 0..x {
+   |              ^^^^
+
 error[E0015]: cannot call non-const fn ` as Iterator>::next` in constant functions
   --> $DIR/const-fn-error.rs:5:14
    |
@@ -42,7 +55,7 @@ LL |     for i in 0..x {
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0015, E0658.
+Some errors have detailed explanations: E0015, E0277, E0658.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/const-for.rs b/tests/ui/consts/const-for.rs
index 8db248535583..ff9c977f7948 100644
--- a/tests/ui/consts/const-for.rs
+++ b/tests/ui/consts/const-for.rs
@@ -5,6 +5,7 @@ const _: () = {
     for _ in 0..5 {}
     //~^ error: cannot call
     //~| error: cannot convert
+    //~| error: the trait bound
 };
 
 fn main() {}
diff --git a/tests/ui/consts/const-for.stderr b/tests/ui/consts/const-for.stderr
index 3fb9787c0d86..64f2f603b943 100644
--- a/tests/ui/consts/const-for.stderr
+++ b/tests/ui/consts/const-for.stderr
@@ -9,6 +9,19 @@ note: impl defined here, but it is not `const`
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
+error[E0277]: the trait bound `std::ops::Range: Iterator` is not satisfied
+  --> $DIR/const-for.rs:5:14
+   |
+LL |     for _ in 0..5 {}
+   |              ^^^^ `std::ops::Range` is not an iterator
+   |
+   = help: the trait `~const Iterator` is not implemented for `std::ops::Range`
+note: the trait `Iterator` is implemented for `std::ops::Range`, but that implementation is not `const`
+  --> $DIR/const-for.rs:5:14
+   |
+LL |     for _ in 0..5 {}
+   |              ^^^^
+
 error[E0015]: cannot call non-const fn ` as Iterator>::next` in constants
   --> $DIR/const-for.rs:5:14
    |
@@ -18,6 +31,7 @@ LL |     for _ in 0..5 {}
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/const-match-check.eval1.stderr b/tests/ui/consts/const-match-check.eval1.stderr
index 08fcd1deab1d..27ff5d4cd5c6 100644
--- a/tests/ui/consts/const-match-check.eval1.stderr
+++ b/tests/ui/consts/const-match-check.eval1.stderr
@@ -9,8 +9,8 @@ LL |     A = { let 0 = 0; 0 },
    = note: the matched value is of type `i32`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     A = { if let 0 = 0 { todo!() } 0 },
-   |           ++           ~~~~~~~~~~~
+LL |     A = { if let 0 = 0 { todo!() }; 0 },
+   |           ++           +++++++++++
 help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
    |
 LL |     A = { let _0 = 0; 0 },
diff --git a/tests/ui/consts/const-match-check.eval2.stderr b/tests/ui/consts/const-match-check.eval2.stderr
index 5d86ca4bfd17..0c74a7b3dd4d 100644
--- a/tests/ui/consts/const-match-check.eval2.stderr
+++ b/tests/ui/consts/const-match-check.eval2.stderr
@@ -9,8 +9,8 @@ LL |     let x: [i32; { let 0 = 0; 0 }] = [];
    = note: the matched value is of type `i32`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     let x: [i32; { if let 0 = 0 { todo!() } 0 }] = [];
-   |                    ++           ~~~~~~~~~~~
+LL |     let x: [i32; { if let 0 = 0 { todo!() }; 0 }] = [];
+   |                    ++           +++++++++++
 help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
    |
 LL |     let x: [i32; { let _0 = 0; 0 }] = [];
diff --git a/tests/ui/consts/const-match-check.matchck.stderr b/tests/ui/consts/const-match-check.matchck.stderr
index c8f66bb0fc02..bcca4c2a6478 100644
--- a/tests/ui/consts/const-match-check.matchck.stderr
+++ b/tests/ui/consts/const-match-check.matchck.stderr
@@ -9,8 +9,8 @@ LL | const X: i32 = { let 0 = 0; 0 };
    = note: the matched value is of type `i32`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
-   |                  ++           ~~~~~~~~~~~
+LL | const X: i32 = { if let 0 = 0 { todo!() }; 0 };
+   |                  ++           +++++++++++
 help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
    |
 LL | const X: i32 = { let _0 = 0; 0 };
@@ -27,8 +27,8 @@ LL | static Y: i32 = { let 0 = 0; 0 };
    = note: the matched value is of type `i32`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 };
-   |                   ++           ~~~~~~~~~~~
+LL | static Y: i32 = { if let 0 = 0 { todo!() }; 0 };
+   |                   ++           +++++++++++
 help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
    |
 LL | static Y: i32 = { let _0 = 0; 0 };
@@ -45,8 +45,8 @@ LL |     const X: i32 = { let 0 = 0; 0 };
    = note: the matched value is of type `i32`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     const X: i32 = { if let 0 = 0 { todo!() } 0 };
-   |                      ++           ~~~~~~~~~~~
+LL |     const X: i32 = { if let 0 = 0 { todo!() }; 0 };
+   |                      ++           +++++++++++
 help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
    |
 LL |     const X: i32 = { let _0 = 0; 0 };
@@ -63,8 +63,8 @@ LL |     const X: i32 = { let 0 = 0; 0 };
    = note: the matched value is of type `i32`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     const X: i32 = { if let 0 = 0 { todo!() } 0 };
-   |                      ++           ~~~~~~~~~~~
+LL |     const X: i32 = { if let 0 = 0 { todo!() }; 0 };
+   |                      ++           +++++++++++
 help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
    |
 LL |     const X: i32 = { let _0 = 0; 0 };
diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr
index c156ea1610c4..2aed68bdd643 100644
--- a/tests/ui/consts/const-pattern-irrefutable.stderr
+++ b/tests/ui/consts/const-pattern-irrefutable.stderr
@@ -1,9 +1,6 @@
 error[E0005]: refutable pattern in local binding
   --> $DIR/const-pattern-irrefutable.rs:12:9
    |
-LL | const a: u8 = 2;
-   | ----------- constant defined here
-...
 LL |     let a = 4;
    |         ^
    |         |
@@ -11,14 +8,13 @@ LL |     let a = 4;
    |         missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `a_var`
    |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `u8`
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/const-pattern-irrefutable.rs:17:9
    |
-LL |     pub const b: u8 = 2;
-   |     --------------- constant defined here
-...
 LL |     let c = 4;
    |         ^
    |         |
@@ -26,14 +22,13 @@ LL |     let c = 4;
    |         missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `c_var`
    |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `u8`
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/const-pattern-irrefutable.rs:22:9
    |
-LL |     pub const d: u8 = 2;
-   |     --------------- constant defined here
-...
 LL |     let d = 4;
    |         ^
    |         |
@@ -41,6 +36,8 @@ LL |     let d = 4;
    |         missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `d_var`
    |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `u8`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
index b005f3220e9c..be144a87b8b3 100644
--- a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
+++ b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
@@ -19,7 +19,7 @@ LL |     match &[][..] {
    = note: the matched value is of type `&[E]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         E_SL => {}
+LL ~         E_SL => {},
 LL +         &_ => todo!()
    |
 
diff --git a/tests/ui/consts/issue-43105.rs b/tests/ui/consts/issue-43105.rs
index cac12b90970f..20b78d64209e 100644
--- a/tests/ui/consts/issue-43105.rs
+++ b/tests/ui/consts/issue-43105.rs
@@ -7,7 +7,6 @@ fn main() {
     match 1 {
         NUM => unimplemented!(),
         //~^ ERROR could not evaluate constant pattern
-        //~| ERROR could not evaluate constant pattern
         _ => unimplemented!(),
     }
 }
diff --git a/tests/ui/consts/issue-43105.stderr b/tests/ui/consts/issue-43105.stderr
index 2d1174af71c8..856a8f0dab6c 100644
--- a/tests/ui/consts/issue-43105.stderr
+++ b/tests/ui/consts/issue-43105.stderr
@@ -12,12 +12,6 @@ error: could not evaluate constant pattern
 LL |         NUM => unimplemented!(),
    |         ^^^
 
-error: could not evaluate constant pattern
-  --> $DIR/issue-43105.rs:8:9
-   |
-LL |         NUM => unimplemented!(),
-   |         ^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/issue-73976-polymorphic.rs b/tests/ui/consts/issue-73976-polymorphic.rs
index 787462da9f96..2c576d1f9ef0 100644
--- a/tests/ui/consts/issue-73976-polymorphic.rs
+++ b/tests/ui/consts/issue-73976-polymorphic.rs
@@ -19,7 +19,6 @@ impl GetTypeId {
 const fn check_type_id() -> bool {
     matches!(GetTypeId::::VALUE, GetTypeId::::VALUE)
     //~^ ERROR constant pattern depends on a generic parameter
-    //~| ERROR constant pattern depends on a generic parameter
 }
 
 pub struct GetTypeNameLen(T);
@@ -31,7 +30,6 @@ impl GetTypeNameLen {
 const fn check_type_name_len() -> bool {
     matches!(GetTypeNameLen::::VALUE, GetTypeNameLen::::VALUE)
     //~^ ERROR constant pattern depends on a generic parameter
-    //~| ERROR constant pattern depends on a generic parameter
 }
 
 fn main() {
diff --git a/tests/ui/consts/issue-73976-polymorphic.stderr b/tests/ui/consts/issue-73976-polymorphic.stderr
index 442ad23f2cc4..97a5fbc5747a 100644
--- a/tests/ui/consts/issue-73976-polymorphic.stderr
+++ b/tests/ui/consts/issue-73976-polymorphic.stderr
@@ -5,22 +5,10 @@ LL |     matches!(GetTypeId::::VALUE, GetTypeId::::VALUE)
    |                                     ^^^^^^^^^^^^^^^^^^^^^
 
 error: constant pattern depends on a generic parameter
-  --> $DIR/issue-73976-polymorphic.rs:32:42
+  --> $DIR/issue-73976-polymorphic.rs:31:42
    |
 LL |     matches!(GetTypeNameLen::::VALUE, GetTypeNameLen::::VALUE)
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: constant pattern depends on a generic parameter
-  --> $DIR/issue-73976-polymorphic.rs:20:37
-   |
-LL |     matches!(GetTypeId::::VALUE, GetTypeId::::VALUE)
-   |                                     ^^^^^^^^^^^^^^^^^^^^^
-
-error: constant pattern depends on a generic parameter
-  --> $DIR/issue-73976-polymorphic.rs:32:42
-   |
-LL |     matches!(GetTypeNameLen::::VALUE, GetTypeNameLen::::VALUE)
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/issue-78655.rs b/tests/ui/consts/issue-78655.rs
index 82d2d7c21d85..cd95ee32c60d 100644
--- a/tests/ui/consts/issue-78655.rs
+++ b/tests/ui/consts/issue-78655.rs
@@ -6,5 +6,4 @@ const FOO: *const u32 = {
 fn main() {
     let FOO = FOO;
     //~^ ERROR could not evaluate constant pattern
-    //~| ERROR could not evaluate constant pattern
 }
diff --git a/tests/ui/consts/issue-78655.stderr b/tests/ui/consts/issue-78655.stderr
index 6b83fa0e5a01..5a38d023d6f1 100644
--- a/tests/ui/consts/issue-78655.stderr
+++ b/tests/ui/consts/issue-78655.stderr
@@ -17,12 +17,6 @@ error: could not evaluate constant pattern
 LL |     let FOO = FOO;
    |         ^^^
 
-error: could not evaluate constant pattern
-  --> $DIR/issue-78655.rs:7:9
-   |
-LL |     let FOO = FOO;
-   |         ^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/consts/issue-79137-toogeneric.rs b/tests/ui/consts/issue-79137-toogeneric.rs
index 456035458cfc..a80c9f48d7bc 100644
--- a/tests/ui/consts/issue-79137-toogeneric.rs
+++ b/tests/ui/consts/issue-79137-toogeneric.rs
@@ -11,7 +11,6 @@ impl GetVariantCount {
 const fn check_variant_count() -> bool {
     matches!(GetVariantCount::::VALUE, GetVariantCount::::VALUE)
     //~^ ERROR constant pattern depends on a generic parameter
-    //~| ERROR constant pattern depends on a generic parameter
 }
 
 fn main() {
diff --git a/tests/ui/consts/issue-79137-toogeneric.stderr b/tests/ui/consts/issue-79137-toogeneric.stderr
index 579e6aa09bdb..efe4fd22e547 100644
--- a/tests/ui/consts/issue-79137-toogeneric.stderr
+++ b/tests/ui/consts/issue-79137-toogeneric.stderr
@@ -4,11 +4,5 @@ error: constant pattern depends on a generic parameter
 LL |     matches!(GetVariantCount::::VALUE, GetVariantCount::::VALUE)
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: constant pattern depends on a generic parameter
-  --> $DIR/issue-79137-toogeneric.rs:12:43
-   |
-LL |     matches!(GetVariantCount::::VALUE, GetVariantCount::::VALUE)
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr
index 6df2fe3d03b9..e3a0d93f09b7 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr
@@ -27,7 +27,7 @@ LL | const U8_MUT: &u8 = {
            }
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:43:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:42:9
    |
 LL |         U8_MUT => true,
    |         ^^^^^^
@@ -39,7 +39,7 @@ LL |     unsafe { &(*static_cross_crate::ZERO_REF)[0] }
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:54:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:52:9
    |
 LL |         U8_MUT2 => true,
    |         ^^^^^^^
@@ -51,31 +51,7 @@ LL |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None =>
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:62:9
-   |
-LL |         U8_MUT3 => true,
-   |         ^^^^^^^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:34:9
-   |
-LL |         SLICE_MUT => true,
-   |         ^^^^^^^^^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:43:9
-   |
-LL |         U8_MUT => true,
-   |         ^^^^^^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:54:9
-   |
-LL |         U8_MUT2 => true,
-   |         ^^^^^^^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:62:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:59:9
    |
 LL |         U8_MUT3 => true,
    |         ^^^^^^^
@@ -133,6 +109,6 @@ help: skipping check that does not even have a feature gate
 LL |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 12 previous errors; 1 warning emitted
+error: aborting due to 8 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr
index 8802f3adacae..a323e9a05f09 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr
@@ -27,7 +27,7 @@ LL | const U8_MUT: &u8 = {
            }
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:43:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:42:9
    |
 LL |         U8_MUT => true,
    |         ^^^^^^
@@ -39,7 +39,7 @@ LL |     unsafe { &(*static_cross_crate::ZERO_REF)[0] }
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:54:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:52:9
    |
 LL |         U8_MUT2 => true,
    |         ^^^^^^^
@@ -51,31 +51,7 @@ LL |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None =>
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:62:9
-   |
-LL |         U8_MUT3 => true,
-   |         ^^^^^^^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:34:9
-   |
-LL |         SLICE_MUT => true,
-   |         ^^^^^^^^^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:43:9
-   |
-LL |         U8_MUT => true,
-   |         ^^^^^^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:54:9
-   |
-LL |         U8_MUT2 => true,
-   |         ^^^^^^^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:62:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:59:9
    |
 LL |         U8_MUT3 => true,
    |         ^^^^^^^
@@ -133,6 +109,6 @@ help: skipping check that does not even have a feature gate
 LL |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 12 previous errors; 1 warning emitted
+error: aborting due to 8 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
index bf4f14f4d5a1..bbaa32ddfd1b 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
@@ -33,7 +33,6 @@ pub fn test(x: &[u8; 1]) -> bool {
     match x {
         SLICE_MUT => true,
         //~^ ERROR could not evaluate constant pattern
-        //~| ERROR could not evaluate constant pattern
         &[1..] => false,
     }
 }
@@ -42,7 +41,6 @@ pub fn test2(x: &u8) -> bool {
     match x {
         U8_MUT => true,
         //~^ ERROR could not evaluate constant pattern
-        //~| ERROR could not evaluate constant pattern
         &(1..) => false,
     }
 }
@@ -53,7 +51,6 @@ pub fn test3(x: &u8) -> bool {
     match x {
         U8_MUT2 => true,
         //~^ ERROR could not evaluate constant pattern
-        //~| ERROR could not evaluate constant pattern
         &(1..) => false,
     }
 }
@@ -61,7 +58,6 @@ pub fn test4(x: &u8) -> bool {
     match x {
         U8_MUT3 => true,
         //~^ ERROR could not evaluate constant pattern
-        //~| ERROR could not evaluate constant pattern
         &(1..) => false,
     }
 }
diff --git a/tests/ui/consts/miri_unleashed/tls.stderr b/tests/ui/consts/miri_unleashed/tls.stderr
index 7aaeadd0403c..ec24527d6c0e 100644
--- a/tests/ui/consts/miri_unleashed/tls.stderr
+++ b/tests/ui/consts/miri_unleashed/tls.stderr
@@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/tls.rs:11:25
    |
 LL |     unsafe { let _val = A; }
-   |                         ^ cannot access thread local static (DefId(0:4 ~ tls[78b0]::A))
+   |                         ^ cannot access thread local static (DefId(0:4 ~ tls[ca29]::A))
 
 error[E0080]: could not evaluate static initializer
   --> $DIR/tls.rs:18:26
    |
 LL |     unsafe { let _val = &A; }
-   |                          ^ cannot access thread local static (DefId(0:4 ~ tls[78b0]::A))
+   |                          ^ cannot access thread local static (DefId(0:4 ~ tls[ca29]::A))
 
 warning: skipping const checks
    |
diff --git a/tests/ui/dyn-star/align.normal.stderr b/tests/ui/dyn-star/align.normal.stderr
index 53c2cbeac326..42fa4fd6f00c 100644
--- a/tests/ui/dyn-star/align.normal.stderr
+++ b/tests/ui/dyn-star/align.normal.stderr
@@ -1,5 +1,5 @@
 warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/align.rs:4:12
+  --> $DIR/align.rs:3:12
    |
 LL | #![feature(dyn_star)]
    |            ^^^^^^^^
@@ -7,5 +7,14 @@ LL | #![feature(dyn_star)]
    = note: see issue #102425  for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-warning: 1 warning emitted
+error[E0277]: `AlignedUsize` needs to have the same ABI as a pointer
+  --> $DIR/align.rs:14:13
+   |
+LL |     let x = AlignedUsize(12) as dyn* Debug;
+   |             ^^^^^^^^^^^^^^^^ `AlignedUsize` needs to be a pointer-like type
+   |
+   = help: the trait `PointerLike` is not implemented for `AlignedUsize`
 
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dyn-star/align.over_aligned.stderr b/tests/ui/dyn-star/align.over_aligned.stderr
index 0365d87a6f82..42fa4fd6f00c 100644
--- a/tests/ui/dyn-star/align.over_aligned.stderr
+++ b/tests/ui/dyn-star/align.over_aligned.stderr
@@ -1,5 +1,5 @@
 warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/align.rs:4:12
+  --> $DIR/align.rs:3:12
    |
 LL | #![feature(dyn_star)]
    |            ^^^^^^^^
@@ -7,8 +7,8 @@ LL | #![feature(dyn_star)]
    = note: see issue #102425  for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0277]: `AlignedUsize` needs to have the same alignment and size as a pointer
-  --> $DIR/align.rs:15:13
+error[E0277]: `AlignedUsize` needs to have the same ABI as a pointer
+  --> $DIR/align.rs:14:13
    |
 LL |     let x = AlignedUsize(12) as dyn* Debug;
    |             ^^^^^^^^^^^^^^^^ `AlignedUsize` needs to be a pointer-like type
diff --git a/tests/ui/dyn-star/align.rs b/tests/ui/dyn-star/align.rs
index 6679997a9402..79cbaba0c78a 100644
--- a/tests/ui/dyn-star/align.rs
+++ b/tests/ui/dyn-star/align.rs
@@ -1,5 +1,4 @@
 // revisions: normal over_aligned
-//[normal] check-pass
 
 #![feature(dyn_star)]
 //~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
@@ -13,5 +12,5 @@ struct AlignedUsize(usize);
 
 fn main() {
     let x = AlignedUsize(12) as dyn* Debug;
-    //[over_aligned]~^ ERROR `AlignedUsize` needs to have the same alignment and size as a pointer
+    //~^ ERROR `AlignedUsize` needs to have the same ABI as a pointer
 }
diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.rs b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.rs
index 85749aa7b00e..913c2faacbd6 100644
--- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.rs
+++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.rs
@@ -9,7 +9,7 @@ fn dyn_debug(_: (dyn* Debug + '_)) {
 
 fn polymorphic(t: &T) {
     dyn_debug(t);
-    //~^ ERROR `&T` needs to have the same alignment and size as a pointer
+    //~^ ERROR `&T` needs to have the same ABI as a pointer
 }
 
 fn main() {}
diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.stderr
index 350630f79413..8726fae79a00 100644
--- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.stderr
+++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.stderr
@@ -1,4 +1,4 @@
-error[E0277]: `&T` needs to have the same alignment and size as a pointer
+error[E0277]: `&T` needs to have the same ABI as a pointer
   --> $DIR/check-size-at-cast-polymorphic-bad.rs:11:15
    |
 LL |     dyn_debug(t);
diff --git a/tests/ui/dyn-star/check-size-at-cast.rs b/tests/ui/dyn-star/check-size-at-cast.rs
index 17bc4f303bff..e15e090b529a 100644
--- a/tests/ui/dyn-star/check-size-at-cast.rs
+++ b/tests/ui/dyn-star/check-size-at-cast.rs
@@ -5,6 +5,6 @@ use std::fmt::Debug;
 
 fn main() {
     let i = [1, 2, 3, 4] as dyn* Debug;
-    //~^ ERROR `[i32; 4]` needs to have the same alignment and size as a pointer
+    //~^ ERROR `[i32; 4]` needs to have the same ABI as a pointer
     dbg!(i);
 }
diff --git a/tests/ui/dyn-star/check-size-at-cast.stderr b/tests/ui/dyn-star/check-size-at-cast.stderr
index 19700b406440..e60b5c56ff04 100644
--- a/tests/ui/dyn-star/check-size-at-cast.stderr
+++ b/tests/ui/dyn-star/check-size-at-cast.stderr
@@ -1,4 +1,4 @@
-error[E0277]: `[i32; 4]` needs to have the same alignment and size as a pointer
+error[E0277]: `[i32; 4]` needs to have the same ABI as a pointer
   --> $DIR/check-size-at-cast.rs:7:13
    |
 LL |     let i = [1, 2, 3, 4] as dyn* Debug;
diff --git a/tests/ui/dyn-star/const-and-static.rs b/tests/ui/dyn-star/const-and-static.rs
new file mode 100644
index 000000000000..551b072abfab
--- /dev/null
+++ b/tests/ui/dyn-star/const-and-static.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+#![feature(dyn_star)]
+//~^ WARN the feature `dyn_star` is incomplete
+
+const C: dyn* Send + Sync = &();
+
+static S: dyn* Send + Sync = &();
+
+fn main() {}
diff --git a/tests/ui/dyn-star/const-and-static.stderr b/tests/ui/dyn-star/const-and-static.stderr
new file mode 100644
index 000000000000..df8f42fb0f57
--- /dev/null
+++ b/tests/ui/dyn-star/const-and-static.stderr
@@ -0,0 +1,11 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/const-and-static.rs:3:12
+   |
+LL | #![feature(dyn_star)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #102425  for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/dyn-star/upcast.stderr b/tests/ui/dyn-star/upcast.stderr
index e60144fea74c..8b34c7f8b710 100644
--- a/tests/ui/dyn-star/upcast.stderr
+++ b/tests/ui/dyn-star/upcast.stderr
@@ -7,7 +7,7 @@ LL | #![feature(dyn_star, trait_upcasting)]
    = note: see issue #102425  for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0277]: `dyn* Foo` needs to have the same alignment and size as a pointer
+error[E0277]: `dyn* Foo` needs to have the same ABI as a pointer
   --> $DIR/upcast.rs:30:23
    |
 LL |     let w: dyn* Bar = w;
diff --git a/tests/ui/error-codes/E0004.stderr b/tests/ui/error-codes/E0004.stderr
index 4ac8c904f053..603bc5237ea2 100644
--- a/tests/ui/error-codes/E0004.stderr
+++ b/tests/ui/error-codes/E0004.stderr
@@ -14,7 +14,7 @@ LL |     HastaLaVistaBaby,
    = note: the matched value is of type `Terminator`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         Terminator::TalkToMyHand => {}
+LL ~         Terminator::TalkToMyHand => {},
 LL +         Terminator::HastaLaVistaBaby => todo!()
    |
 
diff --git a/tests/ui/error-codes/E0030-teach.rs b/tests/ui/error-codes/E0030-teach.rs
index 8caa4f0931d5..388064fb0fae 100644
--- a/tests/ui/error-codes/E0030-teach.rs
+++ b/tests/ui/error-codes/E0030-teach.rs
@@ -4,6 +4,5 @@ fn main() {
     match 5u32 {
         1000 ..= 5 => {}
         //~^ ERROR lower range bound must be less than or equal to upper
-        //~| ERROR lower range bound must be less than or equal to upper
     }
 }
diff --git a/tests/ui/error-codes/E0030-teach.stderr b/tests/ui/error-codes/E0030-teach.stderr
index 800f66416a81..3f1ad4af3a94 100644
--- a/tests/ui/error-codes/E0030-teach.stderr
+++ b/tests/ui/error-codes/E0030-teach.stderr
@@ -6,12 +6,6 @@ LL |         1000 ..= 5 => {}
    |
    = note: When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
 
-error[E0030]: lower range bound must be less than or equal to upper
-  --> $DIR/E0030-teach.rs:5:9
-   |
-LL |         1000 ..= 5 => {}
-   |         ^^^^ lower bound larger than upper bound
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0030`.
diff --git a/tests/ui/error-codes/E0030.rs b/tests/ui/error-codes/E0030.rs
index a5d8f87261b2..58d856b7c9d2 100644
--- a/tests/ui/error-codes/E0030.rs
+++ b/tests/ui/error-codes/E0030.rs
@@ -2,6 +2,5 @@ fn main() {
     match 5u32 {
         1000 ..= 5 => {}
         //~^ ERROR lower range bound must be less than or equal to upper
-        //~| ERROR lower range bound must be less than or equal to upper
     }
 }
diff --git a/tests/ui/error-codes/E0030.stderr b/tests/ui/error-codes/E0030.stderr
index 8a6114024b63..db8161d8fd5d 100644
--- a/tests/ui/error-codes/E0030.stderr
+++ b/tests/ui/error-codes/E0030.stderr
@@ -4,12 +4,6 @@ error[E0030]: lower range bound must be less than or equal to upper
 LL |         1000 ..= 5 => {}
    |         ^^^^ lower bound larger than upper bound
 
-error[E0030]: lower range bound must be less than or equal to upper
-  --> $DIR/E0030.rs:3:9
-   |
-LL |         1000 ..= 5 => {}
-   |         ^^^^ lower bound larger than upper bound
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0030`.
diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
index 4d79ce3c6594..fb39c404c207 100644
--- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
+++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
@@ -115,7 +115,7 @@ LL |         A, B, C,
    = note: the matched value is of type `Foo`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         Foo::B => {}
+LL ~         Foo::B => {},
 LL +         Foo::C => todo!()
    |
 
diff --git a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
index b5510683328f..853b57052ace 100644
--- a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
+++ b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
@@ -9,7 +9,7 @@ LL |     match 0usize {
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         0..=usize::MAX => {}
+LL ~         0..=usize::MAX => {},
 LL +         _ => todo!()
    |
 
@@ -24,7 +24,7 @@ LL |     match 0isize {
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         isize::MIN..=isize::MAX => {}
+LL ~         isize::MIN..=isize::MAX => {},
 LL +         _ => todo!()
    |
 
diff --git a/tests/ui/generator/print/generator-print-verbose-1.drop_tracking.stderr b/tests/ui/generator/print/generator-print-verbose-1.drop_tracking.stderr
index 7d0a201699b5..429b202f6038 100644
--- a/tests/ui/generator/print/generator-print-verbose-1.drop_tracking.stderr
+++ b/tests/ui/generator/print/generator-print-verbose-1.drop_tracking.stderr
@@ -10,7 +10,7 @@ note: generator is not `Send` as this value is used across a yield
   --> $DIR/generator-print-verbose-1.rs:38:9
    |
 LL |         let _non_send_gen = make_non_send_generator();
-   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[7d1d]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
 LL |         yield;
    |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
 LL |     };
@@ -37,17 +37,17 @@ note: required because it's used within this generator
    |
 LL |     || {
    |     ^^
-note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc>])`
+note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[7d1d]::make_gen2::{opaque#0}), [Arc>])`
   --> $DIR/generator-print-verbose-1.rs:44:30
    |
 LL | pub fn make_gen2(t: T) -> impl Generator {
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`
+note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[7d1d]::make_non_send_generator2::{opaque#0}), [])`
   --> $DIR/generator-print-verbose-1.rs:50:34
    |
 LL | fn make_non_send_generator2() -> impl Generator>> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`, `()`
+   = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[7d1d]::make_non_send_generator2::{opaque#0}), [])`, `()`
 note: required because it's used within this generator
   --> $DIR/generator-print-verbose-1.rs:55:20
    |
diff --git a/tests/ui/generator/print/generator-print-verbose-1.drop_tracking_mir.stderr b/tests/ui/generator/print/generator-print-verbose-1.drop_tracking_mir.stderr
index c045b1441c14..01a30fd2f4e9 100644
--- a/tests/ui/generator/print/generator-print-verbose-1.drop_tracking_mir.stderr
+++ b/tests/ui/generator/print/generator-print-verbose-1.drop_tracking_mir.stderr
@@ -10,7 +10,7 @@ note: generator is not `Send` as this value is used across a yield
   --> $DIR/generator-print-verbose-1.rs:38:9
    |
 LL |         let _non_send_gen = make_non_send_generator();
-   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[7d1d]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
 LL |         yield;
    |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
 note: required by a bound in `require_send`
@@ -33,17 +33,17 @@ note: required because it's used within this generator
    |
 LL |     || {
    |     ^^
-note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc>])`
+note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[7d1d]::make_gen2::{opaque#0}), [Arc>])`
   --> $DIR/generator-print-verbose-1.rs:44:30
    |
 LL | pub fn make_gen2(t: T) -> impl Generator {
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`
+note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[7d1d]::make_non_send_generator2::{opaque#0}), [])`
   --> $DIR/generator-print-verbose-1.rs:50:34
    |
 LL | fn make_non_send_generator2() -> impl Generator>> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`
+   = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[7d1d]::make_non_send_generator2::{opaque#0}), [])`
 note: required because it's used within this generator
   --> $DIR/generator-print-verbose-1.rs:55:20
    |
diff --git a/tests/ui/generator/print/generator-print-verbose-1.no_drop_tracking.stderr b/tests/ui/generator/print/generator-print-verbose-1.no_drop_tracking.stderr
index 7d0a201699b5..429b202f6038 100644
--- a/tests/ui/generator/print/generator-print-verbose-1.no_drop_tracking.stderr
+++ b/tests/ui/generator/print/generator-print-verbose-1.no_drop_tracking.stderr
@@ -10,7 +10,7 @@ note: generator is not `Send` as this value is used across a yield
   --> $DIR/generator-print-verbose-1.rs:38:9
    |
 LL |         let _non_send_gen = make_non_send_generator();
-   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[7d1d]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
 LL |         yield;
    |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
 LL |     };
@@ -37,17 +37,17 @@ note: required because it's used within this generator
    |
 LL |     || {
    |     ^^
-note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc>])`
+note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[7d1d]::make_gen2::{opaque#0}), [Arc>])`
   --> $DIR/generator-print-verbose-1.rs:44:30
    |
 LL | pub fn make_gen2(t: T) -> impl Generator {
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`
+note: required because it appears within the type `Opaque(DefId(0:36 ~ generator_print_verbose_1[7d1d]::make_non_send_generator2::{opaque#0}), [])`
   --> $DIR/generator-print-verbose-1.rs:50:34
    |
 LL | fn make_non_send_generator2() -> impl Generator>> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`, `()`
+   = note: required because it captures the following types: `Opaque(DefId(0:36 ~ generator_print_verbose_1[7d1d]::make_non_send_generator2::{opaque#0}), [])`, `()`
 note: required because it's used within this generator
   --> $DIR/generator-print-verbose-1.rs:55:20
    |
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs
index f55566602dba..4b14a314e7ae 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs
@@ -10,44 +10,31 @@ macro_rules! m {
 fn main() {
     m!(0, ..u8::MIN);
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
     m!(0, ..u16::MIN);
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
     m!(0, ..u32::MIN);
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
     m!(0, ..u64::MIN);
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
     m!(0, ..u128::MIN);
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
 
     m!(0, ..i8::MIN);
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
     m!(0, ..i16::MIN);
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
     m!(0, ..i32::MIN);
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
     m!(0, ..i64::MIN);
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
     m!(0, ..i128::MIN);
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
 
     m!(0f32, ..f32::NEG_INFINITY);
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
     m!(0f64, ..f64::NEG_INFINITY);
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
 
     m!('a', ..'\u{0}');
     //~^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
 }
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr
index 56b224a8542b..e9702bb380fb 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr
@@ -5,155 +5,77 @@ LL |     m!(0, ..u8::MIN);
    |           ^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:14:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:13:11
    |
 LL |     m!(0, ..u16::MIN);
    |           ^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:17:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:15:11
    |
 LL |     m!(0, ..u32::MIN);
    |           ^^^^^^^^^^
 
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:20:11
-   |
-LL |     m!(0, ..u64::MIN);
-   |           ^^^^^^^^^^
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:23:11
-   |
-LL |     m!(0, ..u128::MIN);
-   |           ^^^^^^^^^^^
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:27:11
-   |
-LL |     m!(0, ..i8::MIN);
-   |           ^^^^^^^^^
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11
-   |
-LL |     m!(0, ..i16::MIN);
-   |           ^^^^^^^^^^
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:11
-   |
-LL |     m!(0, ..i32::MIN);
-   |           ^^^^^^^^^^
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:36:11
-   |
-LL |     m!(0, ..i64::MIN);
-   |           ^^^^^^^^^^
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:39:11
-   |
-LL |     m!(0, ..i128::MIN);
-   |           ^^^^^^^^^^^
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:43:14
-   |
-LL |     m!(0f32, ..f32::NEG_INFINITY);
-   |              ^^^^^^^^^^^^^^^^^^^
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:46:14
-   |
-LL |     m!(0f64, ..f64::NEG_INFINITY);
-   |              ^^^^^^^^^^^^^^^^^^^
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:50:13
-   |
-LL |     m!('a', ..'\u{0}');
-   |             ^^^^^^^^^
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:11:11
-   |
-LL |     m!(0, ..u8::MIN);
-   |           ^^^^^^^^^
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:14:11
-   |
-LL |     m!(0, ..u16::MIN);
-   |           ^^^^^^^^^^
-
 error[E0579]: lower range bound must be less than upper
   --> $DIR/half-open-range-pats-thir-lower-empty.rs:17:11
    |
-LL |     m!(0, ..u32::MIN);
-   |           ^^^^^^^^^^
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:20:11
-   |
 LL |     m!(0, ..u64::MIN);
    |           ^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:23:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:19:11
    |
 LL |     m!(0, ..u128::MIN);
    |           ^^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:27:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:22:11
    |
 LL |     m!(0, ..i8::MIN);
    |           ^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:24:11
    |
 LL |     m!(0, ..i16::MIN);
    |           ^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:26:11
    |
 LL |     m!(0, ..i32::MIN);
    |           ^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:36:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:28:11
    |
 LL |     m!(0, ..i64::MIN);
    |           ^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:39:11
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11
    |
 LL |     m!(0, ..i128::MIN);
    |           ^^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:43:14
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:14
    |
 LL |     m!(0f32, ..f32::NEG_INFINITY);
    |              ^^^^^^^^^^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:46:14
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:35:14
    |
 LL |     m!(0f64, ..f64::NEG_INFINITY);
    |              ^^^^^^^^^^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:50:13
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:38:13
    |
 LL |     m!('a', ..'\u{0}');
    |             ^^^^^^^^^
 
-error: aborting due to 26 previous errors
+error: aborting due to 13 previous errors
 
 For more information about this error, try `rustc --explain E0579`.
diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr b/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr
new file mode 100644
index 000000000000..bcb201bf0c37
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr
@@ -0,0 +1,18 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-95230.rs:9:13
+   |
+LL |     for<'a> &'a mut Self:;
+   |             ^^^^^^^^^^^^ cannot infer type for mutable reference `&'a mut Bar`
+   |
+note: required by a bound in `Bar`
+  --> $DIR/issue-95230.rs:9:13
+   |
+LL | pub struct Bar
+   |            --- required by a bound in this struct
+LL | where
+LL |     for<'a> &'a mut Self:;
+   |             ^^^^^^^^^^^^ required by this bound in `Bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.rs b/tests/ui/higher-rank-trait-bounds/issue-95230.rs
index 92c506eabb7f..769b6a925376 100644
--- a/tests/ui/higher-rank-trait-bounds/issue-95230.rs
+++ b/tests/ui/higher-rank-trait-bounds/issue-95230.rs
@@ -1,4 +1,8 @@
-// check-pass
+// revisions: old new
+//[new] compile-flags: -Ztrait-solver=next
+//[old] check-pass
+//[new] known-bug: #109764
+
 
 pub struct Bar
 where
diff --git a/tests/ui/hygiene/arguments.rs b/tests/ui/hygiene/arguments.rs
index f0f732f4c6ff..ab58301d468b 100644
--- a/tests/ui/hygiene/arguments.rs
+++ b/tests/ui/hygiene/arguments.rs
@@ -1,5 +1,3 @@
-// ignore-pretty pretty-printing is unhygienic
-
 #![feature(decl_macro)]
 
 macro m($t:ty, $e:expr) {
diff --git a/tests/ui/hygiene/arguments.stderr b/tests/ui/hygiene/arguments.stderr
index d072086e086d..714178375f2d 100644
--- a/tests/ui/hygiene/arguments.stderr
+++ b/tests/ui/hygiene/arguments.stderr
@@ -1,5 +1,5 @@
 error[E0412]: cannot find type `S` in this scope
-  --> $DIR/arguments.rs:16:8
+  --> $DIR/arguments.rs:14:8
    |
 LL |     m!(S, S);
    |        ^ not found in this scope
diff --git a/tests/ui/hygiene/assoc_item_ctxt.rs b/tests/ui/hygiene/assoc_item_ctxt.rs
index 65593d1d5607..f09f81a5d52d 100644
--- a/tests/ui/hygiene/assoc_item_ctxt.rs
+++ b/tests/ui/hygiene/assoc_item_ctxt.rs
@@ -1,5 +1,3 @@
-// ignore-pretty pretty-printing is unhygienic
-
 #![feature(decl_macro)]
 #![allow(unused)]
 
diff --git a/tests/ui/hygiene/assoc_item_ctxt.stderr b/tests/ui/hygiene/assoc_item_ctxt.stderr
index d65716ec2ce6..effa9e8d6559 100644
--- a/tests/ui/hygiene/assoc_item_ctxt.stderr
+++ b/tests/ui/hygiene/assoc_item_ctxt.stderr
@@ -1,5 +1,5 @@
 error[E0407]: method `method` is not a member of trait `Tr`
-  --> $DIR/assoc_item_ctxt.rs:35:13
+  --> $DIR/assoc_item_ctxt.rs:33:13
    |
 LL |             fn method() {}
    |             ^^^------^^^^^
@@ -13,7 +13,7 @@ LL |     mac_trait_impl!();
    = note: this error originates in the macro `mac_trait_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0046]: not all trait items implemented, missing: `method`
-  --> $DIR/assoc_item_ctxt.rs:34:9
+  --> $DIR/assoc_item_ctxt.rs:32:9
    |
 LL |         fn method();
    |         ------------ `method` from trait
diff --git a/tests/ui/hygiene/assoc_ty_bindings.rs b/tests/ui/hygiene/assoc_ty_bindings.rs
index 0567beab9b9c..a78612749329 100644
--- a/tests/ui/hygiene/assoc_ty_bindings.rs
+++ b/tests/ui/hygiene/assoc_ty_bindings.rs
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-pretty pretty-printing is unhygienic
 
 #![feature(decl_macro, associated_type_defaults)]
 
diff --git a/tests/ui/hygiene/auxiliary/legacy_interaction.rs b/tests/ui/hygiene/auxiliary/legacy_interaction.rs
index 90d5243b74b7..3293e346dade 100644
--- a/tests/ui/hygiene/auxiliary/legacy_interaction.rs
+++ b/tests/ui/hygiene/auxiliary/legacy_interaction.rs
@@ -1,5 +1,3 @@
-// ignore-pretty pretty-printing is unhygienic
-
 #[macro_export]
 macro_rules! m {
     () => {
diff --git a/tests/ui/hygiene/fields.rs b/tests/ui/hygiene/fields.rs
index 7a417b46fcc9..86b3d8151d04 100644
--- a/tests/ui/hygiene/fields.rs
+++ b/tests/ui/hygiene/fields.rs
@@ -1,5 +1,3 @@
-// ignore-pretty pretty-printing is unhygienic
-
 #![feature(decl_macro)]
 
 mod foo {
diff --git a/tests/ui/hygiene/fields.stderr b/tests/ui/hygiene/fields.stderr
index 978120b1f101..99252c4b752c 100644
--- a/tests/ui/hygiene/fields.stderr
+++ b/tests/ui/hygiene/fields.stderr
@@ -1,5 +1,5 @@
 error: type `foo::S` is private
-  --> $DIR/fields.rs:15:17
+  --> $DIR/fields.rs:13:17
    |
 LL |         let s = S { x: 0 };
    |                 ^^^^^^^^^^ private type
@@ -10,7 +10,7 @@ LL |     let s = foo::m!(S, x);
    = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: type `foo::S` is private
-  --> $DIR/fields.rs:16:17
+  --> $DIR/fields.rs:14:17
    |
 LL |         let _ = s.x;
    |                 ^ private type
@@ -21,7 +21,7 @@ LL |     let s = foo::m!(S, x);
    = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: type `T` is private
-  --> $DIR/fields.rs:18:17
+  --> $DIR/fields.rs:16:17
    |
 LL |         let t = T(0);
    |                 ^^^^ private type
@@ -32,7 +32,7 @@ LL |     let s = foo::m!(S, x);
    = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: type `T` is private
-  --> $DIR/fields.rs:19:17
+  --> $DIR/fields.rs:17:17
    |
 LL |         let _ = t.0;
    |                 ^ private type
diff --git a/tests/ui/hygiene/generic_params.rs b/tests/ui/hygiene/generic_params.rs
index 3b6216c3e637..b42152955f77 100644
--- a/tests/ui/hygiene/generic_params.rs
+++ b/tests/ui/hygiene/generic_params.rs
@@ -1,7 +1,6 @@
 // Ensure that generic parameters always have modern hygiene.
 
 // check-pass
-// ignore-pretty pretty-printing is unhygienic
 
 #![feature(decl_macro, rustc_attrs)]
 
diff --git a/tests/ui/hygiene/impl_items.rs b/tests/ui/hygiene/impl_items.rs
index ddb25c06b1b1..51088e3693d7 100644
--- a/tests/ui/hygiene/impl_items.rs
+++ b/tests/ui/hygiene/impl_items.rs
@@ -1,5 +1,3 @@
-// ignore-pretty pretty-printing is unhygienic
-
 #![feature(decl_macro)]
 
 mod foo {
diff --git a/tests/ui/hygiene/impl_items.stderr b/tests/ui/hygiene/impl_items.stderr
index 46a2500386e0..32ba3741a59e 100644
--- a/tests/ui/hygiene/impl_items.stderr
+++ b/tests/ui/hygiene/impl_items.stderr
@@ -1,5 +1,5 @@
 error: type `for<'a> fn(&'a foo::S) {foo::S::f}` is private
-  --> $DIR/impl_items.rs:12:23
+  --> $DIR/impl_items.rs:10:23
    |
 LL |         let _: () = S.f();
    |                       ^ private type
diff --git a/tests/ui/hygiene/intercrate.rs b/tests/ui/hygiene/intercrate.rs
index d9b5b789e4ab..2de62f6aff77 100644
--- a/tests/ui/hygiene/intercrate.rs
+++ b/tests/ui/hygiene/intercrate.rs
@@ -1,5 +1,3 @@
-// ignore-pretty pretty-printing is unhygienic
-
 // aux-build:intercrate.rs
 
 #![feature(decl_macro)]
diff --git a/tests/ui/hygiene/intercrate.stderr b/tests/ui/hygiene/intercrate.stderr
index 91358b279e2b..f108617fba61 100644
--- a/tests/ui/hygiene/intercrate.stderr
+++ b/tests/ui/hygiene/intercrate.stderr
@@ -1,5 +1,5 @@
 error: type `fn() -> u32 {foo::bar::f}` is private
-  --> $DIR/intercrate.rs:10:16
+  --> $DIR/intercrate.rs:8:16
    |
 LL |     assert_eq!(intercrate::foo::m!(), 1);
    |                ^^^^^^^^^^^^^^^^^^^^^ private type
diff --git a/tests/ui/hygiene/issue-47311.rs b/tests/ui/hygiene/issue-47311.rs
index 5c2379a8abab..3f1b7397301c 100644
--- a/tests/ui/hygiene/issue-47311.rs
+++ b/tests/ui/hygiene/issue-47311.rs
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-pretty pretty-printing is unhygienic
 
 #![feature(decl_macro)]
 #![allow(unused)]
diff --git a/tests/ui/hygiene/issue-47312.rs b/tests/ui/hygiene/issue-47312.rs
index bbcb3a7f3931..c8b5c36767cf 100644
--- a/tests/ui/hygiene/issue-47312.rs
+++ b/tests/ui/hygiene/issue-47312.rs
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-pretty pretty-printing is unhygienic
 
 #![feature(decl_macro)]
 #![allow(unused)]
diff --git a/tests/ui/hygiene/items.rs b/tests/ui/hygiene/items.rs
index 1c625a9728c4..a7ed749f526e 100644
--- a/tests/ui/hygiene/items.rs
+++ b/tests/ui/hygiene/items.rs
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-pretty pretty-printing is unhygienic
 
 #![feature(decl_macro)]
 
diff --git a/tests/ui/hygiene/legacy_interaction.rs b/tests/ui/hygiene/legacy_interaction.rs
index 52008eed5151..4d150baf5d49 100644
--- a/tests/ui/hygiene/legacy_interaction.rs
+++ b/tests/ui/hygiene/legacy_interaction.rs
@@ -1,6 +1,5 @@
 // check-pass
 #![allow(dead_code)]
-// ignore-pretty pretty-printing is unhygienic
 
 // aux-build:legacy_interaction.rs
 
diff --git a/tests/ui/hygiene/lexical.rs b/tests/ui/hygiene/lexical.rs
index 3d25c720989b..81de974c2035 100644
--- a/tests/ui/hygiene/lexical.rs
+++ b/tests/ui/hygiene/lexical.rs
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-pretty pretty-printing is unhygienic
 
 #![feature(decl_macro)]
 
diff --git a/tests/ui/hygiene/specialization.rs b/tests/ui/hygiene/specialization.rs
index 656aa880ad1f..b8c4c1b0d587 100644
--- a/tests/ui/hygiene/specialization.rs
+++ b/tests/ui/hygiene/specialization.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty pretty-printing is unhygienic
 
 #![feature(decl_macro)]
 
diff --git a/tests/ui/hygiene/trait_items-2.rs b/tests/ui/hygiene/trait_items-2.rs
index 39edfc37d697..cd9122656cd2 100644
--- a/tests/ui/hygiene/trait_items-2.rs
+++ b/tests/ui/hygiene/trait_items-2.rs
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-pretty pretty-printing is unhygienic
 
 #![feature(decl_macro)]
 
diff --git a/tests/ui/hygiene/wrap_unhygienic_example.rs b/tests/ui/hygiene/wrap_unhygienic_example.rs
index 50c6b35ab18d..f6b48156888c 100644
--- a/tests/ui/hygiene/wrap_unhygienic_example.rs
+++ b/tests/ui/hygiene/wrap_unhygienic_example.rs
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-pretty pretty-printing is unhygienic
 
 // aux-build:my_crate.rs
 // aux-build:unhygienic_example.rs
diff --git a/tests/ui/hygiene/xcrate.rs b/tests/ui/hygiene/xcrate.rs
index 6981ce3f687d..6366bebb52f3 100644
--- a/tests/ui/hygiene/xcrate.rs
+++ b/tests/ui/hygiene/xcrate.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty pretty-printing is unhygienic
 
 // aux-build:xcrate.rs
 
diff --git a/tests/ui/impl-trait/auto-trait-leak.stderr b/tests/ui/impl-trait/auto-trait-leak.stderr
index fd0358421ebf..e6c750d0e427 100644
--- a/tests/ui/impl-trait/auto-trait-leak.stderr
+++ b/tests/ui/impl-trait/auto-trait-leak.stderr
@@ -29,6 +29,11 @@ note: ...which requires building MIR for `cycle1`...
    |
 LL | fn cycle1() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires match-checking `cycle1`...
+  --> $DIR/auto-trait-leak.rs:12:1
+   |
+LL | fn cycle1() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires building THIR for `cycle1`...
   --> $DIR/auto-trait-leak.rs:12:1
    |
@@ -70,6 +75,11 @@ note: ...which requires building MIR for `cycle2`...
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires match-checking `cycle2`...
+  --> $DIR/auto-trait-leak.rs:19:1
+   |
+LL | fn cycle2() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires building THIR for `cycle2`...
   --> $DIR/auto-trait-leak.rs:19:1
    |
diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.stderr b/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.stderr
index d56e1273f241..835f7f765600 100644
--- a/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.stderr
+++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.stderr
@@ -6,7 +6,7 @@ LL | fn a() -> impl Fn(&u8) -> impl Debug {
 LL |     |x| x
    |     --- ^
    |     |
-   |     hidden type `&u8` captures the anonymous lifetime #1 defined here
+   |     hidden type `&u8` captures the anonymous lifetime as defined here
 
 error: aborting due to previous error
 
diff --git a/tests/ui/imports/issue-26873-multifile/issue-26873-multifile.rs b/tests/ui/imports/issue-26873-multifile/issue-26873-multifile.rs
index da2acf6c9f70..d369f1e71d06 100644
--- a/tests/ui/imports/issue-26873-multifile/issue-26873-multifile.rs
+++ b/tests/ui/imports/issue-26873-multifile/issue-26873-multifile.rs
@@ -3,7 +3,6 @@
 #![allow(unused_imports)]
 #![allow(non_snake_case)]
 
-// ignore-pretty issue #37195
 
 #[path = "issue-26873-multifile/mod.rs"]
 mod multifile;
diff --git a/tests/ui/index_message.rs b/tests/ui/index_message.rs
index 87e0cde59195..88b848d6f857 100644
--- a/tests/ui/index_message.rs
+++ b/tests/ui/index_message.rs
@@ -1,4 +1,4 @@
 fn main() {
-    let z = ();
-    let _ = z[0]; //~ ERROR cannot index into a value of type `()`
+    let z = (10,);
+    let _ = z[0]; //~ ERROR cannot index into a value of type `({integer},)`
 }
diff --git a/tests/ui/index_message.stderr b/tests/ui/index_message.stderr
index 6c2b126734b0..56d1d70809db 100644
--- a/tests/ui/index_message.stderr
+++ b/tests/ui/index_message.stderr
@@ -1,4 +1,4 @@
-error[E0608]: cannot index into a value of type `()`
+error[E0608]: cannot index into a value of type `({integer},)`
   --> $DIR/index_message.rs:3:13
    |
 LL |     let _ = z[0];
diff --git a/tests/ui/inference/issue-80409.rs b/tests/ui/inference/issue-80409.rs
new file mode 100644
index 000000000000..80cad6dfc46e
--- /dev/null
+++ b/tests/ui/inference/issue-80409.rs
@@ -0,0 +1,36 @@
+// check-pass
+
+#![allow(unreachable_code, unused)]
+
+use std::marker::PhantomData;
+
+struct FsmBuilder {
+    _fsm: PhantomData,
+}
+
+impl FsmBuilder {
+    fn state(&mut self) -> FsmStateBuilder {
+        todo!()
+    }
+}
+
+struct FsmStateBuilder {
+    _state: PhantomData,
+}
+
+impl FsmStateBuilder {
+    fn on_entry)>(&self, _action: TAction) {}
+}
+
+trait Fsm {
+    type Context;
+}
+
+struct StateContext<'a, TFsm: Fsm> {
+    context: &'a mut TFsm::Context,
+}
+
+fn main() {
+    let mut builder: FsmBuilder = todo!();
+    builder.state().on_entry(|_| {});
+}
diff --git a/tests/ui/inference/issue-83606.stderr b/tests/ui/inference/issue-83606.stderr
index f2ee8692e38a..97ed53fb3ce5 100644
--- a/tests/ui/inference/issue-83606.stderr
+++ b/tests/ui/inference/issue-83606.stderr
@@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `[usize; N]`
 LL |     let _ = foo("foo");
    |         ^
    |
-help: consider giving this pattern a type, where the the value of const parameter `N` is specified
+help: consider giving this pattern a type, where the value of const parameter `N` is specified
    |
 LL |     let _: [usize; N] = foo("foo");
    |          ++++++++++++
diff --git a/tests/ui/inference/need_type_info/concrete-impl.rs b/tests/ui/inference/need_type_info/concrete-impl.rs
index 72e0e74f3234..fc79e6201bdb 100644
--- a/tests/ui/inference/need_type_info/concrete-impl.rs
+++ b/tests/ui/inference/need_type_info/concrete-impl.rs
@@ -7,10 +7,13 @@ struct Two;
 struct Struct;
 
 impl Ambiguous for Struct {}
+//~^ NOTE multiple `impl`s satisfying `Struct: Ambiguous<_>` found
 impl Ambiguous for Struct {}
 
 fn main() {
     >::method();
     //~^ ERROR type annotations needed
+    //~| NOTE cannot infer type of the type parameter `A`
     //~| ERROR type annotations needed
+    //~| NOTE infer type of the type parameter `A`
 }
diff --git a/tests/ui/inference/need_type_info/concrete-impl.stderr b/tests/ui/inference/need_type_info/concrete-impl.stderr
index aa32969950d6..74c3f6cd5cfa 100644
--- a/tests/ui/inference/need_type_info/concrete-impl.stderr
+++ b/tests/ui/inference/need_type_info/concrete-impl.stderr
@@ -1,20 +1,21 @@
 error[E0282]: type annotations needed
-  --> $DIR/concrete-impl.rs:13:5
+  --> $DIR/concrete-impl.rs:14:5
    |
 LL |     >::method();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Self` declared on the trait `Ambiguous`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `A` declared on the trait `Ambiguous`
 
 error[E0283]: type annotations needed
-  --> $DIR/concrete-impl.rs:13:5
+  --> $DIR/concrete-impl.rs:14:5
    |
 LL |     >::method();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Self` declared on the trait `Ambiguous`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `A` declared on the trait `Ambiguous`
    |
 note: multiple `impl`s satisfying `Struct: Ambiguous<_>` found
   --> $DIR/concrete-impl.rs:9:1
    |
 LL | impl Ambiguous for Struct {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL | impl Ambiguous for Struct {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/tests/ui/inference/need_type_info/issue-109905.rs b/tests/ui/inference/need_type_info/issue-109905.rs
new file mode 100644
index 000000000000..99d10a5eae04
--- /dev/null
+++ b/tests/ui/inference/need_type_info/issue-109905.rs
@@ -0,0 +1,25 @@
+// Test that we show the correct type parameter that couldn't be inferred and that we don't
+// end up stating nonsense like "type parameter `'a`" which we used to do.
+
+trait Trait<'a, T> {
+    fn m(self);
+}
+
+impl<'a, A> Trait<'a, A> for () {
+    fn m(self) {}
+}
+
+fn qualified() {
+    <() as Trait<'static, _>>::m(());
+    //~^ ERROR type annotations needed
+    //~| NOTE cannot infer type of the type parameter `T`
+
+}
+
+fn unqualified() {
+    Trait::<'static, _>::m(());
+    //~^ ERROR type annotations needed
+    //~| NOTE cannot infer type of the type parameter `T`
+}
+
+fn main() {}
diff --git a/tests/ui/inference/need_type_info/issue-109905.stderr b/tests/ui/inference/need_type_info/issue-109905.stderr
new file mode 100644
index 000000000000..fcdd50f14226
--- /dev/null
+++ b/tests/ui/inference/need_type_info/issue-109905.stderr
@@ -0,0 +1,15 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-109905.rs:13:5
+   |
+LL |     <() as Trait<'static, _>>::m(());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the trait `Trait`
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-109905.rs:20:5
+   |
+LL |     Trait::<'static, _>::m(());
+   |     ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the trait `Trait`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/inline-const/const-match-pat-generic.rs b/tests/ui/inline-const/const-match-pat-generic.rs
index 7c0d83516ea2..46e501abf6c2 100644
--- a/tests/ui/inline-const/const-match-pat-generic.rs
+++ b/tests/ui/inline-const/const-match-pat-generic.rs
@@ -7,7 +7,6 @@ fn foo() {
     match 0 {
         const { V } => {},
         //~^ ERROR constant pattern depends on a generic parameter
-        //~| ERROR constant pattern depends on a generic parameter
         _ => {},
     }
 }
@@ -20,7 +19,6 @@ fn bar() {
     match 0 {
         const { f(V) } => {},
         //~^ ERROR constant pattern depends on a generic parameter
-        //~| ERROR constant pattern depends on a generic parameter
         _ => {},
     }
 }
diff --git a/tests/ui/inline-const/const-match-pat-generic.stderr b/tests/ui/inline-const/const-match-pat-generic.stderr
index 77267f12fb11..4ffbde4101d7 100644
--- a/tests/ui/inline-const/const-match-pat-generic.stderr
+++ b/tests/ui/inline-const/const-match-pat-generic.stderr
@@ -5,22 +5,10 @@ LL |         const { V } => {},
    |         ^^^^^^^^^^^
 
 error: constant pattern depends on a generic parameter
-  --> $DIR/const-match-pat-generic.rs:21:9
+  --> $DIR/const-match-pat-generic.rs:20:9
    |
 LL |         const { f(V) } => {},
    |         ^^^^^^^^^^^^^^
 
-error: constant pattern depends on a generic parameter
-  --> $DIR/const-match-pat-generic.rs:8:9
-   |
-LL |         const { V } => {},
-   |         ^^^^^^^^^^^
-
-error: constant pattern depends on a generic parameter
-  --> $DIR/const-match-pat-generic.rs:21:9
-   |
-LL |         const { f(V) } => {},
-   |         ^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-11709.rs b/tests/ui/issues/issue-11709.rs
index cb5e3dff3b31..58424f9e4c58 100644
--- a/tests/ui/issues/issue-11709.rs
+++ b/tests/ui/issues/issue-11709.rs
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(dead_code)]
-// ignore-pretty issue #37199
 
 // Don't panic on blocks without results
 // There are several tests in this run-pass that raised
diff --git a/tests/ui/issues/issue-27842.rs b/tests/ui/issues/issue-27842.rs
index 3bcfa1330701..060d3b34e09d 100644
--- a/tests/ui/issues/issue-27842.rs
+++ b/tests/ui/issues/issue-27842.rs
@@ -8,4 +8,9 @@ fn main() {
     let i = 0_usize;
     let _ = tup[i];
     //~^ ERROR cannot index into a value of type
+
+    // the case where the index is out of bounds
+    let tup = (10,);
+    let _ = tup[3];
+    //~^ ERROR cannot index into a value of type
 }
diff --git a/tests/ui/issues/issue-27842.stderr b/tests/ui/issues/issue-27842.stderr
index 784666a639e1..83333aa0c47b 100644
--- a/tests/ui/issues/issue-27842.stderr
+++ b/tests/ui/issues/issue-27842.stderr
@@ -8,10 +8,20 @@ error[E0608]: cannot index into a value of type `({integer}, {integer}, {integer
   --> $DIR/issue-27842.rs:9:13
    |
 LL |     let _ = tup[i];
+   |             ^^^^-^
+   |                 |
+   |                 cannot access tuple elements at a variable index
+   |
+   = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`)
+
+error[E0608]: cannot index into a value of type `({integer},)`
+  --> $DIR/issue-27842.rs:14:13
+   |
+LL |     let _ = tup[3];
    |             ^^^^^^
    |
    = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`)
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0608`.
diff --git a/tests/ui/issues/issue-28839.rs b/tests/ui/issues/issue-28839.rs
index 73be87a0c1e6..c086f412a288 100644
--- a/tests/ui/issues/issue-28839.rs
+++ b/tests/ui/issues/issue-28839.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty issue #37199
 
 pub struct Foo;
 
diff --git a/tests/ui/issues/issue-38190.rs b/tests/ui/issues/issue-38190.rs
index cfa0420c80d1..3bb4c7b980ca 100644
--- a/tests/ui/issues/issue-38190.rs
+++ b/tests/ui/issues/issue-38190.rs
@@ -1,6 +1,5 @@
 // run-pass
 // aux-build:issue-38190.rs
-// ignore-pretty issue #37195
 
 #[macro_use]
 extern crate issue_38190;
diff --git a/tests/ui/issues/issue-9129.rs b/tests/ui/issues/issue-9129.rs
index 04110b3ae895..5d623ed540f7 100644
--- a/tests/ui/issues/issue-9129.rs
+++ b/tests/ui/issues/issue-9129.rs
@@ -2,7 +2,6 @@
 #![allow(dead_code)]
 #![allow(non_camel_case_types)]
 #![allow(non_snake_case)]
-// ignore-pretty unreported
 
 pub trait bomb { fn boom(&self, _: Ident); }
 pub struct S;
diff --git a/tests/ui/issues/issue-98299.stderr b/tests/ui/issues/issue-98299.stderr
index fd905392a21a..4fd9f3030fc5 100644
--- a/tests/ui/issues/issue-98299.stderr
+++ b/tests/ui/issues/issue-98299.stderr
@@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `SmallCString`
 LL |     SmallCString::try_from(p).map(|cstr| cstr);
    |                                    ^^^^
    |
-help: consider giving this closure parameter an explicit type, where the the value of const parameter `N` is specified
+help: consider giving this closure parameter an explicit type, where the value of const parameter `N` is specified
    |
 LL |     SmallCString::try_from(p).map(|cstr: SmallCString| cstr);
    |                                        +++++++++++++++++
diff --git a/tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs b/tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs
index 802be7f5afb5..9ba01540aaf2 100644
--- a/tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs
+++ b/tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs
@@ -6,7 +6,6 @@
 // N.B., this file needs CRLF line endings. The .gitattributes file in
 // this directory should enforce it.
 
-// ignore-pretty issue #37195
 
 /// Doc comment that ends in CRLF
 pub fn foo() {}
diff --git a/tests/ui/lifetimes/issue-93911.rs b/tests/ui/lifetimes/issue-93911.rs
new file mode 100644
index 000000000000..b7ccac1ee521
--- /dev/null
+++ b/tests/ui/lifetimes/issue-93911.rs
@@ -0,0 +1,18 @@
+// check-pass
+// edition:2021
+
+#![allow(dead_code)]
+
+struct Foo<'a>(&'a u32);
+
+impl<'a> Foo<'a> {
+    async fn foo() {
+        struct Bar<'b>(&'b u32);
+
+        impl<'b> Bar<'b> {
+            async fn bar() {}
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/lint/lint-temporary-cstring-as-ptr.rs b/tests/ui/lint/lint-temporary-cstring-as-ptr.rs
index 7aa4f2e1e005..fab792f12841 100644
--- a/tests/ui/lint/lint-temporary-cstring-as-ptr.rs
+++ b/tests/ui/lint/lint-temporary-cstring-as-ptr.rs
@@ -3,7 +3,15 @@
 
 use std::ffi::CString;
 
+macro_rules! mymacro {
+    () => {
+        let s = CString::new("some text").unwrap().as_ptr();
+        //~^ ERROR getting the inner pointer of a temporary `CString`
+    }
+}
+
 fn main() {
     let s = CString::new("some text").unwrap().as_ptr();
     //~^ ERROR getting the inner pointer of a temporary `CString`
+    mymacro!();
 }
diff --git a/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr b/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr
index 79ef57dd1a34..4e5c8aa06936 100644
--- a/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr
+++ b/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr
@@ -1,5 +1,5 @@
 error: getting the inner pointer of a temporary `CString`
-  --> $DIR/lint-temporary-cstring-as-ptr.rs:7:48
+  --> $DIR/lint-temporary-cstring-as-ptr.rs:14:48
    |
 LL |     let s = CString::new("some text").unwrap().as_ptr();
    |             ---------------------------------- ^^^^^^ this pointer will be invalid
@@ -14,5 +14,20 @@ note: the lint level is defined here
 LL | #![deny(temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: getting the inner pointer of a temporary `CString`
+  --> $DIR/lint-temporary-cstring-as-ptr.rs:8:52
+   |
+LL |         let s = CString::new("some text").unwrap().as_ptr();
+   |                 ---------------------------------- ^^^^^^ this pointer will be invalid
+   |                 |
+   |                 this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+...
+LL |     mymacro!();
+   |     ---------- in this macro invocation
+   |
+   = 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
+   = note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lint/use-redundant/issue-92904.rs b/tests/ui/lint/use-redundant/issue-92904.rs
new file mode 100644
index 000000000000..511d9d263cf8
--- /dev/null
+++ b/tests/ui/lint/use-redundant/issue-92904.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+pub struct Foo(bar::Bar);
+
+pub mod bar {
+    pub struct Foo(pub Bar);
+    pub struct Bar(pub char);
+}
+
+pub fn warning() -> Foo {
+    use bar::*;
+    #[deny(unused_imports)]
+    use self::Foo; // no error
+    Foo(Bar('a'))
+}
+
+fn main() {}
diff --git a/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs b/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs
new file mode 100644
index 000000000000..6b1e018d2dc3
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-glob-parent.rs
@@ -0,0 +1,16 @@
+// check-pass
+#![warn(unused_imports)]
+
+pub mod bar {
+    pub struct Foo(pub Bar);
+    pub struct Bar(pub char);
+}
+
+use bar::*;
+
+pub fn warning() -> Foo {
+    use bar::Foo; //~ WARNING imported redundantly
+    Foo(Bar('a'))
+}
+
+fn main() {}
diff --git a/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr b/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr
new file mode 100644
index 000000000000..2c3b33452702
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-glob-parent.stderr
@@ -0,0 +1,17 @@
+warning: the item `Foo` is imported redundantly
+  --> $DIR/use-redundant-glob-parent.rs:12:9
+   |
+LL | use bar::*;
+   |     ------ the item `Foo` is already imported here
+...
+LL |     use bar::Foo;
+   |         ^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/use-redundant-glob-parent.rs:2:9
+   |
+LL | #![warn(unused_imports)]
+   |         ^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lint/use-redundant/use-redundant-glob.rs b/tests/ui/lint/use-redundant/use-redundant-glob.rs
new file mode 100644
index 000000000000..bd9e51b6f594
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-glob.rs
@@ -0,0 +1,15 @@
+// check-pass
+#![warn(unused_imports)]
+
+pub mod bar {
+    pub struct Foo(pub Bar);
+    pub struct Bar(pub char);
+}
+
+pub fn warning() -> bar::Foo {
+    use bar::*;
+    use bar::Foo; //~ WARNING imported redundantly
+    Foo(Bar('a'))
+}
+
+fn main() {}
diff --git a/tests/ui/lint/use-redundant/use-redundant-glob.stderr b/tests/ui/lint/use-redundant/use-redundant-glob.stderr
new file mode 100644
index 000000000000..d3b406d82b6d
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-glob.stderr
@@ -0,0 +1,16 @@
+warning: the item `Foo` is imported redundantly
+  --> $DIR/use-redundant-glob.rs:11:9
+   |
+LL |     use bar::*;
+   |         ------ the item `Foo` is already imported here
+LL |     use bar::Foo;
+   |         ^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/use-redundant-glob.rs:2:9
+   |
+LL | #![warn(unused_imports)]
+   |         ^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lint/use-redundant/use-redundant-multiple-namespaces.rs b/tests/ui/lint/use-redundant/use-redundant-multiple-namespaces.rs
new file mode 100644
index 000000000000..0fb60840f8ad
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-multiple-namespaces.rs
@@ -0,0 +1,21 @@
+// check-pass
+#![allow(nonstandard_style)]
+
+pub mod bar {
+    pub struct Foo { pub bar: Bar }
+    pub struct Bar(pub char);
+}
+
+pub mod x {
+    use crate::bar;
+    pub const Foo: bar::Bar = bar::Bar('a');
+}
+
+pub fn warning() -> bar::Foo {
+    #![deny(unused_imports)] // no error
+    use bar::*;
+    use x::Foo;
+    Foo { bar: Foo }
+}
+
+fn main() {}
diff --git a/tests/ui/lint/use-redundant/use-redundant-not-parent.rs b/tests/ui/lint/use-redundant/use-redundant-not-parent.rs
new file mode 100644
index 000000000000..c97a3d34163c
--- /dev/null
+++ b/tests/ui/lint/use-redundant/use-redundant-not-parent.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+pub mod bar {
+    pub struct Foo(pub Bar);
+    pub struct Bar(pub char);
+}
+
+pub mod x {
+    pub struct Foo(pub crate::bar::Bar);
+}
+
+pub fn warning() -> x::Foo {
+    use bar::*;
+    #[deny(unused_imports)]
+    use x::Foo; // no error
+    Foo(Bar('a'))
+}
+
+fn main() {}
diff --git a/tests/ui/lint/use-redundant.rs b/tests/ui/lint/use-redundant/use-redundant.rs
similarity index 100%
rename from tests/ui/lint/use-redundant.rs
rename to tests/ui/lint/use-redundant/use-redundant.rs
diff --git a/tests/ui/lint/use-redundant.stderr b/tests/ui/lint/use-redundant/use-redundant.stderr
similarity index 100%
rename from tests/ui/lint/use-redundant.stderr
rename to tests/ui/lint/use-redundant/use-redundant.stderr
diff --git a/tests/ui/macros/issue-40469.rs b/tests/ui/macros/issue-40469.rs
index 25e08ef85e96..9b22aaef289a 100644
--- a/tests/ui/macros/issue-40469.rs
+++ b/tests/ui/macros/issue-40469.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty issue #37195
 
 #![allow(dead_code)]
 
diff --git a/tests/ui/macros/macro-comma-support-rpass.rs b/tests/ui/macros/macro-comma-support-rpass.rs
index 25b8c3cc62e1..cb019792e656 100644
--- a/tests/ui/macros/macro-comma-support-rpass.rs
+++ b/tests/ui/macros/macro-comma-support-rpass.rs
@@ -8,7 +8,6 @@
 // implementations for some macro_rules! macros as an implementation
 // detail.
 
-// ignore-pretty issue #37195
 
 // compile-flags: --test -C debug_assertions=yes
 // revisions: std core
diff --git a/tests/ui/macros/macro-include-items.rs b/tests/ui/macros/macro-include-items.rs
index 332bf59c944e..ad6f04009b6c 100644
--- a/tests/ui/macros/macro-include-items.rs
+++ b/tests/ui/macros/macro-include-items.rs
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(non_camel_case_types)]
 
-// ignore-pretty issue #37195
 
 fn bar() {}
 
diff --git a/tests/ui/macros/syntax-extension-source-utils.rs b/tests/ui/macros/syntax-extension-source-utils.rs
index 7e46260d5163..f41faddddf6c 100644
--- a/tests/ui/macros/syntax-extension-source-utils.rs
+++ b/tests/ui/macros/syntax-extension-source-utils.rs
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(stable_features)]
 
-// ignore-pretty issue #37195
 
 pub mod m1 {
     pub mod m2 {
@@ -14,9 +13,9 @@ pub mod m1 {
 macro_rules! indirect_line { () => ( line!() ) }
 
 pub fn main() {
-    assert_eq!(line!(), 17);
+    assert_eq!(line!(), 16);
     assert_eq!(column!(), 16);
-    assert_eq!(indirect_line!(), 19);
+    assert_eq!(indirect_line!(), 18);
     assert!((file!().ends_with("syntax-extension-source-utils.rs")));
     assert_eq!(stringify!((2*3) + 5).to_string(), "(2 * 3) + 5".to_string());
     assert!(include!("syntax-extension-source-utils-files/includeme.\
@@ -33,5 +32,5 @@ pub fn main() {
     // The Windows tests are wrapped in an extra module for some reason
     assert!((m1::m2::where_am_i().ends_with("m1::m2")));
 
-    assert_eq!((36, "(2 * 3) + 5"), (line!(), stringify!((2*3) + 5)));
+    assert_eq!((35, "(2 * 3) + 5"), (line!(), stringify!((2*3) + 5)));
 }
diff --git a/tests/ui/match/match-range-fail-2.rs b/tests/ui/match/match-range-fail-2.rs
index 792664e1db82..4489cf1ab1f2 100644
--- a/tests/ui/match/match-range-fail-2.rs
+++ b/tests/ui/match/match-range-fail-2.rs
@@ -3,22 +3,19 @@
 fn main() {
     match 5 {
         6 ..= 1 => { }
+        //~^ ERROR lower range bound must be less than or equal to upper
         _ => { }
     };
-    //~^^^ ERROR lower range bound must be less than or equal to upper
-    //~| ERROR lower range bound must be less than or equal to upper
 
     match 5 {
         0 .. 0 => { }
+        //~^ ERROR lower range bound must be less than upper
         _ => { }
     };
-    //~^^^ ERROR lower range bound must be less than upper
-    //~| ERROR lower range bound must be less than upper
 
     match 5u64 {
         0xFFFF_FFFF_FFFF_FFFF ..= 1 => { }
+        //~^ ERROR lower range bound must be less than or equal to upper
         _ => { }
     };
-    //~^^^ ERROR lower range bound must be less than or equal to upper
-    //~| ERROR lower range bound must be less than or equal to upper
 }
diff --git a/tests/ui/match/match-range-fail-2.stderr b/tests/ui/match/match-range-fail-2.stderr
index 7a0852d7e6ce..52a2bf2b34aa 100644
--- a/tests/ui/match/match-range-fail-2.stderr
+++ b/tests/ui/match/match-range-fail-2.stderr
@@ -5,36 +5,18 @@ LL |         6 ..= 1 => { }
    |         ^ lower bound larger than upper bound
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/match-range-fail-2.rs:12:9
+  --> $DIR/match-range-fail-2.rs:11:9
    |
 LL |         0 .. 0 => { }
    |         ^
 
 error[E0030]: lower range bound must be less than or equal to upper
-  --> $DIR/match-range-fail-2.rs:19:9
+  --> $DIR/match-range-fail-2.rs:17:9
    |
 LL |         0xFFFF_FFFF_FFFF_FFFF ..= 1 => { }
    |         ^^^^^^^^^^^^^^^^^^^^^ lower bound larger than upper bound
 
-error[E0030]: lower range bound must be less than or equal to upper
-  --> $DIR/match-range-fail-2.rs:5:9
-   |
-LL |         6 ..= 1 => { }
-   |         ^ lower bound larger than upper bound
-
-error[E0579]: lower range bound must be less than upper
-  --> $DIR/match-range-fail-2.rs:12:9
-   |
-LL |         0 .. 0 => { }
-   |         ^
-
-error[E0030]: lower range bound must be less than or equal to upper
-  --> $DIR/match-range-fail-2.rs:19:9
-   |
-LL |         0xFFFF_FFFF_FFFF_FFFF ..= 1 => { }
-   |         ^^^^^^^^^^^^^^^^^^^^^ lower bound larger than upper bound
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0030, E0579.
 For more information about an error, try `rustc --explain E0030`.
diff --git a/tests/ui/mir/issue-109743.rs b/tests/ui/mir/issue-109743.rs
new file mode 100644
index 000000000000..73f3405e3ad7
--- /dev/null
+++ b/tests/ui/mir/issue-109743.rs
@@ -0,0 +1,51 @@
+// build-pass
+// compile-flags: --crate-type=lib
+
+use std::marker::PhantomData;
+
+pub trait StreamOnce {
+    type Token;
+}
+
+impl StreamOnce for &str {
+    type Token = ();
+}
+
+pub trait Parser {
+    type PartialState: Default;
+    fn parse_mode(&self, _state: &Self::PartialState) {}
+    fn parse_mode_impl() {}
+}
+
+pub fn parse_bool<'a>() -> impl Parser<&'a str> {
+    pub struct TokensCmp
+    where
+        Input: StreamOnce,
+    {
+        _cmp: C,
+        _marker: PhantomData,
+    }
+
+    impl Parser for TokensCmp
+    where
+        C: FnMut(Input::Token),
+        Input: StreamOnce,
+    {
+        type PartialState = ();
+    }
+
+    TokensCmp { _cmp: |_| (), _marker: PhantomData }
+}
+
+pub struct ParseBool;
+
+impl<'a> Parser<&'a str> for ParseBool
+where
+    &'a str: StreamOnce,
+{
+    type PartialState = ();
+
+    fn parse_mode_impl() {
+        parse_bool().parse_mode(&Default::default())
+    }
+}
diff --git a/tests/ui/missing/missing-items/missing-const-parameter.rs b/tests/ui/missing/missing-items/missing-const-parameter.rs
new file mode 100644
index 000000000000..a3af88f26333
--- /dev/null
+++ b/tests/ui/missing/missing-items/missing-const-parameter.rs
@@ -0,0 +1,24 @@
+struct Struct;
+
+impl Struct<{ N }> {}
+//~^ ERROR cannot find value `N` in this scope
+//~| HELP you might be missing a const parameter
+
+fn func0(_: Struct<{ N }>) {}
+//~^ ERROR cannot find value `N` in this scope
+//~| HELP you might be missing a const parameter
+
+fn func1(_: [u8; N]) {}
+//~^ ERROR cannot find value `N` in this scope
+//~| HELP you might be missing a const parameter
+
+fn func2(_: [T; N]) {}
+//~^ ERROR cannot find value `N` in this scope
+//~| HELP you might be missing a const parameter
+
+struct Image([[u32; C]; R]);
+//~^ ERROR cannot find value `C` in this scope
+//~| HELP a const parameter with a similar name exists
+//~| HELP you might be missing a const parameter
+
+fn main() {}
diff --git a/tests/ui/missing/missing-items/missing-const-parameter.stderr b/tests/ui/missing/missing-items/missing-const-parameter.stderr
new file mode 100644
index 000000000000..d9fea1306514
--- /dev/null
+++ b/tests/ui/missing/missing-items/missing-const-parameter.stderr
@@ -0,0 +1,64 @@
+error[E0425]: cannot find value `N` in this scope
+  --> $DIR/missing-const-parameter.rs:3:15
+   |
+LL | impl Struct<{ N }> {}
+   |               ^ not found in this scope
+   |
+help: you might be missing a const parameter
+   |
+LL | impl Struct<{ N }> {}
+   |     +++++++++++++++++++++
+
+error[E0425]: cannot find value `N` in this scope
+  --> $DIR/missing-const-parameter.rs:7:22
+   |
+LL | fn func0(_: Struct<{ N }>) {}
+   |                      ^ not found in this scope
+   |
+help: you might be missing a const parameter
+   |
+LL | fn func0(_: Struct<{ N }>) {}
+   |         +++++++++++++++++++++
+
+error[E0425]: cannot find value `N` in this scope
+  --> $DIR/missing-const-parameter.rs:11:18
+   |
+LL | fn func1(_: [u8; N]) {}
+   |                  ^ not found in this scope
+   |
+help: you might be missing a const parameter
+   |
+LL | fn func1(_: [u8; N]) {}
+   |         +++++++++++++++++++++
+
+error[E0425]: cannot find value `N` in this scope
+  --> $DIR/missing-const-parameter.rs:15:20
+   |
+LL | fn func2(_: [T; N]) {}
+   |                    ^ not found in this scope
+   |
+help: you might be missing a const parameter
+   |
+LL | fn func2(_: [T; N]) {}
+   |           +++++++++++++++++++++
+
+error[E0425]: cannot find value `C` in this scope
+  --> $DIR/missing-const-parameter.rs:19:37
+   |
+LL | struct Image([[u32; C]; R]);
+   |                    -                ^
+   |                    |
+   |                    similarly named const parameter `R` defined here
+   |
+help: a const parameter with a similar name exists
+   |
+LL | struct Image([[u32; R]; R]);
+   |                                     ~
+help: you might be missing a const parameter
+   |
+LL | struct Image([[u32; C]; R]);
+   |                            +++++++++++++++++++++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/modules/mod_dir_implicit.rs b/tests/ui/modules/mod_dir_implicit.rs
index d6ea6a98bda4..7eac90f4d9b6 100644
--- a/tests/ui/modules/mod_dir_implicit.rs
+++ b/tests/ui/modules/mod_dir_implicit.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty issue #37195
 
 mod mod_dir_implicit_aux;
 
diff --git a/tests/ui/modules/mod_dir_path.rs b/tests/ui/modules/mod_dir_path.rs
index 70f592d0c0ed..72db8e44be31 100644
--- a/tests/ui/modules/mod_dir_path.rs
+++ b/tests/ui/modules/mod_dir_path.rs
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(unused_macros)]
-// ignore-pretty issue #37195
 
 mod mod_dir_simple {
     #[path = "test.rs"]
diff --git a/tests/ui/modules/mod_dir_path2.rs b/tests/ui/modules/mod_dir_path2.rs
index c3e3e1d639e9..b4f8f1c84547 100644
--- a/tests/ui/modules/mod_dir_path2.rs
+++ b/tests/ui/modules/mod_dir_path2.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty issue #37195
 
 #[path = "mod_dir_simple"]
 mod pancakes {
diff --git a/tests/ui/modules/mod_dir_path3.rs b/tests/ui/modules/mod_dir_path3.rs
index fed70c1bc984..56980c01049b 100644
--- a/tests/ui/modules/mod_dir_path3.rs
+++ b/tests/ui/modules/mod_dir_path3.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty issue #37195
 
 #[path = "mod_dir_simple"]
 mod pancakes {
diff --git a/tests/ui/modules/mod_dir_path_multi.rs b/tests/ui/modules/mod_dir_path_multi.rs
index 2b805141a63d..1c111294a337 100644
--- a/tests/ui/modules/mod_dir_path_multi.rs
+++ b/tests/ui/modules/mod_dir_path_multi.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty issue #37195
 
 #[path = "mod_dir_simple"]
 mod biscuits {
diff --git a/tests/ui/modules/mod_dir_recursive.rs b/tests/ui/modules/mod_dir_recursive.rs
index b109d13d1643..56f26139828f 100644
--- a/tests/ui/modules/mod_dir_recursive.rs
+++ b/tests/ui/modules/mod_dir_recursive.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty issue #37195
 
 // Testing that the parser for each file tracks its modules
 // and paths independently. The load_another_mod module should
diff --git a/tests/ui/modules/mod_dir_simple.rs b/tests/ui/modules/mod_dir_simple.rs
index 1d92c968a8fe..56f15b1d6105 100644
--- a/tests/ui/modules/mod_dir_simple.rs
+++ b/tests/ui/modules/mod_dir_simple.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty issue #37195
 
 mod mod_dir_simple {
     pub mod test;
diff --git a/tests/ui/modules/mod_file.rs b/tests/ui/modules/mod_file.rs
index 0ca52889e5c9..7b56b99eb3ac 100644
--- a/tests/ui/modules/mod_file.rs
+++ b/tests/ui/modules/mod_file.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty issue #37195
 
 // Testing that a plain .rs file can load modules from other source files
 
diff --git a/tests/ui/modules/mod_file_with_path_attr.rs b/tests/ui/modules/mod_file_with_path_attr.rs
index 48e253eadae5..e739366954eb 100644
--- a/tests/ui/modules/mod_file_with_path_attr.rs
+++ b/tests/ui/modules/mod_file_with_path_attr.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty issue #37195
 
 // Testing that a plain .rs file can load modules from other source files
 
diff --git a/tests/ui/never_type/exhaustive_patterns.stderr b/tests/ui/never_type/exhaustive_patterns.stderr
index 40c7c1d1067f..5fed903eb70a 100644
--- a/tests/ui/never_type/exhaustive_patterns.stderr
+++ b/tests/ui/never_type/exhaustive_patterns.stderr
@@ -17,8 +17,8 @@ LL |     B(inner::Wrapper),
    = note: the matched value is of type `Either<(), !>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Either::A(()) = foo() { todo!() }
-   |     ++                           ~~~~~~~~~~~
+LL |     if let Either::A(()) = foo() { todo!() };
+   |     ++                           +++++++++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
index 363ddfaffe06..c0d95ddaa079 100644
--- a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
+++ b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
@@ -6,7 +6,7 @@ LL |         let mut closure = expect_sig(|p, y| *p = y);
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) i32)),
+               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) i32)),
                (),
            ]
 
diff --git a/tests/ui/nll/closure-requirements/escape-argument.stderr b/tests/ui/nll/closure-requirements/escape-argument.stderr
index 5a8462d4dc56..61e2a1ea6f01 100644
--- a/tests/ui/nll/closure-requirements/escape-argument.stderr
+++ b/tests/ui/nll/closure-requirements/escape-argument.stderr
@@ -6,7 +6,7 @@ LL |         let mut closure = expect_sig(|p, y| *p = y);
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32)),
+               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) i32)),
                (),
            ]
 
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
index 7da6ce58bf7f..5a7b12732df6 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
@@ -6,7 +6,7 @@ LL |         |_outlives1, _outlives2, _outlives3, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
+               for extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#4r
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
index 993687605c4a..db2ecc779ef9 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(5, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>)),
+               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index 721cd45ded98..1d9dafbe55f6 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -6,7 +6,7 @@ LL |     foo(cell, |cell_a, cell_x| {
    |
    = note: defining type: case1::{closure#0} with closure substs [
                i32,
-               for extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>)),
+               for extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>)),
                (),
            ]
 
@@ -36,7 +36,7 @@ LL |     foo(cell, |cell_a, cell_x| {
    |
    = note: defining type: case2::{closure#0} with closure substs [
                i32,
-               for extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>)),
+               for extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>)),
                (),
            ]
    = note: number of external vids: 2
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index 43dfc3bb9f83..85f7fe35c0aa 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) u32>)),
+               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#2r
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index 96c734226eff..7194843e203f 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(5, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>)),
+               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
index 03dbd686e497..71f8a1c67c67 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
@@ -6,7 +6,7 @@ LL |     establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
+               for extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
diff --git a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
index d716d3de2a11..e1cb97b1c7d9 100644
--- a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
@@ -6,7 +6,7 @@ LL |         |_outlives1, _outlives2, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
+               for extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
index b924873fca6f..b66e8391c013 100644
--- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
+               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#2r
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
index 9b25efd0b66b..49641fd06fdb 100644
--- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
@@ -6,7 +6,7 @@ LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(5, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>)),
+               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)),
                (),
            ]
    = note: late-bound region is '_#3r
diff --git a/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
index 6db72b886325..4e34ba516595 100644
--- a/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
+++ b/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
@@ -6,7 +6,7 @@ LL |     expect_sig(|a, b| b); // ought to return `a`
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32)) -> &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) i32,
+               for extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) i32)) -> &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) i32,
                (),
            ]
 
diff --git a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr
index 7fcb68252cfd..da4b9595c0ee 100644
--- a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr
+++ b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr
@@ -1,16 +1,16 @@
-error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds
   --> $DIR/impl-trait-captures.rs:11:5
    |
 LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
    |                  --     ------------ opaque type defined here
    |                  |
-   |                  hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_)) T` captures the anonymous lifetime defined here
+   |                  hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) T` captures the anonymous lifetime defined here
 LL |     x
    |     ^
    |
-help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(2, 'a)])` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_))` lifetime bound
+help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(2, 'a)])` captures `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound
    |
-LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_)) {
+LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) {
    |                                      ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
index a442cf12d820..2c4a0597554a 100644
--- a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
+++ b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
@@ -6,7 +6,7 @@ LL |     twice(cell, value, |a, b| invoke(a, b));
    |
    = note: defining type: generic::::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) T)),
+               for extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) T)),
                (),
            ]
    = note: number of external vids: 2
@@ -28,7 +28,7 @@ LL |     twice(cell, value, |a, b| invoke(a, b));
    |
    = note: defining type: generic_fail::::{closure#0} with closure substs [
                i16,
-               for extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) T)),
+               for extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) T)),
                (),
            ]
    = note: late-bound region is '_#2r
diff --git a/tests/ui/non_modrs_mods/non_modrs_mods.rs b/tests/ui/non_modrs_mods/non_modrs_mods.rs
index f664b0166d80..b3fa390087f5 100644
--- a/tests/ui/non_modrs_mods/non_modrs_mods.rs
+++ b/tests/ui/non_modrs_mods/non_modrs_mods.rs
@@ -1,6 +1,5 @@
 // run-pass
 //
-// ignore-pretty issue #37195
 pub mod modrs_mod;
 pub mod foors_mod;
 #[path = "some_crazy_attr_mod_dir/arbitrary_name.rs"]
diff --git a/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
index 9aa808e6bc9a..9f691aea8a79 100644
--- a/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
+++ b/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
@@ -7,7 +7,7 @@ LL |     match (0u8, 0u8) {
    = note: the matched value is of type `(u8, u8)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         (0 | 1, 2 | 3) => {}
+LL ~         (0 | 1, 2 | 3) => {},
 LL +         (2_u8..=u8::MAX, _) => todo!()
    |
 
@@ -20,7 +20,7 @@ LL |     match ((0u8,),) {
    = note: the matched value is of type `((u8,),)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         ((0 | 1,) | (2 | 3,),) => {}
+LL ~         ((0 | 1,) | (2 | 3,),) => {},
 LL +         ((4_u8..=u8::MAX)) => todo!()
    |
 
@@ -33,7 +33,7 @@ LL |     match (Some(0u8),) {
    = note: the matched value is of type `(Option,)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         (None | Some(0 | 1),) => {}
+LL ~         (None | Some(0 | 1),) => {},
 LL +         (Some(2_u8..=u8::MAX)) => todo!()
    |
 
diff --git a/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
index 4adcf4feee90..fdb1a9bb4b78 100644
--- a/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
+++ b/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
@@ -9,8 +9,8 @@ LL |     let (0 | (1 | 2)) = 0;
    = note: the matched value is of type `i32`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let (0 | (1 | 2)) = 0 { todo!() }
-   |     ++                       ~~~~~~~~~~~
+LL |     if let (0 | (1 | 2)) = 0 { todo!() };
+   |     ++                       +++++++++++
 
 error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
   --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:3:11
@@ -21,7 +21,7 @@ LL |     match 0 {
    = note: the matched value is of type `i32`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         0 | (1 | 2) => {}
+LL ~         0 | (1 | 2) => {},
 LL +         i32::MIN..=-1_i32 | 3_i32..=i32::MAX => todo!()
    |
 
diff --git a/tests/ui/parser/dyn-trait-compatibility.rs b/tests/ui/parser/dyn-trait-compatibility.rs
index d2b02cc2af54..6341e0532775 100644
--- a/tests/ui/parser/dyn-trait-compatibility.rs
+++ b/tests/ui/parser/dyn-trait-compatibility.rs
@@ -9,6 +9,6 @@ type A2 = dyn;
 type A3 = dyn<::dyn>;
 //~^ ERROR cannot find type `dyn` in this scope
 //~| ERROR cannot find type `dyn` in this scope
-//~| ERROR use of undeclared crate or module `dyn`
+//~| ERROR cannot find trait `dyn` in this scope
 
 fn main() {}
diff --git a/tests/ui/parser/dyn-trait-compatibility.stderr b/tests/ui/parser/dyn-trait-compatibility.stderr
index 0cae01bd1e32..653be5b3b717 100644
--- a/tests/ui/parser/dyn-trait-compatibility.stderr
+++ b/tests/ui/parser/dyn-trait-compatibility.stderr
@@ -4,12 +4,6 @@ error[E0433]: failed to resolve: use of undeclared crate or module `dyn`
 LL | type A1 = dyn::dyn;
    |           ^^^ use of undeclared crate or module `dyn`
 
-error[E0433]: failed to resolve: use of undeclared crate or module `dyn`
-  --> $DIR/dyn-trait-compatibility.rs:9:23
-   |
-LL | type A3 = dyn<::dyn>;
-   |                       ^^^ use of undeclared crate or module `dyn`
-
 error[E0412]: cannot find type `dyn` in this scope
   --> $DIR/dyn-trait-compatibility.rs:1:11
    |
@@ -40,6 +34,12 @@ error[E0412]: cannot find type `dyn` in this scope
 LL | type A3 = dyn<::dyn>;
    |           ^^^ not found in this scope
 
+error[E0405]: cannot find trait `dyn` in this scope
+  --> $DIR/dyn-trait-compatibility.rs:9:23
+   |
+LL | type A3 = dyn<::dyn>;
+   |                       ^^^ not found in this scope
+
 error[E0412]: cannot find type `dyn` in this scope
   --> $DIR/dyn-trait-compatibility.rs:9:16
    |
@@ -48,5 +48,5 @@ LL | type A3 = dyn<::dyn>;
 
 error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0412, E0433.
-For more information about an error, try `rustc --explain E0412`.
+Some errors have detailed explanations: E0405, E0412, E0433.
+For more information about an error, try `rustc --explain E0405`.
diff --git a/tests/ui/parser/issues/issue-110014.rs b/tests/ui/parser/issues/issue-110014.rs
new file mode 100644
index 000000000000..69d8f402bb62
--- /dev/null
+++ b/tests/ui/parser/issues/issue-110014.rs
@@ -0,0 +1,3 @@
+fn`2222222222222222222222222222222222222222() {}
+//~^ ERROR unknown start of token: `
+//~^^ ERROR expected identifier, found `2222222222222222222222222222222222222222`
diff --git a/tests/ui/parser/issues/issue-110014.stderr b/tests/ui/parser/issues/issue-110014.stderr
new file mode 100644
index 000000000000..7f1dd592e123
--- /dev/null
+++ b/tests/ui/parser/issues/issue-110014.stderr
@@ -0,0 +1,19 @@
+error: unknown start of token: `
+  --> $DIR/issue-110014.rs:1:3
+   |
+LL | fn`2222222222222222222222222222222222222222() {}
+   |   ^
+   |
+help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not
+   |
+LL | fn'2222222222222222222222222222222222222222() {}
+   |   ~
+
+error: expected identifier, found `2222222222222222222222222222222222222222`
+  --> $DIR/issue-110014.rs:1:4
+   |
+LL | fn`2222222222222222222222222222222222222222() {}
+   |    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected identifier
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/parser/issues/issue-48508.rs b/tests/ui/parser/issues/issue-48508.rs
index 37d04c5d65f0..1e7db9df814b 100644
--- a/tests/ui/parser/issues/issue-48508.rs
+++ b/tests/ui/parser/issues/issue-48508.rs
@@ -7,7 +7,6 @@
 // issue-48508-aux.rs
 
 // compile-flags:-g
-// ignore-pretty issue #37195
 // ignore-asmjs wasm2js does not support source maps yet
 
 #![allow(uncommon_codepoints)]
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
index 29cd6c45c34b..25838fbf0abd 100644
--- a/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
+++ b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
@@ -2,18 +2,16 @@ error: cannot move out of value because it is borrowed
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14
    |
 LL |         Some(ref _y @ _z) => {}
-   |              ------^^^--
-   |              |        |
-   |              |        value is moved into `_z` here
+   |              ^^^^^^   -- value is moved into `_z` here
+   |              |
    |              value is borrowed by `_y` here
 
 error: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:19:14
    |
 LL |         Some(_z @ ref _y) => {}
-   |              --^^^------
-   |              |    |
-   |              |    value borrowed here after move
+   |              ^^   ------ value borrowed here after move
+   |              |
    |              value moved into `_z` here
    |              move occurs because `_z` has type `X` which does not implement the `Copy` trait
    |
@@ -26,18 +24,16 @@ error: cannot move out of value because it is borrowed
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
    |
 LL |         Some(ref mut _y @ _z) => {}
-   |              ----------^^^--
-   |              |            |
-   |              |            value is moved into `_z` here
+   |              ^^^^^^^^^^   -- value is moved into `_z` here
+   |              |
    |              value is mutably borrowed by `_y` here
 
 error: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:33:14
    |
 LL |         Some(_z @ ref mut _y) => {}
-   |              --^^^----------
-   |              |    |
-   |              |    value borrowed here after move
+   |              ^^   ---------- value borrowed here after move
+   |              |
    |              value moved into `_z` here
    |              move occurs because `_z` has type `X` which does not implement the `Copy` trait
    |
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
index 2c123b01e173..9305facc406f 100644
--- a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
@@ -2,72 +2,64 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-at-and-box.rs:31:9
    |
 LL |     let ref a @ box b = Box::new(NC);
-   |         -----^^^^^^^-
-   |         |           |
-   |         |           value is moved into `b` here
+   |         ^^^^^       - value is moved into `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-at-and-box.rs:34:9
    |
 LL |     let ref a @ box ref mut b = Box::new(nc());
-   |         -----^^^^^^^---------
-   |         |           |
-   |         |           value is mutably borrowed by `b` here
+   |         ^^^^^       --------- value is mutably borrowed by `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-at-and-box.rs:36:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
-   |         -----^^^^^^^---------
-   |         |           |
-   |         |           value is mutably borrowed by `b` here
+   |         ^^^^^       --------- value is mutably borrowed by `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-at-and-box.rs:38:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
-   |         -----^^^^^^^---------
-   |         |           |
-   |         |           value is mutably borrowed by `b` here
+   |         ^^^^^       --------- value is mutably borrowed by `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-at-and-box.rs:42:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
-   |         -----^^^^^^^---------
-   |         |           |
-   |         |           value is mutably borrowed by `b` here
+   |         ^^^^^       --------- value is mutably borrowed by `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-at-and-box.rs:48:9
    |
 LL |     let ref mut a @ box ref b = Box::new(NC);
-   |         ---------^^^^^^^-----
-   |         |               |
-   |         |               value is borrowed by `b` here
+   |         ^^^^^^^^^       ----- value is borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-at-and-box.rs:62:9
    |
 LL |         ref mut a @ box ref b => {
-   |         ---------^^^^^^^-----
-   |         |               |
-   |         |               value is borrowed by `b` here
+   |         ^^^^^^^^^       ----- value is borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-at-and-box.rs:54:11
    |
 LL |     fn f5(ref mut a @ box ref b: Box) {
-   |           ---------^^^^^^^-----
-   |           |               |
-   |           |               value is borrowed by `b` here
+   |           ^^^^^^^^^       ----- value is borrowed by `b` here
+   |           |
    |           value is mutably borrowed by `a` here
 
 error[E0382]: borrow of moved value
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
index d6474f1b49fb..c440f4619f52 100644
--- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
@@ -2,9 +2,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:6:9
    |
 LL |     let a @ ref b = U;
-   |         -^^^-----
-   |         |   |
-   |         |   value borrowed here after move
+   |         ^   ----- value borrowed here after move
+   |         |
    |         value moved into `a` here
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
    |
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
index 389e86e64645..13989ebadcb5 100644
--- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
@@ -2,9 +2,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:22:9
    |
 LL |     let a @ ref b = U;
-   |         -^^^-----
-   |         |   |
-   |         |   value borrowed here after move
+   |         ^   ----- value borrowed here after move
+   |         |
    |         value moved into `a` here
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
    |
@@ -17,9 +16,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
-   |         -^^^^^^^^^^^^---------^^^^^^-----^
-   |         |            |              |
-   |         |            |              value borrowed here after move
+   |         ^            ---------      ----- value borrowed here after move
+   |         |            |
    |         |            value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
@@ -33,9 +31,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:14
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
-   |              -----^^^---------
-   |              |       |
-   |              |       value borrowed here after move
+   |              ^^^^^   --------- value borrowed here after move
+   |              |
    |              value moved into `b` here
    |              move occurs because `b` has type `U` which does not implement the `Copy` trait
    |
@@ -48,9 +45,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:33
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
-   |                                 -^^^-----
-   |                                 |   |
-   |                                 |   value borrowed here after move
+   |                                 ^   ----- value borrowed here after move
+   |                                 |
    |                                 value moved into `d` here
    |                                 move occurs because `d` has type `U` which does not implement the `Copy` trait
    |
@@ -63,9 +59,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9
    |
 LL |     let a @ [ref mut b, ref c] = [U, U];
-   |         -^^^^---------^^-----^
-   |         |    |          |
-   |         |    |          value borrowed here after move
+   |         ^    ---------  ----- value borrowed here after move
+   |         |    |
    |         |    value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
@@ -79,9 +74,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9
    |
 LL |     let a @ ref b = u();
-   |         -^^^-----
-   |         |   |
-   |         |   value borrowed here after move
+   |         ^   ----- value borrowed here after move
+   |         |
    |         value moved into `a` here
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
    |
@@ -94,9 +88,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
-   |         -^^^^^^^^^^^^---------^^^^^^-----^
-   |         |            |              |
-   |         |            |              value borrowed here after move
+   |         ^            ---------      ----- value borrowed here after move
+   |         |            |
    |         |            value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
@@ -110,9 +103,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:14
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
-   |              -----^^^---------
-   |              |       |
-   |              |       value borrowed here after move
+   |              ^^^^^   --------- value borrowed here after move
+   |              |
    |              value moved into `b` here
    |              move occurs because `b` has type `U` which does not implement the `Copy` trait
    |
@@ -125,9 +117,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:33
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
-   |                                 -^^^-----
-   |                                 |   |
-   |                                 |   value borrowed here after move
+   |                                 ^   ----- value borrowed here after move
+   |                                 |
    |                                 value moved into `d` here
    |                                 move occurs because `d` has type `U` which does not implement the `Copy` trait
    |
@@ -140,9 +131,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9
    |
 LL |     let a @ [ref mut b, ref c] = [u(), u()];
-   |         -^^^^---------^^-----^
-   |         |    |          |
-   |         |    |          value borrowed here after move
+   |         ^    ---------  ----- value borrowed here after move
+   |         |    |
    |         |    value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
@@ -156,9 +146,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:42:9
    |
 LL |         a @ Some(ref b) => {}
-   |         -^^^^^^^^-----^
-   |         |        |
-   |         |        value borrowed here after move
+   |         ^        ----- value borrowed here after move
+   |         |
    |         value moved into `a` here
    |         move occurs because `a` has type `Option` which does not implement the `Copy` trait
    |
@@ -171,9 +160,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:9
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
-   |         -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^
-   |         |                 |              |
-   |         |                 |              value borrowed here after move
+   |         ^                 ---------      ----- value borrowed here after move
+   |         |                 |
    |         |                 value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
@@ -187,9 +175,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:19
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
-   |                   -----^^^---------
-   |                   |       |
-   |                   |       value borrowed here after move
+   |                   ^^^^^   --------- value borrowed here after move
+   |                   |
    |                   value moved into `b` here
    |                   move occurs because `b` has type `U` which does not implement the `Copy` trait
    |
@@ -202,9 +189,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
-   |                                      -^^^-----
-   |                                      |   |
-   |                                      |   value borrowed here after move
+   |                                      ^   ----- value borrowed here after move
+   |                                      |
    |                                      value moved into `d` here
    |                                      move occurs because `d` has type `U` which does not implement the `Copy` trait
    |
@@ -217,9 +203,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9
    |
 LL |         mut a @ Some([ref b, ref mut c]) => {}
-   |         -----^^^^^^^^^-----^^---------^^
-   |         |             |      |
-   |         |             |      value borrowed here after move
+   |         ^^^^^         -----  --------- value borrowed here after move
+   |         |             |
    |         |             value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
@@ -233,9 +218,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9
    |
 LL |         a @ Some(ref b) => {}
-   |         -^^^^^^^^-----^
-   |         |        |
-   |         |        value borrowed here after move
+   |         ^        ----- value borrowed here after move
+   |         |
    |         value moved into `a` here
    |         move occurs because `a` has type `Option` which does not implement the `Copy` trait
    |
@@ -248,9 +232,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:9
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
-   |         -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^
-   |         |                 |              |
-   |         |                 |              value borrowed here after move
+   |         ^                 ---------      ----- value borrowed here after move
+   |         |                 |
    |         |                 value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
@@ -264,9 +247,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:19
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
-   |                   -----^^^---------
-   |                   |       |
-   |                   |       value borrowed here after move
+   |                   ^^^^^   --------- value borrowed here after move
+   |                   |
    |                   value moved into `b` here
    |                   move occurs because `b` has type `U` which does not implement the `Copy` trait
    |
@@ -279,9 +261,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
-   |                                      -^^^-----
-   |                                      |   |
-   |                                      |   value borrowed here after move
+   |                                      ^   ----- value borrowed here after move
+   |                                      |
    |                                      value moved into `d` here
    |                                      move occurs because `d` has type `U` which does not implement the `Copy` trait
    |
@@ -294,9 +275,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:9
    |
 LL |         mut a @ Some([ref b, ref mut c]) => {}
-   |         -----^^^^^^^^^-----^^---------^^
-   |         |             |      |
-   |         |             |      value borrowed here after move
+   |         ^^^^^         -----  --------- value borrowed here after move
+   |         |             |
    |         |             value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
@@ -310,9 +290,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:11:11
    |
 LL |     fn f1(a @ ref b: U) {}
-   |           -^^^-----
-   |           |   |
-   |           |   value borrowed here after move
+   |           ^   ----- value borrowed here after move
+   |           |
    |           value moved into `a` here
    |           move occurs because `a` has type `U` which does not implement the `Copy` trait
    |
@@ -325,9 +304,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
-   |           -----^^^^^^^^-----^^^^^^^^^^-----^
-   |           |            |              |
-   |           |            |              value borrowed here after move
+   |           ^^^^^        -----          ----- value borrowed here after move
+   |           |            |
    |           |            value borrowed here after move
    |           value moved into `a` here
    |           move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
@@ -341,9 +319,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:20
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
-   |                    -^^^-----
-   |                    |   |
-   |                    |   value borrowed here after move
+   |                    ^   ----- value borrowed here after move
+   |                    |
    |                    value moved into `b` here
    |                    move occurs because `b` has type `U` which does not implement the `Copy` trait
    |
@@ -356,9 +333,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:31
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
-   |                               -----^^^-----
-   |                               |       |
-   |                               |       value borrowed here after move
+   |                               ^^^^^   ----- value borrowed here after move
+   |                               |
    |                               value moved into `d` here
    |                               move occurs because `d` has type `U` which does not implement the `Copy` trait
    |
@@ -371,9 +347,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:19:11
    |
 LL |     fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
-   |           -^^^^---------^^-----^
-   |           |    |          |
-   |           |    |          value borrowed here after move
+   |           ^    ---------  ----- value borrowed here after move
+   |           |    |
    |           |    value borrowed here after move
    |           value moved into `a` here
    |           move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
index 4f7fbc9e04b0..00593b2a98f2 100644
--- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
@@ -2,18 +2,16 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:24:9
    |
 LL |     let ref a @ b = U;
-   |         -----^^^-
-   |         |       |
-   |         |       value is moved into `b` here
+   |         ^^^^^   - value is moved into `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:26:9
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
-   |         -----^^^^^^^^^^^^-----^^^^^^^^^^-^
-   |         |                |              |
-   |         |                |              value is moved into `e` here
+   |         ^^^^^            -----          - value is moved into `e` here
+   |         |                |
    |         |                value is moved into `c` here
    |         value is borrowed by `a` here
 
@@ -21,27 +19,24 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:26:18
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
-   |                  -----^^^-----
-   |                  |       |
-   |                  |       value is moved into `c` here
+   |                  ^^^^^   ----- value is moved into `c` here
+   |                  |
    |                  value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:26:33
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
-   |                                 -----^^^-
-   |                                 |       |
-   |                                 |       value is moved into `e` here
+   |                                 ^^^^^   - value is moved into `e` here
+   |                                 |
    |                                 value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
    |
 LL |     let ref mut a @ [b, mut c] = [U, U];
-   |         ---------^^^^-^^-----^
-   |         |            |  |
-   |         |            |  value is moved into `c` here
+   |         ^^^^^^^^^    -  ----- value is moved into `c` here
+   |         |            |
    |         |            value is moved into `b` here
    |         value is mutably borrowed by `a` here
 
@@ -49,18 +44,16 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
    |
 LL |     let ref a @ b = u();
-   |         -----^^^-
-   |         |       |
-   |         |       value is moved into `b` here
+   |         ^^^^^   - value is moved into `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
-   |         -----^^^^^^^^^^^^-----^^^^^^^^^^-^
-   |         |                |              |
-   |         |                |              value is moved into `e` here
+   |         ^^^^^            -----          - value is moved into `e` here
+   |         |                |
    |         |                value is moved into `c` here
    |         value is borrowed by `a` here
 
@@ -68,27 +61,24 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
-   |                  -----^^^-----
-   |                  |       |
-   |                  |       value is moved into `c` here
+   |                  ^^^^^   ----- value is moved into `c` here
+   |                  |
    |                  value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
-   |                                 -----^^^-
-   |                                 |       |
-   |                                 |       value is moved into `e` here
+   |                                 ^^^^^   - value is moved into `e` here
+   |                                 |
    |                                 value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
    |
 LL |     let ref mut a @ [b, mut c] = [u(), u()];
-   |         ---------^^^^-^^-----^
-   |         |            |  |
-   |         |            |  value is moved into `c` here
+   |         ^^^^^^^^^    -  ----- value is moved into `c` here
+   |         |            |
    |         |            value is moved into `b` here
    |         value is mutably borrowed by `a` here
 
@@ -96,18 +86,16 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:47:9
    |
 LL |         ref a @ Some(b) => {}
-   |         -----^^^^^^^^-^
-   |         |            |
-   |         |            value is moved into `b` here
+   |         ^^^^^        - value is moved into `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
-   |         -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
-   |         |                     |              |
-   |         |                     |              value is moved into `e` here
+   |         ^^^^^                 -----          - value is moved into `e` here
+   |         |                     |
    |         |                     value is moved into `c` here
    |         value is borrowed by `a` here
 
@@ -115,27 +103,24 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:52:23
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
-   |                       -----^^^-----
-   |                       |       |
-   |                       |       value is moved into `c` here
+   |                       ^^^^^   ----- value is moved into `c` here
+   |                       |
    |                       value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:52:38
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
-   |                                      -----^^^-
-   |                                      |       |
-   |                                      |       value is moved into `e` here
+   |                                      ^^^^^   - value is moved into `e` here
+   |                                      |
    |                                      value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:59:9
    |
 LL |         ref mut a @ Some([b, mut c]) => {}
-   |         ---------^^^^^^^^^-^^-----^^
-   |         |                 |  |
-   |         |                 |  value is moved into `c` here
+   |         ^^^^^^^^^         -  ----- value is moved into `c` here
+   |         |                 |
    |         |                 value is moved into `b` here
    |         value is mutably borrowed by `a` here
 
@@ -143,18 +128,16 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:64:9
    |
 LL |         ref a @ Some(b) => {}
-   |         -----^^^^^^^^-^
-   |         |            |
-   |         |            value is moved into `b` here
+   |         ^^^^^        - value is moved into `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
-   |         -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
-   |         |                     |              |
-   |         |                     |              value is moved into `e` here
+   |         ^^^^^                 -----          - value is moved into `e` here
+   |         |                     |
    |         |                     value is moved into `c` here
    |         value is borrowed by `a` here
 
@@ -162,27 +145,24 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
-   |                       -----^^^-----
-   |                       |       |
-   |                       |       value is moved into `c` here
+   |                       ^^^^^   ----- value is moved into `c` here
+   |                       |
    |                       value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
-   |                                      -----^^^-
-   |                                      |       |
-   |                                      |       value is moved into `e` here
+   |                                      ^^^^^   - value is moved into `e` here
+   |                                      |
    |                                      value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:78:9
    |
 LL |         ref mut a @ Some([b, mut c]) => {}
-   |         ---------^^^^^^^^^-^^-----^^
-   |         |                 |  |
-   |         |                 |  value is moved into `c` here
+   |         ^^^^^^^^^         -  ----- value is moved into `c` here
+   |         |                 |
    |         |                 value is moved into `b` here
    |         value is mutably borrowed by `a` here
 
@@ -190,18 +170,16 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11
    |
 LL |     fn f1(ref a @ b: U) {}
-   |           -----^^^-
-   |           |       |
-   |           |       value is moved into `b` here
+   |           ^^^^^   - value is moved into `b` here
+   |           |
    |           value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
-   |           -----^^^^^^^^^^^^-----^^^^^^^^^^-^
-   |           |                |              |
-   |           |                |              value is moved into `e` here
+   |           ^^^^^            -----          - value is moved into `e` here
+   |           |                |
    |           |                value is moved into `c` here
    |           value is borrowed by `a` here
 
@@ -209,27 +187,24 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
-   |                    -----^^^-----
-   |                    |       |
-   |                    |       value is moved into `c` here
+   |                    ^^^^^   ----- value is moved into `c` here
+   |                    |
    |                    value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
-   |                                   -----^^^-
-   |                                   |       |
-   |                                   |       value is moved into `e` here
+   |                                   ^^^^^   - value is moved into `e` here
+   |                                   |
    |                                   value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
    |
 LL |     fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
-   |           ---------^^^^-^^-----^
-   |           |            |  |
-   |           |            |  value is moved into `c` here
+   |           ^^^^^^^^^    -  ----- value is moved into `c` here
+   |           |            |
    |           |            value is moved into `b` here
    |           value is mutably borrowed by `a` here
 
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
index f51b5041858c..d6409d1b643b 100644
--- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
@@ -2,18 +2,16 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:9
    |
 LL |         ref mut z @ &mut Some(ref a) => {
-   |         ---------^^^^^^^^^^^^^-----^
-   |         |                     |
-   |         |                     value is borrowed by `a` here
+   |         ^^^^^^^^^             ----- value is borrowed by `a` here
+   |         |
    |         value is mutably borrowed by `z` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:9
    |
 LL |     let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
-   |         ---------^^^^-----------------^
-   |         |            |       |
-   |         |            |       value is mutably borrowed by `c` here
+   |         ^^^^^^^^^    -----   --------- value is mutably borrowed by `c` here
+   |         |            |
    |         |            value is borrowed by `b` here
    |         value is mutably borrowed by `a` here
 
@@ -21,36 +19,32 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:22
    |
 LL |     let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
-   |                      -----^^^---------
-   |                      |       |
-   |                      |       value is mutably borrowed by `c` here
+   |                      ^^^^^   --------- value is mutably borrowed by `c` here
+   |                      |
    |                      value is borrowed by `b` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:37:9
    |
 LL |     let ref a @ ref mut b = U;
-   |         -----^^^---------
-   |         |       |
-   |         |       value is mutably borrowed by `b` here
+   |         ^^^^^   --------- value is mutably borrowed by `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9
    |
 LL |     let ref mut a @ ref b = U;
-   |         ---------^^^-----
-   |         |           |
-   |         |           value is borrowed by `b` here
+   |         ^^^^^^^^^   ----- value is borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         -----^^^^---------^^---------^
-   |         |        |          |
-   |         |        |          value is mutably borrowed by `c` here
+   |         ^^^^^    ---------  --------- value is mutably borrowed by `c` here
+   |         |        |
    |         |        value is mutably borrowed by `b` here
    |         value is borrowed by `a` here
 
@@ -58,9 +52,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9
    |
 LL |     let ref mut a @ (ref b, ref c) = (U, U);
-   |         ---------^^^^-----^^-----^
-   |         |            |      |
-   |         |            |      value is borrowed by `c` here
+   |         ^^^^^^^^^    -----  ----- value is borrowed by `c` here
+   |         |            |
    |         |            value is borrowed by `b` here
    |         value is mutably borrowed by `a` here
 
@@ -68,153 +61,136 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9
    |
 LL |     let ref mut a @ ref b = u();
-   |         ---------^^^-----
-   |         |           |
-   |         |           value is borrowed by `b` here
+   |         ^^^^^^^^^   ----- value is borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9
    |
 LL |     let ref a @ ref mut b = u();
-   |         -----^^^---------
-   |         |       |
-   |         |       value is mutably borrowed by `b` here
+   |         ^^^^^   --------- value is mutably borrowed by `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:57:9
    |
 LL |     let ref mut a @ ref b = U;
-   |         ---------^^^-----
-   |         |           |
-   |         |           value is borrowed by `b` here
+   |         ^^^^^^^^^   ----- value is borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:61:9
    |
 LL |     let ref a @ ref mut b = U;
-   |         -----^^^---------
-   |         |       |
-   |         |       value is mutably borrowed by `b` here
+   |         ^^^^^   --------- value is mutably borrowed by `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:9
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
-   |         ---------^^^^^^-----^
-   |         |              |
-   |         |              value is borrowed by `b` here
+   |         ^^^^^^^^^      ----- value is borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:33
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
-   |                                 ---------^^^^^^^-----^
-   |                                 |               |
-   |                                 |               value is borrowed by `b` here
+   |                                 ^^^^^^^^^       ----- value is borrowed by `b` here
+   |                                 |
    |                                 value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:9
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
-   |         -----^^^^^^---------^
-   |         |          |
-   |         |          value is mutably borrowed by `b` here
+   |         ^^^^^      --------- value is mutably borrowed by `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:33
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
-   |                                 -----^^^^^^^---------^
-   |                                 |           |
-   |                                 |           value is mutably borrowed by `b` here
+   |                                 ^^^^^       --------- value is mutably borrowed by `b` here
+   |                                 |
    |                                 value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:9
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
-   |         -----^^^^^^---------^
-   |         |          |
-   |         |          value is mutably borrowed by `b` here
+   |         ^^^^^      --------- value is mutably borrowed by `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:33
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
-   |                                 -----^^^^^^^---------^
-   |                                 |           |
-   |                                 |           value is mutably borrowed by `b` here
+   |                                 ^^^^^       --------- value is mutably borrowed by `b` here
+   |                                 |
    |                                 value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:9
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
-   |         ---------^^^^^^-----^
-   |         |              |
-   |         |              value is borrowed by `b` here
+   |         ^^^^^^^^^      ----- value is borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:33
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
-   |                                 ---------^^^^^^^-----^
-   |                                 |               |
-   |                                 |               value is borrowed by `b` here
+   |                                 ^^^^^^^^^       ----- value is borrowed by `b` here
+   |                                 |
    |                                 value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:9
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
-   |         -----^^^^^^---------^
-   |         |          |
-   |         |          value is mutably borrowed by `b` here
+   |         ^^^^^      --------- value is mutably borrowed by `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:33
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
-   |                                 -----^^^^^^^---------^
-   |                                 |           |
-   |                                 |           value is mutably borrowed by `b` here
+   |                                 ^^^^^       --------- value is mutably borrowed by `b` here
+   |                                 |
    |                                 value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:9
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
-   |         ---------^^^^^^-----^
-   |         |              |
-   |         |              value is borrowed by `b` here
+   |         ^^^^^^^^^      ----- value is borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:33
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
-   |                                 ---------^^^^^^^-----^
-   |                                 |               |
-   |                                 |               value is borrowed by `b` here
+   |                                 ^^^^^^^^^       ----- value is borrowed by `b` here
+   |                                 |
    |                                 value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         -----^^^^---------^^---------^
-   |         |        |          |
-   |         |        |          value is mutably borrowed by `c` here
+   |         ^^^^^    ---------  --------- value is mutably borrowed by `c` here
+   |         |        |
    |         |        value is mutably borrowed by `b` here
    |         value is borrowed by `a` here
 
@@ -222,9 +198,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         -----^^^^---------^^---------^
-   |         |        |          |
-   |         |        |          value is mutably borrowed by `c` here
+   |         ^^^^^    ---------  --------- value is mutably borrowed by `c` here
+   |         |        |
    |         |        value is mutably borrowed by `b` here
    |         value is borrowed by `a` here
 
@@ -232,9 +207,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         -----^^^^---------^^---------^
-   |         |        |          |
-   |         |        |          value is mutably borrowed by `c` here
+   |         ^^^^^    ---------  --------- value is mutably borrowed by `c` here
+   |         |        |
    |         |        value is mutably borrowed by `b` here
    |         value is borrowed by `a` here
 
@@ -242,9 +216,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:134:9
    |
 LL |     let ref mut a @ (ref b, ref c) = (U, U);
-   |         ---------^^^^-----^^-----^
-   |         |            |      |
-   |         |            |      value is borrowed by `c` here
+   |         ^^^^^^^^^    -----  ----- value is borrowed by `c` here
+   |         |            |
    |         |            value is borrowed by `b` here
    |         value is mutably borrowed by `a` here
 
@@ -252,36 +225,32 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:22:11
    |
 LL |     fn f1(ref a @ ref mut b: U) {}
-   |           -----^^^---------
-   |           |       |
-   |           |       value is mutably borrowed by `b` here
+   |           ^^^^^   --------- value is mutably borrowed by `b` here
+   |           |
    |           value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11
    |
 LL |     fn f2(ref mut a @ ref b: U) {}
-   |           ---------^^^-----
-   |           |           |
-   |           |           value is borrowed by `b` here
+   |           ^^^^^^^^^   ----- value is borrowed by `b` here
+   |           |
    |           value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11
    |
 LL |     fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {}
-   |           -----^^^^^^^^^^^----------------^^^^^^^^
-   |           |               |
-   |           |               value is mutably borrowed by `mid` here
+   |           ^^^^^           ----------- value is mutably borrowed by `mid` here
+   |           |
    |           value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:22
    |
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
-   |                      -----^^^-------------
-   |                      |       |           |
-   |                      |       |           value is moved into `c` here
+   |                      ^^^^^   ---------   - value is moved into `c` here
+   |                      |       |
    |                      |       value is mutably borrowed by `b` here
    |                      value is borrowed by `a` here
 
@@ -289,9 +258,8 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30
    |
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
-   |                              ---------^^^-
-   |                              |           |
-   |                              |           value is moved into `c` here
+   |                              ^^^^^^^^^   - value is moved into `c` here
+   |                              |
    |                              value is mutably borrowed by `b` here
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
index a0cb04a064e0..24189d0615c7 100644
--- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
@@ -2,98 +2,80 @@ error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:26:9
    |
 LL |     let ref mut a @ ref mut b = U;
-   |         ---------^^^---------
-   |         |           |
-   |         |           value is mutably borrowed by `b` here
+   |         ^^^^^^^^^   --------- value is mutably borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
    |
 LL |     let ref mut a @ ref mut b = U;
-   |         ---------^^^---------
-   |         |           |
-   |         |           value is mutably borrowed by `b` here
+   |         ^^^^^^^^^   --------- value is mutably borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:33:9
    |
 LL |     let ref mut a @ ref mut b = U;
-   |         ---------^^^---------
-   |         |           |
-   |         |           value is mutably borrowed by `b` here
+   |         ^^^^^^^^^   --------- value is mutably borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:36:9
    |
 LL |     let ref mut a @ ref mut b = U;
-   |         ---------^^^---------
-   |         |           |
-   |         |           value is mutably borrowed by `b` here
+   |         ^^^^^^^^^   --------- value is mutably borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9
    |
 LL |     let ref mut a @ ref mut b = U;
-   |         ---------^^^---------
-   |         |           |
-   |         |           value is mutably borrowed by `b` here
+   |         ^^^^^^^^^   --------- value is mutably borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:44:9
    |
-LL |       let ref mut a @ (
-   |           ^--------
-   |           |
-   |  _________value is mutably borrowed by `a` here
-   | |
-LL | |
-LL | |         ref mut b,
-   | |         --------- value is mutably borrowed by `b` here
-LL | |         [
-LL | |             ref mut c,
-   | |             --------- value is mutably borrowed by `c` here
-LL | |             ref mut d,
-   | |             --------- value is mutably borrowed by `d` here
-LL | |             ref e,
-   | |             ----- value is borrowed by `e` here
-LL | |         ]
-LL | |     ) = (U, [U, U, U]);
-   | |_____^
+LL |     let ref mut a @ (
+   |         ^^^^^^^^^ value is mutably borrowed by `a` here
+LL |
+LL |         ref mut b,
+   |         --------- value is mutably borrowed by `b` here
+LL |         [
+LL |             ref mut c,
+   |             --------- value is mutably borrowed by `c` here
+LL |             ref mut d,
+   |             --------- value is mutably borrowed by `d` here
+LL |             ref e,
+   |             ----- value is borrowed by `e` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:54:9
    |
-LL |       let ref mut a @ (
-   |           ^--------
-   |           |
-   |  _________value is mutably borrowed by `a` here
-   | |
-LL | |
-LL | |             ref mut b,
-   | |             --------- value is mutably borrowed by `b` here
-LL | |             [
-LL | |                 ref mut c,
-   | |                 --------- value is mutably borrowed by `c` here
-LL | |                 ref mut d,
-   | |                 --------- value is mutably borrowed by `d` here
-LL | |                 ref e,
-   | |                 ----- value is borrowed by `e` here
-LL | |             ]
-LL | |         ) = (u(), [u(), u(), u()]);
-   | |_________^
+LL |     let ref mut a @ (
+   |         ^^^^^^^^^ value is mutably borrowed by `a` here
+LL |
+LL |             ref mut b,
+   |             --------- value is mutably borrowed by `b` here
+LL |             [
+LL |                 ref mut c,
+   |                 --------- value is mutably borrowed by `c` here
+LL |                 ref mut d,
+   |                 --------- value is mutably borrowed by `d` here
+LL |                 ref e,
+   |                 ----- value is borrowed by `e` here
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:64:9
    |
 LL |     let a @ (ref mut b, ref mut c) = (U, U);
-   |         -^^^^---------^^---------^
-   |         |    |          |
-   |         |    |          value borrowed here after move
+   |         ^    ---------  --------- value borrowed here after move
+   |         |    |
    |         |    value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
@@ -107,9 +89,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:67:9
    |
 LL |     let a @ (b, [c, d]) = &mut val; // Same as ^--
-   |         -^^^^-^^^-^^-^^
-   |         |    |   |  |
-   |         |    |   |  value borrowed here after move
+   |         ^    -   -  - value borrowed here after move
+   |         |    |   |
    |         |    |   value borrowed here after move
    |         |    value borrowed here after move
    |         value moved into `a` here
@@ -124,9 +105,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9
    |
 LL |     let a @ &mut ref mut b = &mut U;
-   |         -^^^^^^^^---------
-   |         |        |
-   |         |        value borrowed here after move
+   |         ^        --------- value borrowed here after move
+   |         |
    |         value moved into `a` here
    |         move occurs because `a` has type `&mut U` which does not implement the `Copy` trait
    |
@@ -139,9 +119,8 @@ error: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:72:9
    |
 LL |     let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
-   |         -^^^^^^^^^---------^^---------^
-   |         |         |          |
-   |         |         |          value borrowed here after move
+   |         ^         ---------  --------- value borrowed here after move
+   |         |         |
    |         |         value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait
@@ -155,117 +134,99 @@ error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |         ---------^^^^^^---------^
-   |         |              |
-   |         |              value is mutably borrowed by `b` here
+   |         ^^^^^^^^^      --------- value is mutably borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:76:37
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |                                     ---------^^^^^^^---------^
-   |                                     |               |
-   |                                     |               value is mutably borrowed by `b` here
+   |                                     ^^^^^^^^^       --------- value is mutably borrowed by `b` here
+   |                                     |
    |                                     value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |         ---------^^^^^^---------^
-   |         |              |
-   |         |              value is mutably borrowed by `b` here
+   |         ^^^^^^^^^      --------- value is mutably borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |                                     ---------^^^^^^^---------^
-   |                                     |               |
-   |                                     |               value is mutably borrowed by `b` here
+   |                                     ^^^^^^^^^       --------- value is mutably borrowed by `b` here
+   |                                     |
    |                                     value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:89:9
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |         ---------^^^^^^---------^
-   |         |              |
-   |         |              value is mutably borrowed by `b` here
+   |         ^^^^^^^^^      --------- value is mutably borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:89:37
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |                                     ---------^^^^^^^---------^
-   |                                     |               |
-   |                                     |               value is mutably borrowed by `b` here
+   |                                     ^^^^^^^^^       --------- value is mutably borrowed by `b` here
+   |                                     |
    |                                     value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:101:9
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |         ---------^^^^^^---------^
-   |         |              |
-   |         |              value is mutably borrowed by `b` here
+   |         ^^^^^^^^^      --------- value is mutably borrowed by `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:101:37
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |                                     ---------^^^^^^^---------^
-   |                                     |               |
-   |                                     |               value is mutably borrowed by `b` here
+   |                                     ^^^^^^^^^       --------- value is mutably borrowed by `b` here
+   |                                     |
    |                                     value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:8:11
    |
 LL |     fn f1(ref mut a @ ref mut b: U) {}
-   |           ---------^^^---------
-   |           |           |
-   |           |           value is mutably borrowed by `b` here
+   |           ^^^^^^^^^   --------- value is mutably borrowed by `b` here
+   |           |
    |           value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11
    |
 LL |     fn f2(ref mut a @ ref mut b: U) {}
-   |           ---------^^^---------
-   |           |           |
-   |           |           value is mutably borrowed by `b` here
+   |           ^^^^^^^^^   --------- value is mutably borrowed by `b` here
+   |           |
    |           value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:13:9
    |
-LL |           ref mut a @ [
-   |           ^--------
-   |           |
-   |  _________value is mutably borrowed by `a` here
-   | |
-LL | |
-LL | |             [ref b @ .., _],
-   | |              ---------- value is borrowed by `b` here
-LL | |             [_, ref mut mid @ ..],
-   | |                 ---------------- value is mutably borrowed by `mid` here
-LL | |             ..,
-LL | |             [..],
-LL | |         ] : [[U; 4]; 5]
-   | |_________^
+LL |         ref mut a @ [
+   |         ^^^^^^^^^ value is mutably borrowed by `a` here
+LL |
+LL |             [ref b @ .., _],
+   |              ----- value is borrowed by `b` here
+LL |             [_, ref mut mid @ ..],
+   |                 ----------- value is mutably borrowed by `mid` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:21:22
    |
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
-   |                      ---------^^^-------------
-   |                      |           |           |
-   |                      |           |           value is moved into `c` here
+   |                      ^^^^^^^^^   ---------   - value is moved into `c` here
+   |                      |           |
    |                      |           value is mutably borrowed by `b` here
    |                      value is mutably borrowed by `a` here
 
@@ -273,9 +234,8 @@ error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34
    |
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
-   |                                  ---------^^^-
-   |                                  |           |
-   |                                  |           value is moved into `c` here
+   |                                  ^^^^^^^^^   - value is moved into `c` here
+   |                                  |
    |                                  value is mutably borrowed by `b` here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
diff --git a/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
index 73ebbf48118d..36515c1a29bb 100644
--- a/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
+++ b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
@@ -2,36 +2,32 @@ error: cannot move out of value because it is borrowed
   --> $DIR/default-binding-modes-both-sides-independent.rs:26:9
    |
 LL |     let ref a @ b = NotCopy;
-   |         -----^^^-
-   |         |       |
-   |         |       value is moved into `b` here
+   |         ^^^^^   - value is moved into `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
    |
 LL |     let ref mut a @ b = NotCopy;
-   |         ---------^^^-
-   |         |           |
-   |         |           value is moved into `b` here
+   |         ^^^^^^^^^   - value is moved into `b` here
+   |         |
    |         value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/default-binding-modes-both-sides-independent.rs:34:12
    |
 LL |         Ok(ref a @ b) | Err(b @ ref a) => {
-   |            -----^^^-
-   |            |       |
-   |            |       value is moved into `b` here
+   |            ^^^^^   - value is moved into `b` here
+   |            |
    |            value is borrowed by `a` here
 
 error: borrow of moved value
   --> $DIR/default-binding-modes-both-sides-independent.rs:34:29
    |
 LL |         Ok(ref a @ b) | Err(b @ ref a) => {
-   |                             -^^^-----
-   |                             |   |
-   |                             |   value borrowed here after move
+   |                             ^   ----- value borrowed here after move
+   |                             |
    |                             value moved into `b` here
    |                             move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait
    |
@@ -44,9 +40,8 @@ error: cannot move out of value because it is borrowed
   --> $DIR/default-binding-modes-both-sides-independent.rs:42:9
    |
 LL |         ref a @ b => {
-   |         -----^^^-
-   |         |       |
-   |         |       value is moved into `b` here
+   |         ^^^^^   - value is moved into `b` here
+   |         |
    |         value is borrowed by `a` here
 
 error[E0382]: borrow of moved value
diff --git a/tests/ui/pattern/issue-106552.stderr b/tests/ui/pattern/issue-106552.stderr
index ed5d40c09685..96f3d68458fa 100644
--- a/tests/ui/pattern/issue-106552.stderr
+++ b/tests/ui/pattern/issue-106552.stderr
@@ -9,8 +9,8 @@ LL |     let 5 = 6;
    = note: the matched value is of type `i32`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let 5 = 6 { todo!() }
-   |     ++           ~~~~~~~~~~~
+LL |     if let 5 = 6 { todo!() };
+   |     ++           +++++++++++
 help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
    |
 LL |     let _5 = 6;
@@ -20,7 +20,7 @@ error[E0005]: refutable pattern in local binding
   --> $DIR/issue-106552.rs:5:9
    |
 LL |     let x @ 5 = 6;
-   |         ^^^^^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered
+   |         ^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
diff --git a/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr b/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr
index 54ecc24981f8..62c90b638d7c 100644
--- a/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr
+++ b/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr
@@ -1,15 +1,15 @@
-error[E0158]: associated consts cannot be referenced in patterns
-  --> $DIR/issue-68393-let-pat-assoc-constant.rs:20:40
-   |
-LL | pub fn test(arg: EFoo, A::X: EFoo) {
-   |                                        ^^^^
-
 error[E0158]: associated consts cannot be referenced in patterns
   --> $DIR/issue-68393-let-pat-assoc-constant.rs:22:9
    |
 LL |     let A::X = arg;
    |         ^^^^
 
+error[E0158]: associated consts cannot be referenced in patterns
+  --> $DIR/issue-68393-let-pat-assoc-constant.rs:20:40
+   |
+LL | pub fn test(arg: EFoo, A::X: EFoo) {
+   |                                        ^^^^
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0158`.
diff --git a/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed
index b28dce881059..b469fade3ea5 100644
--- a/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed
+++ b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed
@@ -4,7 +4,7 @@ fn main() {
     match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
         Some(1) => {}
         // hello
-        Some(_) => {}
+        Some(_) => {},
         None => todo!()
     }
 }
diff --git a/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr
index 2a016048f2f7..5f2c89246e39 100644
--- a/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr
+++ b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr
@@ -12,7 +12,7 @@ note: `Option` defined here
    = note: the matched value is of type `Option`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         Some(_) => {}
+LL ~         Some(_) => {},
 LL +         None => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr
index 08e3d76b538b..3f0b4a9f26a8 100644
--- a/tests/ui/pattern/usefulness/consts-opaque.stderr
+++ b/tests/ui/pattern/usefulness/consts-opaque.stderr
@@ -7,21 +7,6 @@ LL |         FOO => {}
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:32:9
-   |
-LL |         FOO => {}
-   |         --- matches any value
-LL |
-LL |         _ => {} // should not be emitting unreachable warning
-   |         ^ unreachable pattern
-   |
-note: the lint level is defined here
-  --> $DIR/consts-opaque.rs:6:9
-   |
-LL | #![deny(unreachable_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-
 error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
   --> $DIR/consts-opaque.rs:37:9
    |
@@ -31,15 +16,6 @@ LL |         FOO_REF => {}
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:39:9
-   |
-LL |         FOO_REF => {}
-   |         ------- matches any value
-LL |
-LL |         Foo(_) => {} // should not be emitting unreachable warning
-   |         ^^^^^^ unreachable pattern
-
 warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
   --> $DIR/consts-opaque.rs:45:9
    |
@@ -61,23 +37,6 @@ LL |         BAR => {} // should not be emitting unreachable warning
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:53:9
-   |
-LL |         Bar => {}
-   |         --- matches any value
-LL |         BAR => {} // should not be emitting unreachable warning
-   |         ^^^ unreachable pattern
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:56:9
-   |
-LL |         Bar => {}
-   |         --- matches any value
-...
-LL |         _ => {}
-   |         ^ unreachable pattern
-
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
   --> $DIR/consts-opaque.rs:61:9
    |
@@ -87,24 +46,6 @@ LL |         BAR => {}
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:63:9
-   |
-LL |         BAR => {}
-   |         --- matches any value
-LL |
-LL |         Bar => {} // should not be emitting unreachable warning
-   |         ^^^ unreachable pattern
-
-error: unreachable pattern
-  --> $DIR/consts-opaque.rs:65:9
-   |
-LL |         BAR => {}
-   |         --- matches any value
-...
-LL |         _ => {}
-   |         ^ unreachable pattern
-
 error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
   --> $DIR/consts-opaque.rs:70:9
    |
@@ -123,6 +64,92 @@ LL |         BAR => {} // should not be emitting unreachable warning
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
 
+error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:80:9
+   |
+LL |         BAZ => {}
+   |         ^^^
+   |
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+
+error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:90:9
+   |
+LL |         BAZ => {}
+   |         ^^^
+   |
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+
+error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/consts-opaque.rs:97:9
+   |
+LL |         BAZ => {}
+   |         ^^^
+   |
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:32:9
+   |
+LL |         FOO => {}
+   |         --- matches any value
+LL |
+LL |         _ => {} // should not be emitting unreachable warning
+   |         ^ unreachable pattern
+   |
+note: the lint level is defined here
+  --> $DIR/consts-opaque.rs:6:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:39:9
+   |
+LL |         FOO_REF => {}
+   |         ------- matches any value
+LL |
+LL |         Foo(_) => {} // should not be emitting unreachable warning
+   |         ^^^^^^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:53:9
+   |
+LL |         Bar => {}
+   |         --- matches any value
+LL |         BAR => {} // should not be emitting unreachable warning
+   |         ^^^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:56:9
+   |
+LL |         Bar => {}
+   |         --- matches any value
+...
+LL |         _ => {}
+   |         ^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:63:9
+   |
+LL |         BAR => {}
+   |         --- matches any value
+LL |
+LL |         Bar => {} // should not be emitting unreachable warning
+   |         ^^^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:65:9
+   |
+LL |         BAR => {}
+   |         --- matches any value
+...
+LL |         _ => {}
+   |         ^ unreachable pattern
+
 error: unreachable pattern
   --> $DIR/consts-opaque.rs:72:9
    |
@@ -141,15 +168,6 @@ LL |         BAR => {}
 LL |         _ => {} // should not be emitting unreachable warning
    |         ^ unreachable pattern
 
-error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:80:9
-   |
-LL |         BAZ => {}
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
 error: unreachable pattern
   --> $DIR/consts-opaque.rs:82:9
    |
@@ -168,15 +186,6 @@ LL |         BAZ => {}
 LL |         _ => {}
    |         ^ unreachable pattern
 
-error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:90:9
-   |
-LL |         BAZ => {}
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
 error: unreachable pattern
   --> $DIR/consts-opaque.rs:92:9
    |
@@ -186,15 +195,6 @@ LL |
 LL |         _ => {}
    |         ^ unreachable pattern
 
-error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:97:9
-   |
-LL |         BAZ => {}
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
 error: unreachable pattern
   --> $DIR/consts-opaque.rs:99:9
    |
diff --git a/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
index 17e1a2304a13..ff29de03d6b3 100644
--- a/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
+++ b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
@@ -12,7 +12,7 @@ LL | pub enum HiddenEnum {
    = note: the matched value is of type `HiddenEnum`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         HiddenEnum::B => {}
+LL ~         HiddenEnum::B => {},
 LL +         _ => todo!()
    |
 
@@ -33,7 +33,7 @@ LL |     B,
    = note: the matched value is of type `HiddenEnum`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         HiddenEnum::C => {}
+LL ~         HiddenEnum::C => {},
 LL +         HiddenEnum::B => todo!()
    |
 
@@ -54,7 +54,7 @@ LL |     B,
    = note: the matched value is of type `HiddenEnum`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         HiddenEnum::A => {}
+LL ~         HiddenEnum::A => {},
 LL +         HiddenEnum::B | _ => todo!()
    |
 
@@ -72,7 +72,7 @@ note: `Option` defined here
    = note: the matched value is of type `Option`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         Some(HiddenEnum::A) => {}
+LL ~         Some(HiddenEnum::A) => {},
 LL +         Some(HiddenEnum::B) | Some(_) => todo!()
    |
 
@@ -93,7 +93,7 @@ LL |     C,
    = note: the matched value is of type `InCrate`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         InCrate::B => {}
+LL ~         InCrate::B => {},
 LL +         InCrate::C => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
index 5e12bc1d22f0..5a145efce948 100644
--- a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
@@ -162,7 +162,7 @@ LL |     match_guarded_arm!(0u8);
    = note: the matched value is of type `u8`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             _ => todo!()
    |
 
@@ -180,7 +180,7 @@ LL | struct NonEmptyStruct1;
    = note: the matched value is of type `NonEmptyStruct1`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             NonEmptyStruct1 => todo!()
    |
 
@@ -198,7 +198,7 @@ LL | struct NonEmptyStruct2(bool);
    = note: the matched value is of type `NonEmptyStruct2`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             NonEmptyStruct2(_) => todo!()
    |
 
@@ -216,7 +216,7 @@ LL | union NonEmptyUnion1 {
    = note: the matched value is of type `NonEmptyUnion1`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             NonEmptyUnion1 { .. } => todo!()
    |
 
@@ -234,7 +234,7 @@ LL | union NonEmptyUnion2 {
    = note: the matched value is of type `NonEmptyUnion2`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             NonEmptyUnion2 { .. } => todo!()
    |
 
@@ -254,7 +254,7 @@ LL |     Foo(bool),
    = note: the matched value is of type `NonEmptyEnum1`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             NonEmptyEnum1::Foo(_) => todo!()
    |
 
@@ -276,7 +276,7 @@ LL |     Bar,
    = note: the matched value is of type `NonEmptyEnum2`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!()
    |
 
@@ -294,7 +294,7 @@ LL | enum NonEmptyEnum5 {
    = note: the matched value is of type `NonEmptyEnum5`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             _ => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/empty-match.normal.stderr b/tests/ui/pattern/usefulness/empty-match.normal.stderr
index 5e12bc1d22f0..5a145efce948 100644
--- a/tests/ui/pattern/usefulness/empty-match.normal.stderr
+++ b/tests/ui/pattern/usefulness/empty-match.normal.stderr
@@ -162,7 +162,7 @@ LL |     match_guarded_arm!(0u8);
    = note: the matched value is of type `u8`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             _ => todo!()
    |
 
@@ -180,7 +180,7 @@ LL | struct NonEmptyStruct1;
    = note: the matched value is of type `NonEmptyStruct1`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             NonEmptyStruct1 => todo!()
    |
 
@@ -198,7 +198,7 @@ LL | struct NonEmptyStruct2(bool);
    = note: the matched value is of type `NonEmptyStruct2`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             NonEmptyStruct2(_) => todo!()
    |
 
@@ -216,7 +216,7 @@ LL | union NonEmptyUnion1 {
    = note: the matched value is of type `NonEmptyUnion1`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             NonEmptyUnion1 { .. } => todo!()
    |
 
@@ -234,7 +234,7 @@ LL | union NonEmptyUnion2 {
    = note: the matched value is of type `NonEmptyUnion2`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             NonEmptyUnion2 { .. } => todo!()
    |
 
@@ -254,7 +254,7 @@ LL |     Foo(bool),
    = note: the matched value is of type `NonEmptyEnum1`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             NonEmptyEnum1::Foo(_) => todo!()
    |
 
@@ -276,7 +276,7 @@ LL |     Bar,
    = note: the matched value is of type `NonEmptyEnum2`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!()
    |
 
@@ -294,7 +294,7 @@ LL | enum NonEmptyEnum5 {
    = note: the matched value is of type `NonEmptyEnum5`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
    |
-LL ~             _ if false => {}
+LL ~             _ if false => {},
 LL +             _ => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/floats.stderr b/tests/ui/pattern/usefulness/floats.stderr
index c926e50b3580..d66d4ba298be 100644
--- a/tests/ui/pattern/usefulness/floats.stderr
+++ b/tests/ui/pattern/usefulness/floats.stderr
@@ -7,7 +7,7 @@ LL |     match 0.0 {
    = note: the matched value is of type `f64`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~       0.0..=1.0 => {}
+LL ~       0.0..=1.0 => {},
 LL +       _ => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/guards.stderr b/tests/ui/pattern/usefulness/guards.stderr
index 0c1563c160c1..fc6748958de5 100644
--- a/tests/ui/pattern/usefulness/guards.stderr
+++ b/tests/ui/pattern/usefulness/guards.stderr
@@ -7,7 +7,7 @@ LL |     match 0u8 {
    = note: the matched value is of type `u8`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         128 ..= 255 if true => {}
+LL ~         128 ..= 255 if true => {},
 LL +         128_u8..=u8::MAX => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
index f30ba05dff9e..b585de206291 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
+++ b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
@@ -91,7 +91,7 @@ LL |     match 0i8 {
    = note: the matched value is of type `i8`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         1 ..= i8::MAX => {}
+LL ~         1 ..= i8::MAX => {},
 LL +         0_i8 => todo!()
    |
 
@@ -140,7 +140,7 @@ LL |     match (0u8, true) {
    = note: the matched value is of type `(u8, bool)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         (0 ..= 255, true) => {}
+LL ~         (0 ..= 255, true) => {},
 LL +         (126_u8..=127_u8, false) => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
index e3eb98ccdcda..0e0f0c3e11ee 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
+++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
@@ -9,7 +9,7 @@ LL |     match 0usize {
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         0 ..= usize::MAX => {}
+LL ~         0 ..= usize::MAX => {},
 LL +         _ => todo!()
    |
 
@@ -24,7 +24,7 @@ LL |     match 0isize {
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         isize::MIN ..= isize::MAX => {}
+LL ~         isize::MIN ..= isize::MAX => {},
 LL +         _ => todo!()
    |
 
@@ -147,7 +147,7 @@ LL |     match 0isize {
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         1 ..= isize::MAX => {}
+LL ~         1 ..= isize::MAX => {},
 LL +         _ => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr
index 30492c98206c..b80411b26b04 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr
+++ b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr
@@ -9,7 +9,7 @@ LL |     match 0usize {
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         0..=usize::MAX => {}
+LL ~         0..=usize::MAX => {},
 LL +         _ => todo!()
    |
 
@@ -24,7 +24,7 @@ LL |     match 0isize {
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         isize::MIN..=isize::MAX => {}
+LL ~         isize::MIN..=isize::MAX => {},
 LL +         _ => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/issue-2111.stderr b/tests/ui/pattern/usefulness/issue-2111.stderr
index 01890b73cbdd..7f7c5a0f19de 100644
--- a/tests/ui/pattern/usefulness/issue-2111.stderr
+++ b/tests/ui/pattern/usefulness/issue-2111.stderr
@@ -7,7 +7,7 @@ LL |     match (a, b) {
    = note: the matched value is of type `(Option, Option)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         (Some(_), None) | (None, Some(_)) => {}
+LL ~         (Some(_), None) | (None, Some(_)) => {},
 LL +         (None, None) | (Some(_), Some(_)) => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/issue-30240.stderr b/tests/ui/pattern/usefulness/issue-30240.stderr
index 759fdeafe4eb..ff755d681ac7 100644
--- a/tests/ui/pattern/usefulness/issue-30240.stderr
+++ b/tests/ui/pattern/usefulness/issue-30240.stderr
@@ -7,7 +7,7 @@ LL |     match "world" {
    = note: the matched value is of type `&str`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         "hello" => {}
+LL ~         "hello" => {},
 LL +         &_ => todo!()
    |
 
@@ -20,7 +20,7 @@ LL |     match "world" {
    = note: the matched value is of type `&str`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         "hello" => {}
+LL ~         "hello" => {},
 LL +         &_ => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/issue-35609.stderr b/tests/ui/pattern/usefulness/issue-35609.stderr
index 12113957d634..6d5e2f410bc9 100644
--- a/tests/ui/pattern/usefulness/issue-35609.stderr
+++ b/tests/ui/pattern/usefulness/issue-35609.stderr
@@ -7,7 +7,7 @@ LL |     match (A, ()) {
    = note: the matched value is of type `(Enum, ())`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
    |
-LL ~         (A, _) => {}
+LL ~         (A, _) => {},
 LL +         _ => todo!()
    |
 
@@ -20,7 +20,7 @@ LL |     match (A, A) {
    = note: the matched value is of type `(Enum, Enum)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
    |
-LL ~         (_, A) => {}
+LL ~         (_, A) => {},
 LL +         _ => todo!()
    |
 
@@ -33,7 +33,7 @@ LL |     match ((A, ()), ()) {
    = note: the matched value is of type `((Enum, ()), ())`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
    |
-LL ~         ((A, ()), _) => {}
+LL ~         ((A, ()), _) => {},
 LL +         _ => todo!()
    |
 
@@ -46,7 +46,7 @@ LL |     match ((A, ()), A) {
    = note: the matched value is of type `((Enum, ()), Enum)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
    |
-LL ~         ((A, ()), _) => {}
+LL ~         ((A, ()), _) => {},
 LL +         _ => todo!()
    |
 
@@ -59,7 +59,7 @@ LL |     match ((A, ()), ()) {
    = note: the matched value is of type `((Enum, ()), ())`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
    |
-LL ~         ((A, _), _) => {}
+LL ~         ((A, _), _) => {},
 LL +         _ => todo!()
    |
 
@@ -77,7 +77,7 @@ LL | struct S(Enum, ());
    = note: the matched value is of type `S`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
    |
-LL ~         S(A, _) => {}
+LL ~         S(A, _) => {},
 LL +         _ => todo!()
    |
 
@@ -95,7 +95,7 @@ LL | struct Sd { x: Enum, y: () }
    = note: the matched value is of type `Sd`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
    |
-LL ~         Sd { x: A, y: _ } => {}
+LL ~         Sd { x: A, y: _ } => {},
 LL +         _ => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/issue-3601.stderr b/tests/ui/pattern/usefulness/issue-3601.stderr
index 59d7bcd4b5e7..2f6b167d4f8b 100644
--- a/tests/ui/pattern/usefulness/issue-3601.stderr
+++ b/tests/ui/pattern/usefulness/issue-3601.stderr
@@ -9,7 +9,7 @@ note: `Box` defined here
    = note: the matched value is of type `Box`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~             box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }
+LL ~             box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true },
 LL +             box _ => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/issue-50900.stderr b/tests/ui/pattern/usefulness/issue-50900.stderr
index 348246d28aac..7880c8925671 100644
--- a/tests/ui/pattern/usefulness/issue-50900.stderr
+++ b/tests/ui/pattern/usefulness/issue-50900.stderr
@@ -12,7 +12,7 @@ LL | pub struct Tag(pub Context, pub u16);
    = note: the matched value is of type `Tag`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         Tag::ExifIFDPointer => {}
+LL ~         Tag::ExifIFDPointer => {},
 LL +         Tag(Context::Exif, _) => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/issue-56379.stderr b/tests/ui/pattern/usefulness/issue-56379.stderr
index 6eed6bfae4c9..b3e40b992399 100644
--- a/tests/ui/pattern/usefulness/issue-56379.stderr
+++ b/tests/ui/pattern/usefulness/issue-56379.stderr
@@ -18,7 +18,7 @@ LL |     C(bool),
    = note: the matched value is of type `Foo`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         Foo::C(true) => {}
+LL ~         Foo::C(true) => {},
 LL +         Foo::A(false) | Foo::B(false) | Foo::C(false) => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/match-byte-array-patterns-2.stderr b/tests/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
index a90f32f7aebf..3c482eef2105 100644
--- a/tests/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
+++ b/tests/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
@@ -7,7 +7,7 @@ LL |     match buf {
    = note: the matched value is of type `&[u8; 4]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         b"AAAA" => {}
+LL ~         b"AAAA" => {},
 LL +         &[0_u8..=64_u8, _, _, _] | &[66_u8..=u8::MAX, _, _, _] => todo!()
    |
 
@@ -20,7 +20,7 @@ LL |     match buf {
    = note: the matched value is of type `&[u8]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
    |
-LL ~         b"AAAA" => {}
+LL ~         b"AAAA" => {},
 LL +         _ => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/match-privately-empty.stderr b/tests/ui/pattern/usefulness/match-privately-empty.stderr
index 86f75d15cfde..45352f09417f 100644
--- a/tests/ui/pattern/usefulness/match-privately-empty.stderr
+++ b/tests/ui/pattern/usefulness/match-privately-empty.stderr
@@ -12,7 +12,7 @@ note: `Option` defined here
    = note: the matched value is of type `Option`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         }) => {}
+LL ~         }) => {},
 LL +         Some(Private { misc: true, .. }) => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/match-slice-patterns.stderr b/tests/ui/pattern/usefulness/match-slice-patterns.stderr
index 961dd5901196..63d1f38e9db4 100644
--- a/tests/ui/pattern/usefulness/match-slice-patterns.stderr
+++ b/tests/ui/pattern/usefulness/match-slice-patterns.stderr
@@ -7,7 +7,7 @@ LL |     match list {
    = note: the matched value is of type `&[Option<()>]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         &[.., Some(_), _] => {}
+LL ~         &[.., Some(_), _] => {},
 LL ~         &[_, Some(_), .., None, _] => todo!(),
    |
 
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
index 769d4070fb58..8489e2f14b87 100644
--- a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
+++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
@@ -18,7 +18,7 @@ LL |     C
    = note: the matched value is of type `E`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         E::A => {}
+LL ~         E::A => {},
 LL +         E::B | E::C => todo!()
    |
 
@@ -44,8 +44,8 @@ LL |     C
    = note: the matched value is of type `E`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let E::A = e { todo!() }
-   |     ++              ~~~~~~~~~~~
+LL |     if let E::A = e { todo!() };
+   |     ++              +++++++++++
 
 error[E0004]: non-exhaustive patterns: `&E::B` and `&E::C` not covered
   --> $DIR/non-exhaustive-defined-here.rs:50:11
@@ -67,7 +67,7 @@ LL |     C
    = note: the matched value is of type `&E`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         E::A => {}
+LL ~         E::A => {},
 LL +         &E::B | &E::C => todo!()
    |
 
@@ -93,8 +93,8 @@ LL |     C
    = note: the matched value is of type `&E`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let E::A = e { todo!() }
-   |     ++              ~~~~~~~~~~~
+LL |     if let E::A = e { todo!() };
+   |     ++              +++++++++++
 
 error[E0004]: non-exhaustive patterns: `&&mut &E::B` and `&&mut &E::C` not covered
   --> $DIR/non-exhaustive-defined-here.rs:66:11
@@ -116,7 +116,7 @@ LL |     C
    = note: the matched value is of type `&&mut &E`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         E::A => {}
+LL ~         E::A => {},
 LL +         &&mut &E::B | &&mut &E::C => todo!()
    |
 
@@ -142,8 +142,8 @@ LL |     C
    = note: the matched value is of type `&&mut &E`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let E::A = e { todo!() }
-   |     ++              ~~~~~~~~~~~
+LL |     if let E::A = e { todo!() };
+   |     ++              +++++++++++
 
 error[E0004]: non-exhaustive patterns: `Opt::None` not covered
   --> $DIR/non-exhaustive-defined-here.rs:92:11
@@ -162,7 +162,7 @@ LL |     None,
    = note: the matched value is of type `Opt`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         Opt::Some(ref _x) => {}
+LL ~         Opt::Some(ref _x) => {},
 LL +         Opt::None => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr b/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr
index 44f327421109..98e417a17f86 100644
--- a/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr
+++ b/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr
@@ -25,7 +25,7 @@ LL | enum T { A(U), B }
    = note: the matched value is of type `T`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         T::B => { panic!("goodbye"); }
+LL ~         T::B => { panic!("goodbye"); },
 LL +         T::A(U::C) => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr
index e2260f50bfef..e59e8885e1a4 100644
--- a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr
+++ b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr
@@ -24,7 +24,7 @@ LL |     match true {
    = note: the matched value is of type `bool`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~       true => {}
+LL ~       true => {},
 LL +       false => todo!()
    |
 
@@ -42,7 +42,7 @@ note: `Option` defined here
    = note: the matched value is of type `Option`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~       None => {}
+LL ~       None => {},
 LL +       Some(_) => todo!()
    |
 
@@ -55,7 +55,7 @@ LL |     match (2, 3, 4) {
    = note: the matched value is of type `(i32, i32, i32)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~       (_, _, 4) => {}
+LL ~       (_, _, 4) => {},
 LL +       (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!()
    |
 
@@ -68,7 +68,7 @@ LL |     match (T::A, T::A) {
    = note: the matched value is of type `(T, T)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~       (T::B, T::A) => {}
+LL ~       (T::B, T::A) => {},
 LL +       (T::A, T::A) | (T::B, T::B) => todo!()
    |
 
@@ -86,7 +86,7 @@ LL | enum T { A, B }
    = note: the matched value is of type `T`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~       T::A => {}
+LL ~       T::A => {},
 LL +       T::B => todo!()
    |
 
@@ -99,7 +99,7 @@ LL |     match *vec {
    = note: the matched value is of type `[Option]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [None] => {}
+LL ~         [None] => {},
 LL +         [] => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr b/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr
index c518de47740d..beb51a4d4504 100644
--- a/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr
+++ b/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr
@@ -17,8 +17,8 @@ LL |     let (1, (Some(1), 2..=3)) = (1, (None, 2));
    = note: the matched value is of type `(i32, (Option, i32))`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { todo!() }
-   |     ++                                            ~~~~~~~~~~~
+LL |     if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { todo!() };
+   |     ++                                            +++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr
index 55f0b2319fb7..ab3f6f69fb16 100644
--- a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr
+++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr
@@ -5,6 +5,10 @@ LL |     let f = |3: isize| println!("hello");
    |              ^ pattern `_` not covered
    |
    = note: the matched value is of type `isize`
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL |     let f = |_3: isize| println!("hello");
+   |              +
 
 error: aborting due to previous error
 
diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
index 5d1e170ae6c2..fb6ecda3c4df 100644
--- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
+++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
@@ -7,7 +7,7 @@ LL |     match s2 {
    = note: the matched value is of type `&[bool; 2]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [true, .., true] => {}
+LL ~         [true, .., true] => {},
 LL +         &[false, _] => todo!()
    |
 
@@ -20,7 +20,7 @@ LL |     match s3 {
    = note: the matched value is of type `&[bool; 3]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [true, .., true] => {}
+LL ~         [true, .., true] => {},
 LL +         &[false, ..] => todo!()
    |
 
@@ -33,7 +33,7 @@ LL |     match s10 {
    = note: the matched value is of type `&[bool; 10]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [true, .., true] => {}
+LL ~         [true, .., true] => {},
 LL +         &[false, ..] => todo!()
    |
 
@@ -46,7 +46,7 @@ LL |     match s2 {
    = note: the matched value is of type `&[bool; 2]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [.., false] => {}
+LL ~         [.., false] => {},
 LL +         &[false, true] => todo!()
    |
 
@@ -59,7 +59,7 @@ LL |     match s3 {
    = note: the matched value is of type `&[bool; 3]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [.., false] => {}
+LL ~         [.., false] => {},
 LL +         &[false, .., true] => todo!()
    |
 
@@ -72,7 +72,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [.., false] => {}
+LL ~         [.., false] => {},
 LL +         &[false, .., true] => todo!()
    |
 
@@ -85,7 +85,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [] => {}
+LL ~         [] => {},
 LL +         &[_, ..] => todo!()
    |
 
@@ -98,7 +98,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [_] => {}
+LL ~         [_] => {},
 LL +         &[_, _, ..] => todo!()
    |
 
@@ -111,7 +111,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [true, ..] => {}
+LL ~         [true, ..] => {},
 LL +         &[false, ..] => todo!()
    |
 
@@ -124,7 +124,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [true, ..] => {}
+LL ~         [true, ..] => {},
 LL +         &[false, _, ..] => todo!()
    |
 
@@ -137,7 +137,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [.., true] => {}
+LL ~         [.., true] => {},
 LL +         &[_, .., false] => todo!()
    |
 
@@ -150,7 +150,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [.., false] => {}
+LL ~         [.., false] => {},
 LL +         &[_, _, .., true] => todo!()
    |
 
@@ -163,7 +163,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [false, .., false] => {}
+LL ~         [false, .., false] => {},
 LL +         &[true, _, .., _] => todo!()
    |
 
@@ -176,7 +176,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         &[true] => {}
+LL ~         &[true] => {},
 LL +         &[] | &[_, _, ..] => todo!()
    |
 
@@ -189,7 +189,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         CONST => {}
+LL ~         CONST => {},
 LL +         &[] | &[_, _, ..] => todo!()
    |
 
@@ -202,7 +202,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         &[false] => {}
+LL ~         &[false] => {},
 LL +         &[] | &[_, _, ..] => todo!()
    |
 
@@ -215,7 +215,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         CONST => {}
+LL ~         CONST => {},
 LL +         &[] | &[_, _, ..] => todo!()
    |
 
@@ -228,7 +228,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         CONST => {}
+LL ~         CONST => {},
 LL +         &[_, _, ..] => todo!()
    |
 
@@ -241,7 +241,7 @@ LL |     match s {
    = note: the matched value is of type `&[bool]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         &[_, _, ..] => {}
+LL ~         &[_, _, ..] => {},
 LL +         &[false] => todo!()
    |
 
@@ -254,7 +254,7 @@ LL |     match s1 {
    = note: the matched value is of type `&[bool; 1]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         CONST1 => {}
+LL ~         CONST1 => {},
 LL +         &[false] => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/stable-gated-patterns.stderr b/tests/ui/pattern/usefulness/stable-gated-patterns.stderr
index 7b8588a3c735..f944c25a905c 100644
--- a/tests/ui/pattern/usefulness/stable-gated-patterns.stderr
+++ b/tests/ui/pattern/usefulness/stable-gated-patterns.stderr
@@ -15,7 +15,7 @@ LL |     Stable2,
    = note: the matched value is of type `UnstableEnum`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
-LL ~         UnstableEnum::Stable => {}
+LL ~         UnstableEnum::Stable => {},
 LL +         UnstableEnum::Stable2 | _ => todo!()
    |
 
@@ -33,7 +33,7 @@ LL | pub enum UnstableEnum {
    = note: the matched value is of type `UnstableEnum`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         UnstableEnum::Stable2 => {}
+LL ~         UnstableEnum::Stable2 => {},
 LL +         _ => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr b/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr
index 85c97be29d6d..22425aa0dd4d 100644
--- a/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr
+++ b/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr
@@ -14,7 +14,7 @@ LL |     B { x: Option },
    = note: the matched value is of type `A`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         A::B { x: None } => {}
+LL ~         A::B { x: None } => {},
 LL +         A::B { x: Some(_) } => todo!()
    |
 
diff --git a/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr b/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr
index 6dc9a4058398..d776249b2318 100644
--- a/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr
+++ b/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr
@@ -15,7 +15,7 @@ LL |     Unstable,
    = note: the matched value is of type `UnstableEnum`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         UnstableEnum::Stable2 => {}
+LL ~         UnstableEnum::Stable2 => {},
 LL +         UnstableEnum::Unstable => todo!()
    |
 
diff --git a/tests/ui/privacy/effective_visibilities.rs b/tests/ui/privacy/effective_visibilities.rs
index 3e9eef462306..e9ac93160870 100644
--- a/tests/ui/privacy/effective_visibilities.rs
+++ b/tests/ui/privacy/effective_visibilities.rs
@@ -18,13 +18,13 @@ mod outer { //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub
         }
 
         #[rustc_effective_visibility]
-        struct PrivStruct; //~ ERROR Direct: pub(self), Reexported: pub(self), Reachable: pub(self), ReachableThroughImplTrait: pub(self)
-                           //~| ERROR Direct: pub(self), Reexported: pub(self), Reachable: pub(self), ReachableThroughImplTrait: pub(self)
+        struct PrivStruct; //~ ERROR not in the table
+                           //~| ERROR not in the table
 
         #[rustc_effective_visibility]
         pub union PubUnion { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
             #[rustc_effective_visibility]
-            a: u8, //~ ERROR Direct: pub(self), Reexported: pub(self), Reachable: pub(self), ReachableThroughImplTrait: pub(self)
+            a: u8, //~ ERROR not in the table
             #[rustc_effective_visibility]
             pub b: u8, //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
         }
diff --git a/tests/ui/privacy/effective_visibilities.stderr b/tests/ui/privacy/effective_visibilities.stderr
index 2618fc427e91..f74f812e1a0e 100644
--- a/tests/ui/privacy/effective_visibilities.stderr
+++ b/tests/ui/privacy/effective_visibilities.stderr
@@ -34,13 +34,13 @@ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImpl
 LL |         pub trait PubTrait {
    |         ^^^^^^^^^^^^^^^^^^
 
-error: Direct: pub(self), Reexported: pub(self), Reachable: pub(self), ReachableThroughImplTrait: pub(self)
+error: not in the table
   --> $DIR/effective_visibilities.rs:21:9
    |
 LL |         struct PrivStruct;
    |         ^^^^^^^^^^^^^^^^^
 
-error: Direct: pub(self), Reexported: pub(self), Reachable: pub(self), ReachableThroughImplTrait: pub(self)
+error: not in the table
   --> $DIR/effective_visibilities.rs:21:9
    |
 LL |         struct PrivStruct;
@@ -52,7 +52,7 @@ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImpl
 LL |         pub union PubUnion {
    |         ^^^^^^^^^^^^^^^^^^
 
-error: Direct: pub(self), Reexported: pub(self), Reachable: pub(self), ReachableThroughImplTrait: pub(self)
+error: not in the table
   --> $DIR/effective_visibilities.rs:27:13
    |
 LL |             a: u8,
diff --git a/tests/ui/proc-macro/span-api-tests.rs b/tests/ui/proc-macro/span-api-tests.rs
index 3f04ba866b7d..7493f9cdb3de 100644
--- a/tests/ui/proc-macro/span-api-tests.rs
+++ b/tests/ui/proc-macro/span-api-tests.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty
 // aux-build:span-api-tests.rs
 // aux-build:span-test-macros.rs
 // compile-flags: -Ztranslate-remapped-path-to-local-path=yes
diff --git a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.rs b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.rs
index d02caff1febd..206f05d0d3ca 100644
--- a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.rs
+++ b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.rs
@@ -4,10 +4,8 @@ fn main() {
     match 0u8 {
         251..257 => {}
         //~^ ERROR literal out of range
-        //~| ERROR literal out of range
         251..=256 => {}
         //~^ ERROR literal out of range
-        //~| ERROR literal out of range
         _ => {}
     }
 }
diff --git a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr
index 7b8309b9bc2a..4f3f9d1eb3a7 100644
--- a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr
+++ b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr
@@ -5,22 +5,10 @@ LL |         251..257 => {}
    |              ^^^ this value doesn't fit in `u8` whose maximum value is `255`
 
 error: literal out of range for `u8`
-  --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:8:15
+  --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:7:15
    |
 LL |         251..=256 => {}
    |               ^^^ this value doesn't fit in `u8` whose maximum value is `255`
 
-error: literal out of range for `u8`
-  --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:5:14
-   |
-LL |         251..257 => {}
-   |              ^^^ this value doesn't fit in `u8` whose maximum value is `255`
-
-error: literal out of range for `u8`
-  --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:8:15
-   |
-LL |         251..=256 => {}
-   |               ^^^ this value doesn't fit in `u8` whose maximum value is `255`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/recursion/issue-95134.rs b/tests/ui/recursion/issue-95134.rs
index fdc4d5369814..2f1cffa2fa90 100644
--- a/tests/ui/recursion/issue-95134.rs
+++ b/tests/ui/recursion/issue-95134.rs
@@ -1,7 +1,7 @@
 // build-fail
 // known-bug: #95134
 // compile-flags: -Copt-level=0
-// failure-status: 101
+// dont-check-failure-status
 // dont-check-compiler-stderr
 
 pub fn encode_num(n: u32, mut writer: Writer) -> Result<(), Writer::Error> {
diff --git a/tests/ui/resolve/tool-import.rs b/tests/ui/resolve/tool-import.rs
new file mode 100644
index 000000000000..971993332f54
--- /dev/null
+++ b/tests/ui/resolve/tool-import.rs
@@ -0,0 +1,8 @@
+// edition: 2018
+
+use clippy::time::Instant;
+//~^ `clippy` is a tool module
+
+fn main() {
+    Instant::now();
+}
diff --git a/tests/ui/resolve/tool-import.stderr b/tests/ui/resolve/tool-import.stderr
new file mode 100644
index 000000000000..d3bdfc93d492
--- /dev/null
+++ b/tests/ui/resolve/tool-import.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: `clippy` is a tool module, not a module
+  --> $DIR/tool-import.rs:3:5
+   |
+LL | use clippy::time::Instant;
+   |     ^^^^^^ `clippy` is a tool module, not a module
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/rfc-2005-default-binding-mode/slice.stderr b/tests/ui/rfc-2005-default-binding-mode/slice.stderr
index 60c1f5420f62..5b51dc5acc4e 100644
--- a/tests/ui/rfc-2005-default-binding-mode/slice.stderr
+++ b/tests/ui/rfc-2005-default-binding-mode/slice.stderr
@@ -7,7 +7,7 @@ LL |     match sl {
    = note: the matched value is of type `&[u8]`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~         [first, remainder @ ..] => {}
+LL ~         [first, remainder @ ..] => {},
 LL ~         &[] => todo!(),
    |
 
diff --git a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs
index 7ef1d635d9ce..3482af74752f 100644
--- a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs
+++ b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.rs
@@ -194,6 +194,14 @@ fn main() {
     let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit;
     //~^ refutable pattern in local binding
 
+    // Check that matching on a reference results in a correctly spanned diagnostic
+    #[deny(non_exhaustive_omitted_patterns)]
+    match &non_enum {
+        NonExhaustiveEnum::Unit => {}
+        NonExhaustiveEnum::Tuple(_) => {}
+        _ => {}
+    }
+    //~^^ some variants are not matched explicitly
 }
 
 #[deny(non_exhaustive_omitted_patterns)]
diff --git a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr
index 617c629a4fe0..923394474b26 100644
--- a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr
+++ b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr
@@ -188,7 +188,7 @@ error[E0005]: refutable pattern in local binding
   --> $DIR/omitted-patterns.rs:194:9
    |
 LL |     let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered
+   |         ^^^^^^^^^^^^^^^ pattern `_` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -198,6 +198,20 @@ help: you might want to use `let else` to handle the variant that isn't matched
 LL |     let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit else { todo!() };
    |                                                                             ++++++++++++++++
 
-error: aborting due to 9 previous errors; 6 warnings emitted
+error: some variants are not matched explicitly
+  --> $DIR/omitted-patterns.rs:202:9
+   |
+LL |         _ => {}
+   |         ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered
+   |
+   = help: ensure that all variants are matched explicitly by adding the suggested match arms
+   = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
+note: the lint level is defined here
+  --> $DIR/omitted-patterns.rs:198:12
+   |
+LL |     #[deny(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 10 previous errors; 6 warnings emitted
 
 For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/rfc-2008-non-exhaustive/struct.stderr b/tests/ui/rfc-2008-non-exhaustive/struct.stderr
index 2cb9ba0d1d14..39b1ef1e078c 100644
--- a/tests/ui/rfc-2008-non-exhaustive/struct.stderr
+++ b/tests/ui/rfc-2008-non-exhaustive/struct.stderr
@@ -10,14 +10,11 @@ error[E0603]: tuple struct constructor `TupleStruct` is private
 LL |     let ts_explicit = structs::TupleStruct(640, 480);
    |                                ^^^^^^^^^^^ private tuple struct constructor
    |
-  ::: $DIR/auxiliary/structs.rs:12:24
-   |
-LL | pub struct TupleStruct(pub u16, pub u16);
-   |                        ---------------- a constructor is private if any of the fields is private
-   |
 note: the tuple struct constructor `TupleStruct` is defined here
   --> $DIR/auxiliary/structs.rs:12:1
    |
+LL | #[non_exhaustive]
+   | ----------------- cannot be constructed because it is `#[non_exhaustive]`
 LL | pub struct TupleStruct(pub u16, pub u16);
    | ^^^^^^^^^^^^^^^^^^^^^^
 
@@ -30,6 +27,8 @@ LL |     let us_explicit = structs::UnitStruct;
 note: the unit struct `UnitStruct` is defined here
   --> $DIR/auxiliary/structs.rs:9:1
    |
+LL | #[non_exhaustive]
+   | ----------------- cannot be constructed because it is `#[non_exhaustive]`
 LL | pub struct UnitStruct;
    | ^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/tests/ui/rfc-2008-non-exhaustive/variant.stderr b/tests/ui/rfc-2008-non-exhaustive/variant.stderr
index 720b7b119cec..4083f57a9cdf 100644
--- a/tests/ui/rfc-2008-non-exhaustive/variant.stderr
+++ b/tests/ui/rfc-2008-non-exhaustive/variant.stderr
@@ -8,7 +8,9 @@ note: the tuple variant `Tuple` is defined here
   --> $DIR/auxiliary/variants.rs:5:23
    |
 LL |     #[non_exhaustive] Tuple(u32),
-   |                       ^^^^^
+   |     ----------------- ^^^^^
+   |     |
+   |     cannot be constructed because it is `#[non_exhaustive]`
 
 error[E0603]: unit variant `Unit` is private
   --> $DIR/variant.rs:14:47
@@ -20,7 +22,9 @@ note: the unit variant `Unit` is defined here
   --> $DIR/auxiliary/variants.rs:4:23
    |
 LL |     #[non_exhaustive] Unit,
-   |                       ^^^^
+   |     ----------------- ^^^^
+   |     |
+   |     cannot be constructed because it is `#[non_exhaustive]`
 
 error[E0603]: unit variant `Unit` is private
   --> $DIR/variant.rs:18:32
@@ -32,7 +36,9 @@ note: the unit variant `Unit` is defined here
   --> $DIR/auxiliary/variants.rs:4:23
    |
 LL |     #[non_exhaustive] Unit,
-   |                       ^^^^
+   |     ----------------- ^^^^
+   |     |
+   |     cannot be constructed because it is `#[non_exhaustive]`
 
 error[E0603]: tuple variant `Tuple` is private
   --> $DIR/variant.rs:20:32
@@ -44,7 +50,9 @@ note: the tuple variant `Tuple` is defined here
   --> $DIR/auxiliary/variants.rs:5:23
    |
 LL |     #[non_exhaustive] Tuple(u32),
-   |                       ^^^^^
+   |     ----------------- ^^^^^
+   |     |
+   |     cannot be constructed because it is `#[non_exhaustive]`
 
 error[E0603]: tuple variant `Tuple` is private
   --> $DIR/variant.rs:26:35
@@ -56,7 +64,9 @@ note: the tuple variant `Tuple` is defined here
   --> $DIR/auxiliary/variants.rs:5:23
    |
 LL |     #[non_exhaustive] Tuple(u32),
-   |                       ^^^^^
+   |     ----------------- ^^^^^
+   |     |
+   |     cannot be constructed because it is `#[non_exhaustive]`
 
 error[E0639]: cannot create non-exhaustive variant using struct expression
   --> $DIR/variant.rs:8:26
diff --git a/tests/ui/runtime/backtrace-debuginfo.rs b/tests/ui/runtime/backtrace-debuginfo.rs
index 8b5466b6cfa0..5d233b38dbe2 100644
--- a/tests/ui/runtime/backtrace-debuginfo.rs
+++ b/tests/ui/runtime/backtrace-debuginfo.rs
@@ -9,7 +9,6 @@
 // compile-flags:-g -Copt-level=0 -Cllvm-args=-enable-tail-merge=0
 // compile-flags:-Cforce-frame-pointers=yes
 // compile-flags:-Cstrip=none
-// ignore-pretty issue #37195
 // ignore-emscripten spawning processes is not supported
 // ignore-sgx no processes
 // ignore-fuchsia Backtrace not symbolized, trace different line alignment
diff --git a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed
index 85d106bc11f6..ede0c2e8eaf0 100644
--- a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed
+++ b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed
@@ -18,9 +18,11 @@ mod foo {
 fn main() {
     let _: ::Bar = ();
     //~^ ERROR absolute paths must start with
-    //~| this is accepted in the current edition
+    //~| WARN this is accepted in the current edition
+    //~| ERROR absolute paths must start with
+    //~| WARN this is accepted in the current edition
 
     let _: ::Bar = ();
     //~^ ERROR absolute paths must start with
-    //~| this is accepted in the current edition
+    //~| WARN this is accepted in the current edition
 }
diff --git a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs
index 9ff3c2e5fcff..48b091ddb45e 100644
--- a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs
+++ b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs
@@ -18,9 +18,11 @@ mod foo {
 fn main() {
     let _: ::Bar = ();
     //~^ ERROR absolute paths must start with
-    //~| this is accepted in the current edition
+    //~| WARN this is accepted in the current edition
+    //~| ERROR absolute paths must start with
+    //~| WARN this is accepted in the current edition
 
     let _: <::foo::Baz as foo::Foo>::Bar = ();
     //~^ ERROR absolute paths must start with
-    //~| this is accepted in the current edition
+    //~| WARN this is accepted in the current edition
 }
diff --git a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr
index e1709db0990c..497ee440dfdb 100644
--- a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr
+++ b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr
@@ -13,7 +13,16 @@ LL | #![deny(absolute_paths_not_starting_with_crate)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-fully-qualified-paths.rs:23:13
+  --> $DIR/edition-lint-fully-qualified-paths.rs:19:25
+   |
+LL |     let _: ::Bar = ();
+   |                         ^^^^^^^^^^ help: use `crate`: `crate::foo::Foo`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-fully-qualified-paths.rs:25:13
    |
 LL |     let _: <::foo::Baz as foo::Foo>::Bar = ();
    |             ^^^^^^^^^^ help: use `crate`: `crate::foo::Baz`
@@ -21,5 +30,5 @@ LL |     let _: <::foo::Baz as foo::Foo>::Bar = ();
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #53130 
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/simd/monomorphize-heterogeneous.rs b/tests/ui/simd/monomorphize-heterogeneous.rs
new file mode 100644
index 000000000000..42e380dbb779
--- /dev/null
+++ b/tests/ui/simd/monomorphize-heterogeneous.rs
@@ -0,0 +1,9 @@
+#![feature(repr_simd)]
+
+#[repr(simd)]
+struct I64F64(i64, f64);
+//~^ ERROR SIMD vector should be homogeneous
+
+static X: I64F64 = I64F64(1, 2.0);
+
+fn main() {}
diff --git a/tests/ui/simd/monomorphize-heterogeneous.stderr b/tests/ui/simd/monomorphize-heterogeneous.stderr
new file mode 100644
index 000000000000..e7b41cd787cd
--- /dev/null
+++ b/tests/ui/simd/monomorphize-heterogeneous.stderr
@@ -0,0 +1,9 @@
+error[E0076]: SIMD vector should be homogeneous
+  --> $DIR/monomorphize-heterogeneous.rs:4:1
+   |
+LL | struct I64F64(i64, f64);
+   | ^^^^^^^^^^^^^ SIMD elements must have the same type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0076`.
diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr
index ee62d8f2d25c..d723ff538a88 100644
--- a/tests/ui/stats/hir-stats.stderr
+++ b/tests/ui/stats/hir-stats.stderr
@@ -15,45 +15,45 @@ ast-stats-1 Arm                       96 ( 1.5%)             2            48
 ast-stats-1 ForeignItem               96 ( 1.5%)             1            96
 ast-stats-1 - Fn                        96 ( 1.5%)             1
 ast-stats-1 FnDecl                   120 ( 1.8%)             5            24
-ast-stats-1 FieldDef                 160 ( 2.4%)             2            80
-ast-stats-1 Stmt                     160 ( 2.4%)             5            32
+ast-stats-1 FieldDef                 160 ( 2.5%)             2            80
+ast-stats-1 Stmt                     160 ( 2.5%)             5            32
 ast-stats-1 - Local                     32 ( 0.5%)             1
 ast-stats-1 - MacCall                   32 ( 0.5%)             1
 ast-stats-1 - Expr                      96 ( 1.5%)             3
-ast-stats-1 Param                    160 ( 2.4%)             4            40
-ast-stats-1 Block                    192 ( 2.9%)             6            32
+ast-stats-1 Param                    160 ( 2.5%)             4            40
+ast-stats-1 Block                    192 ( 3.0%)             6            32
 ast-stats-1 Variant                  208 ( 3.2%)             2           104
-ast-stats-1 GenericBound             224 ( 3.4%)             4            56
-ast-stats-1 - Trait                    224 ( 3.4%)             4
-ast-stats-1 AssocItem                416 ( 6.3%)             4           104
-ast-stats-1 - Type                     208 ( 3.2%)             2
-ast-stats-1 - Fn                       208 ( 3.2%)             2
-ast-stats-1 GenericParam             480 ( 7.3%)             5            96
-ast-stats-1 Pat                      504 ( 7.7%)             7            72
+ast-stats-1 GenericBound             224 ( 3.5%)             4            56
+ast-stats-1 - Trait                    224 ( 3.5%)             4
+ast-stats-1 AssocItem                352 ( 5.4%)             4            88
+ast-stats-1 - Type                     176 ( 2.7%)             2
+ast-stats-1 - Fn                       176 ( 2.7%)             2
+ast-stats-1 GenericParam             480 ( 7.4%)             5            96
+ast-stats-1 Pat                      504 ( 7.8%)             7            72
 ast-stats-1 - Struct                    72 ( 1.1%)             1
 ast-stats-1 - Wild                      72 ( 1.1%)             1
 ast-stats-1 - Ident                    360 ( 5.5%)             5
-ast-stats-1 Expr                     576 ( 8.8%)             8            72
+ast-stats-1 Expr                     576 ( 8.9%)             8            72
 ast-stats-1 - Path                      72 ( 1.1%)             1
 ast-stats-1 - Match                     72 ( 1.1%)             1
 ast-stats-1 - Struct                    72 ( 1.1%)             1
 ast-stats-1 - Lit                      144 ( 2.2%)             2
 ast-stats-1 - Block                    216 ( 3.3%)             3
-ast-stats-1 PathSegment              720 (11.0%)            30            24
-ast-stats-1 Ty                       896 (13.7%)            14            64
+ast-stats-1 PathSegment              720 (11.1%)            30            24
+ast-stats-1 Ty                       896 (13.8%)            14            64
 ast-stats-1 - Ptr                       64 ( 1.0%)             1
 ast-stats-1 - Ref                       64 ( 1.0%)             1
 ast-stats-1 - ImplicitSelf             128 ( 2.0%)             2
-ast-stats-1 - Path                     640 ( 9.8%)            10
-ast-stats-1 Item                   1_224 (18.7%)             9           136
+ast-stats-1 - Path                     640 ( 9.9%)            10
+ast-stats-1 Item                   1_224 (18.9%)             9           136
 ast-stats-1 - Trait                    136 ( 2.1%)             1
 ast-stats-1 - Enum                     136 ( 2.1%)             1
 ast-stats-1 - ForeignMod               136 ( 2.1%)             1
 ast-stats-1 - Impl                     136 ( 2.1%)             1
 ast-stats-1 - Fn                       272 ( 4.2%)             2
-ast-stats-1 - Use                      408 ( 6.2%)             3
+ast-stats-1 - Use                      408 ( 6.3%)             3
 ast-stats-1 ----------------------------------------------------------------
-ast-stats-1 Total                  6_552
+ast-stats-1 Total                  6_488
 ast-stats-1
 ast-stats-2 POST EXPANSION AST STATS
 ast-stats-2 Name                Accumulated Size         Count     Item Size
@@ -65,32 +65,32 @@ ast-stats-2 ExprField                 48 ( 0.7%)             1            48
 ast-stats-2 WherePredicate            56 ( 0.8%)             1            56
 ast-stats-2 - BoundPredicate            56 ( 0.8%)             1
 ast-stats-2 Local                     72 ( 1.0%)             1            72
-ast-stats-2 Arm                       96 ( 1.3%)             2            48
-ast-stats-2 ForeignItem               96 ( 1.3%)             1            96
-ast-stats-2 - Fn                        96 ( 1.3%)             1
+ast-stats-2 Arm                       96 ( 1.4%)             2            48
+ast-stats-2 ForeignItem               96 ( 1.4%)             1            96
+ast-stats-2 - Fn                        96 ( 1.4%)             1
 ast-stats-2 InlineAsm                120 ( 1.7%)             1           120
 ast-stats-2 FnDecl                   120 ( 1.7%)             5            24
 ast-stats-2 Attribute                128 ( 1.8%)             4            32
-ast-stats-2 - DocComment                32 ( 0.4%)             1
-ast-stats-2 - Normal                    96 ( 1.3%)             3
-ast-stats-2 FieldDef                 160 ( 2.2%)             2            80
-ast-stats-2 Stmt                     160 ( 2.2%)             5            32
-ast-stats-2 - Local                     32 ( 0.4%)             1
-ast-stats-2 - Semi                      32 ( 0.4%)             1
-ast-stats-2 - Expr                      96 ( 1.3%)             3
-ast-stats-2 Param                    160 ( 2.2%)             4            40
+ast-stats-2 - DocComment                32 ( 0.5%)             1
+ast-stats-2 - Normal                    96 ( 1.4%)             3
+ast-stats-2 FieldDef                 160 ( 2.3%)             2            80
+ast-stats-2 Stmt                     160 ( 2.3%)             5            32
+ast-stats-2 - Local                     32 ( 0.5%)             1
+ast-stats-2 - Semi                      32 ( 0.5%)             1
+ast-stats-2 - Expr                      96 ( 1.4%)             3
+ast-stats-2 Param                    160 ( 2.3%)             4            40
 ast-stats-2 Block                    192 ( 2.7%)             6            32
 ast-stats-2 Variant                  208 ( 2.9%)             2           104
-ast-stats-2 GenericBound             224 ( 3.1%)             4            56
-ast-stats-2 - Trait                    224 ( 3.1%)             4
-ast-stats-2 AssocItem                416 ( 5.8%)             4           104
-ast-stats-2 - Type                     208 ( 2.9%)             2
-ast-stats-2 - Fn                       208 ( 2.9%)             2
-ast-stats-2 GenericParam             480 ( 6.7%)             5            96
-ast-stats-2 Pat                      504 ( 7.0%)             7            72
+ast-stats-2 GenericBound             224 ( 3.2%)             4            56
+ast-stats-2 - Trait                    224 ( 3.2%)             4
+ast-stats-2 AssocItem                352 ( 5.0%)             4            88
+ast-stats-2 - Type                     176 ( 2.5%)             2
+ast-stats-2 - Fn                       176 ( 2.5%)             2
+ast-stats-2 GenericParam             480 ( 6.8%)             5            96
+ast-stats-2 Pat                      504 ( 7.1%)             7            72
 ast-stats-2 - Struct                    72 ( 1.0%)             1
 ast-stats-2 - Wild                      72 ( 1.0%)             1
-ast-stats-2 - Ident                    360 ( 5.0%)             5
+ast-stats-2 - Ident                    360 ( 5.1%)             5
 ast-stats-2 Expr                     648 ( 9.1%)             9            72
 ast-stats-2 - Path                      72 ( 1.0%)             1
 ast-stats-2 - Match                     72 ( 1.0%)             1
@@ -98,22 +98,22 @@ ast-stats-2 - Struct                    72 ( 1.0%)             1
 ast-stats-2 - InlineAsm                 72 ( 1.0%)             1
 ast-stats-2 - Lit                      144 ( 2.0%)             2
 ast-stats-2 - Block                    216 ( 3.0%)             3
-ast-stats-2 PathSegment              792 (11.1%)            33            24
-ast-stats-2 Ty                       896 (12.5%)            14            64
+ast-stats-2 PathSegment              792 (11.2%)            33            24
+ast-stats-2 Ty                       896 (12.6%)            14            64
 ast-stats-2 - Ptr                       64 ( 0.9%)             1
 ast-stats-2 - Ref                       64 ( 0.9%)             1
 ast-stats-2 - ImplicitSelf             128 ( 1.8%)             2
-ast-stats-2 - Path                     640 ( 8.9%)            10
-ast-stats-2 Item                   1_496 (20.9%)            11           136
+ast-stats-2 - Path                     640 ( 9.0%)            10
+ast-stats-2 Item                   1_496 (21.1%)            11           136
 ast-stats-2 - Trait                    136 ( 1.9%)             1
 ast-stats-2 - Enum                     136 ( 1.9%)             1
 ast-stats-2 - ExternCrate              136 ( 1.9%)             1
 ast-stats-2 - ForeignMod               136 ( 1.9%)             1
 ast-stats-2 - Impl                     136 ( 1.9%)             1
 ast-stats-2 - Fn                       272 ( 3.8%)             2
-ast-stats-2 - Use                      544 ( 7.6%)             4
+ast-stats-2 - Use                      544 ( 7.7%)             4
 ast-stats-2 ----------------------------------------------------------------
-ast-stats-2 Total                  7_152
+ast-stats-2 Total                  7_088
 ast-stats-2
 hir-stats HIR STATS
 hir-stats Name                Accumulated Size         Count     Item Size
diff --git a/tests/ui/structs/struct-tuple-field-names.rs b/tests/ui/structs/struct-tuple-field-names.rs
index 7bd54af1dbee..33f264aa2509 100644
--- a/tests/ui/structs/struct-tuple-field-names.rs
+++ b/tests/ui/structs/struct-tuple-field-names.rs
@@ -12,4 +12,7 @@ fn main() {
     match y {
         S { } => {} //~ ERROR: tuple variant `S` written as struct variant [E0769]
     }
+
+    if let E::S { 0: a } = x { //~ ERROR: pattern does not mention field `1`
+    }
 }
diff --git a/tests/ui/structs/struct-tuple-field-names.stderr b/tests/ui/structs/struct-tuple-field-names.stderr
index 5494c29a6fd2..0b837a47a825 100644
--- a/tests/ui/structs/struct-tuple-field-names.stderr
+++ b/tests/ui/structs/struct-tuple-field-names.stderr
@@ -20,6 +20,22 @@ help: use the tuple variant pattern syntax instead
 LL |         S(_, _) => {}
    |          ~~~~~~
 
-error: aborting due to 2 previous errors
+error[E0027]: pattern does not mention field `1`
+  --> $DIR/struct-tuple-field-names.rs:16:12
+   |
+LL |     if let E::S { 0: a } = x {
+   |            ^^^^^^^^^^^^^ missing field `1`
+   |
+help: include the missing field in the pattern
+   |
+LL |     if let E::S { 0: a, 1: _ } = x {
+   |                       ~~~~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+   |
+LL |     if let E::S { 0: a, .. } = x {
+   |                       ~~~~~~
 
-For more information about this error, try `rustc --explain E0769`.
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0027, E0769.
+For more information about an error, try `rustc --explain E0027`.
diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
index 15f08486f0f0..af47ba8baa3f 100644
--- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
+++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
@@ -2,10 +2,9 @@ fn main() {
     let A = 3;
     //~^ ERROR refutable pattern in local binding
     //~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
-    //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
+    //~| missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
-    //~| SUGGESTION a_var
+    //~| SUGGESTION A_var
 
     const A: i32 = 2;
-    //~^ constant defined here
 }
diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
index 1c1cab25fbfa..9ee3e6eb2c82 100644
--- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
+++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
@@ -5,12 +5,11 @@ LL |     let A = 3;
    |         ^
    |         |
    |         patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
-   |         missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `a_var`
-...
-LL |     const A: i32 = 2;
-   |     ------------ constant defined here
+   |         missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
+   |         help: introduce a variable instead: `A_var`
    |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
 
 error: aborting due to previous error
diff --git a/tests/ui/suggestions/issue-109291.rs b/tests/ui/suggestions/issue-109291.rs
new file mode 100644
index 000000000000..1947b16a32e6
--- /dev/null
+++ b/tests/ui/suggestions/issue-109291.rs
@@ -0,0 +1,4 @@
+fn main() {
+    println!("Custom backtrace: {}", std::backtrace::Backtrace::forced_capture());
+    //~^ ERROR no function or associated item name
+}
diff --git a/tests/ui/suggestions/issue-109291.stderr b/tests/ui/suggestions/issue-109291.stderr
new file mode 100644
index 000000000000..4ef5948d9bf2
--- /dev/null
+++ b/tests/ui/suggestions/issue-109291.stderr
@@ -0,0 +1,12 @@
+error[E0599]: no function or associated item named `forced_capture` found for struct `Backtrace` in the current scope
+  --> $DIR/issue-109291.rs:2:65
+   |
+LL |     println!("Custom backtrace: {}", std::backtrace::Backtrace::forced_capture());
+   |                                                                 ^^^^^^^^^^^^^^
+   |                                                                 |
+   |                                                                 function or associated item not found in `Backtrace`
+   |                                                                 help: there is an associated function with a similar name: `force_capture`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/suggestions/issue-109396.stderr b/tests/ui/suggestions/issue-109396.stderr
index eca160e2fab2..d4956872a399 100644
--- a/tests/ui/suggestions/issue-109396.stderr
+++ b/tests/ui/suggestions/issue-109396.stderr
@@ -25,7 +25,7 @@ note: function defined here
 help: remove the extra arguments
    |
 LL -             file.as_raw_fd(),
-LL +             ,
+LL +             );
    |
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/suggestions/ref-pattern-binding.stderr b/tests/ui/suggestions/ref-pattern-binding.stderr
index 7b194259349b..69ce5d440af8 100644
--- a/tests/ui/suggestions/ref-pattern-binding.stderr
+++ b/tests/ui/suggestions/ref-pattern-binding.stderr
@@ -2,9 +2,8 @@ error: borrow of moved value
   --> $DIR/ref-pattern-binding.rs:10:9
    |
 LL |     let _moved @ ref _from = String::from("foo");
-   |         ------^^^---------
-   |         |        |
-   |         |        value borrowed here after move
+   |         ^^^^^^   --------- value borrowed here after move
+   |         |
    |         value moved into `_moved` here
    |         move occurs because `_moved` has type `String` which does not implement the `Copy` trait
    |
@@ -17,27 +16,24 @@ error: cannot move out of value because it is borrowed
   --> $DIR/ref-pattern-binding.rs:11:9
    |
 LL |     let ref _moved @ _from = String::from("foo");
-   |         ----------^^^-----
-   |         |            |
-   |         |            value is moved into `_from` here
+   |         ^^^^^^^^^^   ----- value is moved into `_from` here
+   |         |
    |         value is borrowed by `_moved` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/ref-pattern-binding.rs:15:9
    |
 LL |     let ref _moved @ S { f } = S { f: String::from("foo") };
-   |         ----------^^^^^^^-^^
-   |         |                |
-   |         |                value is moved into `f` here
+   |         ^^^^^^^^^^       - value is moved into `f` here
+   |         |
    |         value is borrowed by `_moved` here
 
 error: borrow of moved value
   --> $DIR/ref-pattern-binding.rs:18:9
    |
 LL |     let _moved @ S { ref f } = S { f: String::from("foo") };
-   |         ------^^^^^^^-----^^
-   |         |            |
-   |         |            value borrowed here after move
+   |         ^^^^^^       ----- value borrowed here after move
+   |         |
    |         value moved into `_moved` here
    |         move occurs because `_moved` has type `S` which does not implement the `Copy` trait
    |
diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr
index fe490a6000d7..c1cbefac828d 100644
--- a/tests/ui/symbol-names/basic.legacy.stderr
+++ b/tests/ui/symbol-names/basic.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN5basic4main17he9f658e438f1cac0E)
+error: symbol-name(_ZN5basic4main17h6fc0c8d27b1a289fE)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic::main::he9f658e438f1cac0)
+error: demangling(basic::main::h6fc0c8d27b1a289f)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/basic.v0.stderr b/tests/ui/symbol-names/basic.v0.stderr
index 1f02781364eb..17c6d0ce704c 100644
--- a/tests/ui/symbol-names/basic.v0.stderr
+++ b/tests/ui/symbol-names/basic.v0.stderr
@@ -4,7 +4,7 @@ error: symbol-name(_RNvCsCRATE_HASH_5basic4main)
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic[b751b4a00e2291d9]::main)
+error: demangling(basic[a90d658f4748b9d1]::main)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/foreign-types.stderr b/tests/ui/symbol-names/foreign-types.stderr
index d6ee388ddf89..9c8633742b24 100644
--- a/tests/ui/symbol-names/foreign-types.stderr
+++ b/tests/ui/symbol-names/foreign-types.stderr
@@ -4,7 +4,7 @@ error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB_5CheckNvB_11For
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(>)
+error: demangling(>)
   --> $DIR/foreign-types.rs:13:1
    |
 LL | #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/impl1.v0.stderr b/tests/ui/symbol-names/impl1.v0.stderr
index 33caad71f52f..a7cc5fc8ed21 100644
--- a/tests/ui/symbol-names/impl1.v0.stderr
+++ b/tests/ui/symbol-names/impl1.v0.stderr
@@ -4,7 +4,7 @@ error: symbol-name(_RNvMNtCsCRATE_HASH_5impl13fooNtB_3Foo3bar)
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(::bar)
+error: demangling(::bar)
   --> $DIR/impl1.rs:14:9
    |
 LL |         #[rustc_symbol_name]
@@ -28,7 +28,7 @@ error: symbol-name(_RNvMNtCsCRATE_HASH_5impl13barNtNtB_3foo3Foo3baz)
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(::baz)
+error: demangling(::baz)
   --> $DIR/impl1.rs:32:9
    |
 LL |         #[rustc_symbol_name]
@@ -52,7 +52,7 @@ error: symbol-name(_RNvXNCNvCsCRATE_HASH_5impl14mains_0ARDNtB_3Foop5AssocFG
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<[&dyn impl1[2c09c4f1c7c8e90c]::Foo extern "C" fn(&'a u8, ...)> + impl1[2c09c4f1c7c8e90c]::AutoTrait; 3usize] as impl1[2c09c4f1c7c8e90c]::main::{closure#1}::Bar>::method)
+error: demangling(<[&dyn impl1[d5591eb39db23cbb]::Foo extern "C" fn(&'a u8, ...)> + impl1[d5591eb39db23cbb]::AutoTrait; 3usize] as impl1[d5591eb39db23cbb]::main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:62:13
    |
 LL |             #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr
index 29b42f48d803..7dd68e6e3a8e 100644
--- a/tests/ui/symbol-names/issue-60925.legacy.stderr
+++ b/tests/ui/symbol-names/issue-60925.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h13209029be24b923E)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hab58a402db4ebf3aE)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(issue_60925::foo::Foo::foo::h13209029be24b923)
+error: demangling(issue_60925::foo::Foo::foo::hab58a402db4ebf3a)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/issue-60925.v0.stderr b/tests/ui/symbol-names/issue-60925.v0.stderr
index 408c957c6a14..77449becc84d 100644
--- a/tests/ui/symbol-names/issue-60925.v0.stderr
+++ b/tests/ui/symbol-names/issue-60925.v0.stderr
@@ -4,7 +4,7 @@ error: symbol-name(_RNvMNtCsCRATE_HASH_11issue_609253fooINtB_3FooNtNtB
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(>::foo)
+error: demangling(>::foo)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/issue-75326.v0.stderr b/tests/ui/symbol-names/issue-75326.v0.stderr
index 3d7803a0c3b9..fb742f5e4490 100644
--- a/tests/ui/symbol-names/issue-75326.v0.stderr
+++ b/tests/ui/symbol-names/issue-75326.v0.stderr
@@ -4,7 +4,7 @@ error: symbol-name(_RNvXINICsCRATE_HASH_11issue_75326s_0pppEINtB_3FooppENtB
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling( as issue_75326[e8e253d78520f2a2]::Iterator2>::next)
+error: demangling( as issue_75326[189ebc60e18860d7]::Iterator2>::next)
   --> $DIR/issue-75326.rs:41:5
    |
 LL |     #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/trait-objects.v0.stderr b/tests/ui/symbol-names/trait-objects.v0.stderr
index 47192ce5b838..84f2bce66be1 100644
--- a/tests/ui/symbol-names/trait-objects.v0.stderr
+++ b/tests/ui/symbol-names/trait-objects.v0.stderr
@@ -4,7 +4,7 @@ error: symbol-name(_RNvXCsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4cor
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[7260a56bea9f357b]::Bar>::method)
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[3c073c57f94bedc2]::Bar>::method)
   --> $DIR/trait-objects.rs:15:5
    |
 LL |     #[rustc_symbol_name]
@@ -22,7 +22,7 @@ error: symbol-name(_RNvXs_CsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4c
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[7260a56bea9f357b]::Foo>::method)
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3c073c57f94bedc2]::Foo>::method)
   --> $DIR/trait-objects.rs:27:5
    |
 LL |     #[rustc_symbol_name]
@@ -40,7 +40,7 @@ error: symbol-name(_RNvXs0_CsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[7260a56bea9f357b]::Baz>::method)
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3c073c57f94bedc2]::Baz>::method)
   --> $DIR/trait-objects.rs:39:5
    |
 LL |     #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/x86-stdcall.rs b/tests/ui/symbol-names/x86-stdcall.rs
index 9948488c0e95..43c086dc6bc1 100644
--- a/tests/ui/symbol-names/x86-stdcall.rs
+++ b/tests/ui/symbol-names/x86-stdcall.rs
@@ -1,5 +1,7 @@
 // build-pass
-// only-x86-windows
+// only-x86
+// only-windows
+// ignore-gnu - vectorcall is not supported by GCC: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
 #![crate_type = "cdylib"]
 #![feature(abi_vectorcall)]
 
diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs
index 2382c98f8f12..2eea087c7059 100644
--- a/tests/ui/target-feature/gate.rs
+++ b/tests/ui/target-feature/gate.rs
@@ -6,7 +6,6 @@
 // ignore-mips64
 // ignore-powerpc
 // ignore-powerpc64
-// ignore-powerpc64le
 // ignore-riscv64
 // ignore-sparc
 // ignore-sparc64
diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr
index ee542b60a263..2d6abcc0a015 100644
--- a/tests/ui/target-feature/gate.stderr
+++ b/tests/ui/target-feature/gate.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the target feature `avx512bw` is currently unstable
-  --> $DIR/gate.rs:32:18
+  --> $DIR/gate.rs:31:18
    |
 LL | #[target_feature(enable = "avx512bw")]
    |                  ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs
index 0c400d7bf972..b59ed076f936 100644
--- a/tests/ui/target-feature/invalid-attribute.rs
+++ b/tests/ui/target-feature/invalid-attribute.rs
@@ -6,7 +6,6 @@
 // ignore-mips64
 // ignore-powerpc
 // ignore-powerpc64
-// ignore-powerpc64le
 // ignore-riscv64
 // ignore-s390x
 // ignore-sparc
diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr
index 6d37d0917bc6..c36392d430f7 100644
--- a/tests/ui/target-feature/invalid-attribute.stderr
+++ b/tests/ui/target-feature/invalid-attribute.stderr
@@ -1,11 +1,11 @@
 error: malformed `target_feature` attribute input
-  --> $DIR/invalid-attribute.rs:32:1
+  --> $DIR/invalid-attribute.rs:31:1
    |
 LL | #[target_feature = "+sse2"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]`
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:17:1
+  --> $DIR/invalid-attribute.rs:16:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -14,7 +14,7 @@ LL | extern crate alloc;
    | ------------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:22:1
+  --> $DIR/invalid-attribute.rs:21:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | use alloc::alloc::alloc;
    | ------------------------ not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:27:1
+  --> $DIR/invalid-attribute.rs:26:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL | extern "Rust" {}
    | ---------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:49:1
+  --> $DIR/invalid-attribute.rs:48:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL | mod another {}
    | -------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:54:1
+  --> $DIR/invalid-attribute.rs:53:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@ LL | const FOO: usize = 7;
    | --------------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:59:1
+  --> $DIR/invalid-attribute.rs:58:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL | struct Foo;
    | ----------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:64:1
+  --> $DIR/invalid-attribute.rs:63:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL | enum Bar {}
    | ----------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:69:1
+  --> $DIR/invalid-attribute.rs:68:1
    |
 LL |   #[target_feature(enable = "sse2")]
    |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -81,7 +81,7 @@ LL | | }
    | |_- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:77:1
+  --> $DIR/invalid-attribute.rs:76:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL | type Uwu = ();
    | -------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:82:1
+  --> $DIR/invalid-attribute.rs:81:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL | trait Baz {}
    | ------------ not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:92:1
+  --> $DIR/invalid-attribute.rs:91:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -108,7 +108,7 @@ LL | static A: () = ();
    | ------------------ not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:97:1
+  --> $DIR/invalid-attribute.rs:96:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -117,7 +117,7 @@ LL | impl Quux for u8 {}
    | ------------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:102:1
+  --> $DIR/invalid-attribute.rs:101:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -126,7 +126,7 @@ LL | impl Foo {}
    | ----------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:120:5
+  --> $DIR/invalid-attribute.rs:119:5
    |
 LL |       #[target_feature(enable = "sse2")]
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -138,7 +138,7 @@ LL | |     }
    | |_____- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:128:5
+  --> $DIR/invalid-attribute.rs:127:5
    |
 LL |     #[target_feature(enable = "sse2")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -147,25 +147,25 @@ LL |     || {};
    |     ----- not a function definition
 
 error: the feature named `foo` is not valid for this target
-  --> $DIR/invalid-attribute.rs:34:18
+  --> $DIR/invalid-attribute.rs:33:18
    |
 LL | #[target_feature(enable = "foo")]
    |                  ^^^^^^^^^^^^^^ `foo` is not valid for this target
 
 error: malformed `target_feature` attribute input
-  --> $DIR/invalid-attribute.rs:37:18
+  --> $DIR/invalid-attribute.rs:36:18
    |
 LL | #[target_feature(bar)]
    |                  ^^^ help: must be of the form: `enable = ".."`
 
 error: malformed `target_feature` attribute input
-  --> $DIR/invalid-attribute.rs:39:18
+  --> $DIR/invalid-attribute.rs:38:18
    |
 LL | #[target_feature(disable = "baz")]
    |                  ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
 
 error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
-  --> $DIR/invalid-attribute.rs:43:1
+  --> $DIR/invalid-attribute.rs:42:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -177,13 +177,13 @@ LL | fn bar() {}
    = help: add `#![feature(target_feature_11)]` to the crate attributes to enable
 
 error: cannot use `#[inline(always)]` with `#[target_feature]`
-  --> $DIR/invalid-attribute.rs:87:1
+  --> $DIR/invalid-attribute.rs:86:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
 
 error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
-  --> $DIR/invalid-attribute.rs:112:5
+  --> $DIR/invalid-attribute.rs:111:5
    |
 LL |     #[target_feature(enable = "sse2")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout
index 910c0da27378..9d467f73d097 100644
--- a/tests/ui/thir-print/thir-flat.stdout
+++ b/tests/ui/thir-print/thir-flat.stdout
@@ -1,4 +1,4 @@
-DefId(0:3 ~ thir_flat[45a6]::main):
+DefId(0:3 ~ thir_flat[7b97]::main):
 Thir {
     body_type: Fn(
         ([]; c_variadic: false)->(),
@@ -30,7 +30,7 @@ Thir {
             kind: Scope {
                 region_scope: Node(2),
                 lint_level: Explicit(
-                    HirId(DefId(0:3 ~ thir_flat[45a6]::main).2),
+                    HirId(DefId(0:3 ~ thir_flat[7b97]::main).2),
                 ),
                 value: e0,
             },
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index d6174ec262a4..eea04c0951d3 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -1,10 +1,10 @@
-DefId(0:16 ~ thir_tree_match[3c9a]::has_match):
+DefId(0:16 ~ thir_tree_match[fcf8]::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))
+        hir_id: Some(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).1))
         param: Some( 
             Pat: {
                 ty: Foo
@@ -14,7 +14,7 @@ params: [
                         mutability: Not
                         name: "foo"
                         mode: ByValue
-                        var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).2))
+                        var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).2))
                         ty: Foo
                         is_primary: true
                         subpattern: None
@@ -41,7 +41,7 @@ body:
                         kind: 
                             Scope {
                                 region_scope: Node(26)
-                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).26))
+                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).26))
                                 value:
                                     Expr {
                                         ty: bool
@@ -63,7 +63,7 @@ body:
                                                         kind: 
                                                             Scope {
                                                                 region_scope: Node(3)
-                                                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).3))
+                                                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).3))
                                                                 value:
                                                                     Expr {
                                                                         ty: bool
@@ -79,7 +79,7 @@ body:
                                                                                         kind: 
                                                                                             Scope {
                                                                                                 region_scope: Node(4)
-                                                                                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).4))
+                                                                                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4))
                                                                                                 value:
                                                                                                     Expr {
                                                                                                         ty: Foo
@@ -87,7 +87,7 @@ body:
                                                                                                         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))
+                                                                                                                id: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).2))
                                                                                                             }
                                                                                                     }
                                                                                             }
@@ -102,10 +102,10 @@ body:
                                                                                                     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 }]
+                                                                                                                did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
+                                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::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 }
+                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 3477539199540094892 }
                                                                                                         substs: []
                                                                                                         variant_index: 0
                                                                                                         subpatterns: [
@@ -116,10 +116,10 @@ body:
                                                                                                                     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 }]
+                                                                                                                                did: DefId(0:3 ~ thir_tree_match[fcf8]::Bar)
+                                                                                                                                variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[fcf8]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[fcf8]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[fcf8]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[fcf8]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[fcf8]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[fcf8]::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 }
+                                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 10333377570083945360 }
                                                                                                                         substs: []
                                                                                                                         variant_index: 0
                                                                                                                         subpatterns: []
@@ -148,7 +148,7 @@ body:
                                                                                                                 kind: 
                                                                                                                     Scope {
                                                                                                                         region_scope: Node(13)
-                                                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).13))
+                                                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).13))
                                                                                                                         value:
                                                                                                                             Expr {
                                                                                                                                 ty: bool
@@ -162,7 +162,7 @@ body:
                                                                                                             }
                                                                                                     }
                                                                                             }
-                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).12))
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).12))
                                                                                         scope: Node(12)
                                                                                         span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0)
                                                                                     }
@@ -175,10 +175,10 @@ body:
                                                                                                     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 }]
+                                                                                                                did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
+                                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::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 }
+                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 3477539199540094892 }
                                                                                                         substs: []
                                                                                                         variant_index: 0
                                                                                                         subpatterns: [
@@ -211,7 +211,7 @@ body:
                                                                                                                 kind: 
                                                                                                                     Scope {
                                                                                                                         region_scope: Node(19)
-                                                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).19))
+                                                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).19))
                                                                                                                         value:
                                                                                                                             Expr {
                                                                                                                                 ty: bool
@@ -225,7 +225,7 @@ body:
                                                                                                             }
                                                                                                     }
                                                                                             }
-                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).18))
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).18))
                                                                                         scope: Node(18)
                                                                                         span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0)
                                                                                     }
@@ -238,10 +238,10 @@ body:
                                                                                                     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 }]
+                                                                                                                did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
+                                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])) }], flags: NO_VARIANT_FLAGS }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::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 }
+                                                                                                                repr: ReprOptions { int: None, align: None, pack: None, flags: (empty), field_shuffle_seed: 3477539199540094892 }
                                                                                                         substs: []
                                                                                                         variant_index: 1
                                                                                                         subpatterns: []
@@ -266,7 +266,7 @@ body:
                                                                                                                 kind: 
                                                                                                                     Scope {
                                                                                                                         region_scope: Node(24)
-                                                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).24))
+                                                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).24))
                                                                                                                         value:
                                                                                                                             Expr {
                                                                                                                                 ty: bool
@@ -280,7 +280,7 @@ body:
                                                                                                             }
                                                                                                     }
                                                                                             }
-                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[3c9a]::has_match).23))
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).23))
                                                                                         scope: Node(23)
                                                                                         span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0)
                                                                                     }
@@ -297,7 +297,7 @@ body:
     }
 
 
-DefId(0:17 ~ thir_tree_match[3c9a]::main):
+DefId(0:17 ~ thir_tree_match[fcf8]::main):
 params: [
 ]
 body:
@@ -317,7 +317,7 @@ body:
                         kind: 
                             Scope {
                                 region_scope: Node(2)
-                                lint_level: Explicit(HirId(DefId(0:17 ~ thir_tree_match[3c9a]::main).2))
+                                lint_level: Explicit(HirId(DefId(0:17 ~ thir_tree_match[fcf8]::main).2))
                                 value:
                                     Expr {
                                         ty: ()
diff --git a/tests/ui/thir-print/thir-tree.stdout b/tests/ui/thir-print/thir-tree.stdout
index 0a35d9fb78ca..1b478dbef993 100644
--- a/tests/ui/thir-print/thir-tree.stdout
+++ b/tests/ui/thir-print/thir-tree.stdout
@@ -1,4 +1,4 @@
-DefId(0:3 ~ thir_tree[8f1d]::main):
+DefId(0:3 ~ thir_tree[7aaa]::main):
 params: [
 ]
 body:
@@ -18,7 +18,7 @@ body:
                         kind: 
                             Scope {
                                 region_scope: Node(2)
-                                lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2))
+                                lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree[7aaa]::main).2))
                                 value:
                                     Expr {
                                         ty: ()
diff --git a/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.rs b/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.rs
index 471a6b836b51..8e43b7249f7c 100644
--- a/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.rs
+++ b/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.rs
@@ -18,6 +18,6 @@ fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String { //~ ERROR expec
 
 fn issue_95327() where ::Assoc: String {}
 //~^ ERROR expected trait, found struct
-//~| ERROR use of undeclared type `Unresolved`
+//~| ERROR cannot find trait `Unresolved` in this scope
 
 fn main() {}
diff --git a/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr b/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr
index 5be334986418..0020f9e416df 100644
--- a/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr
+++ b/tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr
@@ -1,9 +1,3 @@
-error[E0433]: failed to resolve: use of undeclared type `Unresolved`
-  --> $DIR/assoc_type_bound_with_struct.rs:19:31
-   |
-LL | fn issue_95327() where ::Assoc: String {}
-   |                               ^^^^^^^^^^ use of undeclared type `Unresolved`
-
 error[E0404]: expected trait, found struct `String`
   --> $DIR/assoc_type_bound_with_struct.rs:5:46
    |
@@ -76,6 +70,12 @@ help: a trait with a similar name exists
 LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: ToString {
    |                                                         ~~~~~~~~
 
+error[E0405]: cannot find trait `Unresolved` in this scope
+  --> $DIR/assoc_type_bound_with_struct.rs:19:31
+   |
+LL | fn issue_95327() where ::Assoc: String {}
+   |                               ^^^^^^^^^^ not found in this scope
+
 error[E0404]: expected trait, found struct `String`
   --> $DIR/assoc_type_bound_with_struct.rs:19:51
    |
@@ -87,5 +87,5 @@ LL | fn issue_95327() where ::Assoc: String {}
 
 error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0404, E0433.
+Some errors have detailed explanations: E0404, E0405.
 For more information about an error, try `rustc --explain E0404`.
diff --git a/tests/ui/traits/dyn-trait.rs b/tests/ui/traits/dyn-trait.rs
index e1c1a8de55a0..10e69105ceda 100644
--- a/tests/ui/traits/dyn-trait.rs
+++ b/tests/ui/traits/dyn-trait.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-pretty `dyn ::foo` parses differently in the current edition
 
 use std::fmt::Display;
 
diff --git a/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs b/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs
index fd5d0e3b1946..531203d9c64f 100644
--- a/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs
+++ b/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs
@@ -1,7 +1,7 @@
 // compile-flags: -Ztrait-solver=next
 
 // check that when computing `alias-eq(<() as Foo>::Assoc, <() as Foo>::Assoc)`
-//  we do not infer `?0 = u8` via the `for (): Foo` impl or `?0 = u16` by
+// we do not infer `?0 = u8` via the `for (): Foo` impl or `?0 = u16` by
 // relating substs as either could be a valid solution.
 
 trait Foo {
diff --git a/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.fail.stderr b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.fail.stderr
new file mode 100644
index 000000000000..6a926534e079
--- /dev/null
+++ b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.fail.stderr
@@ -0,0 +1,18 @@
+error[E0277]: `impl Future` cannot be sent between threads safely
+  --> $DIR/auto-with-drop_tracking_mir.rs:24:13
+   |
+LL |     is_send(foo());
+   |     ------- ^^^^^ `impl Future` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Send` is not implemented for `impl Future`
+note: required by a bound in `is_send`
+  --> $DIR/auto-with-drop_tracking_mir.rs:23:24
+   |
+LL |     fn is_send(_: impl Send) {}
+   |                        ^^^^ required by this bound in `is_send`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs
new file mode 100644
index 000000000000..a5db7c4636b3
--- /dev/null
+++ b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs
@@ -0,0 +1,26 @@
+// compile-flags: -Ztrait-solver=next -Zdrop-tracking-mir
+// edition: 2021
+// revisions: pass fail
+//[pass] check-pass
+
+#![feature(negative_impls)]
+
+struct NotSync;
+impl !Sync for NotSync {}
+
+async fn foo() {
+    #[cfg(pass)]
+    let x = &();
+    #[cfg(fail)]
+    let x = &NotSync;
+    bar().await;
+    drop(x);
+}
+
+async fn bar() {}
+
+fn main() {
+    fn is_send(_: impl Send) {}
+    is_send(foo());
+    //[fail]~^ ERROR `impl Future` cannot be sent between threads safely
+}
diff --git a/tests/ui/traits/new-solver/pointer-like.rs b/tests/ui/traits/new-solver/pointer-like.rs
index 3745a075e6a4..98630176976f 100644
--- a/tests/ui/traits/new-solver/pointer-like.rs
+++ b/tests/ui/traits/new-solver/pointer-like.rs
@@ -9,6 +9,6 @@ fn require_(_: impl PointerLike) {}
 fn main() {
     require_(1usize);
     require_(1u16);
-    //~^ ERROR `u16` needs to have the same alignment and size as a pointer
+    //~^ ERROR `u16` needs to have the same ABI as a pointer
     require_(&1i16);
 }
diff --git a/tests/ui/traits/new-solver/pointer-like.stderr b/tests/ui/traits/new-solver/pointer-like.stderr
index f695e64187d4..215a81cc2657 100644
--- a/tests/ui/traits/new-solver/pointer-like.stderr
+++ b/tests/ui/traits/new-solver/pointer-like.stderr
@@ -1,4 +1,4 @@
-error[E0277]: `u16` needs to have the same alignment and size as a pointer
+error[E0277]: `u16` needs to have the same ABI as a pointer
   --> $DIR/pointer-like.rs:11:14
    |
 LL |     require_(1u16);
diff --git a/tests/ui/traits/new-solver/prefer-candidate-no-constraints.rs b/tests/ui/traits/new-solver/prefer-candidate-no-constraints.rs
new file mode 100644
index 000000000000..6f8164f3a40f
--- /dev/null
+++ b/tests/ui/traits/new-solver/prefer-candidate-no-constraints.rs
@@ -0,0 +1,22 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+trait Foo {}
+
+impl Foo for T {}
+
+trait Bar {}
+
+struct Wrapper<'a, T>(&'a T);
+
+impl<'a, T> Bar for Wrapper<'a, T> where &'a T: Foo {}
+// We need to satisfy `&'a T: Foo` when checking that this impl is WF
+// that can either be satisfied via the param-env, or via an impl.
+//
+// When satisfied via the param-env, since each lifetime is canonicalized
+// separately, we end up getting extra region constraints.
+//
+// However, when satisfied via the impl, there are no region constraints,
+// and we can short-circuit a response with no external constraints.
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/prefer-param-env-on-ambiguity.rs b/tests/ui/traits/new-solver/prefer-param-env-on-ambiguity.rs
new file mode 100644
index 000000000000..909b33ec3d5a
--- /dev/null
+++ b/tests/ui/traits/new-solver/prefer-param-env-on-ambiguity.rs
@@ -0,0 +1,10 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+trait Foo<'a> {}
+trait Bar<'a> {}
+
+impl<'a, T: Bar<'a>> Foo<'a> for T {}
+impl Bar<'static> for T {}
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr
index 29cfa47a1050..e3a92e85e17e 100644
--- a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr
+++ b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr
@@ -1,9 +1,16 @@
-error[E0282]: type annotations needed
+error[E0283]: type annotations needed: cannot satisfy `::Assoc1: Bar`
   --> $DIR/recursive-self-normalization-2.rs:15:5
    |
 LL |     needs_bar::();
-   |     ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `S` declared on the function `needs_bar`
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: cannot satisfy `::Assoc1: Bar`
+note: required by a bound in `needs_bar`
+  --> $DIR/recursive-self-normalization-2.rs:12:17
+   |
+LL | fn needs_bar() {}
+   |                 ^^^ required by this bound in `needs_bar`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/new-solver/recursive-self-normalization.stderr b/tests/ui/traits/new-solver/recursive-self-normalization.stderr
index ba39981893d4..773007aebaa6 100644
--- a/tests/ui/traits/new-solver/recursive-self-normalization.stderr
+++ b/tests/ui/traits/new-solver/recursive-self-normalization.stderr
@@ -1,9 +1,16 @@
-error[E0282]: type annotations needed
+error[E0283]: type annotations needed: cannot satisfy `::Assoc: Bar`
   --> $DIR/recursive-self-normalization.rs:11:5
    |
 LL |     needs_bar::();
-   |     ^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `S` declared on the function `needs_bar`
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: cannot satisfy `::Assoc: Bar`
+note: required by a bound in `needs_bar`
+  --> $DIR/recursive-self-normalization.rs:8:17
+   |
+LL | fn needs_bar() {}
+   |                 ^^^ required by this bound in `needs_bar`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/non_lifetime_binders/method-probe.rs b/tests/ui/traits/non_lifetime_binders/method-probe.rs
new file mode 100644
index 000000000000..8df240c2082b
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/method-probe.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+#![feature(non_lifetime_binders)]
+//~^ WARN the feature `non_lifetime_binders` is incomplete
+
+trait Foo: for Bar {}
+
+trait Bar {
+    fn method() -> T;
+}
+
+fn x() {
+    let _: i32 = T::method();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/non_lifetime_binders/method-probe.stderr b/tests/ui/traits/non_lifetime_binders/method-probe.stderr
new file mode 100644
index 000000000000..8f61792e6ce7
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/method-probe.stderr
@@ -0,0 +1,11 @@
+warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/method-probe.rs:3:12
+   |
+LL | #![feature(non_lifetime_binders)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #108185  for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs
index e6f7dc410b61..a450dbb82d1b 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.rs
+++ b/tests/ui/typeck/typeck_type_placeholder_item.rs
@@ -228,4 +228,5 @@ fn evens_squared(n: usize) -> _ {
 
 const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
 //~^ ERROR the trait bound
+//~| ERROR the trait bound
 //~| ERROR the placeholder
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr
index 9144ab9e3a6b..bc6c9fd07799 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr
@@ -437,6 +437,19 @@ LL | fn evens_squared(n: usize) -> _ {
    |                               not allowed in type signatures
    |                               help: replace with an appropriate return type: `impl Iterator`
 
+error[E0277]: the trait bound `std::ops::Range<{integer}>: Iterator` is not satisfied
+  --> $DIR/typeck_type_placeholder_item.rs:229:22
+   |
+LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
+   |                      ^^^^^^ `std::ops::Range<{integer}>` is not an iterator
+   |
+   = help: the trait `~const Iterator` is not implemented for `std::ops::Range<{integer}>`
+note: the trait `Iterator` is implemented for `std::ops::Range<{integer}>`, but that implementation is not `const`
+  --> $DIR/typeck_type_placeholder_item.rs:229:14
+   |
+LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
+   |              ^^^^^^^
+
 error[E0277]: the trait bound `Filter, [closure@$DIR/typeck_type_placeholder_item.rs:229:29: 229:32]>: Iterator` is not satisfied
   --> $DIR/typeck_type_placeholder_item.rs:229:45
    |
@@ -664,7 +677,7 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              help: replace with the correct type: `i32`
 
-error: aborting due to 72 previous errors
+error: aborting due to 73 previous errors
 
 Some errors have detailed explanations: E0121, E0277, E0282, E0403.
 For more information about an error, try `rustc --explain E0121`.
diff --git a/tests/ui/ufcs/ufcs-partially-resolved.rs b/tests/ui/ufcs/ufcs-partially-resolved.rs
index e6470aa6d64f..712668728c9e 100644
--- a/tests/ui/ufcs/ufcs-partially-resolved.rs
+++ b/tests/ui/ufcs/ufcs-partially-resolved.rs
@@ -17,37 +17,37 @@ type A = u32;
 
 fn main() {
     let _: ::N; //~ ERROR cannot find associated type `N` in trait `Tr`
-    let _: ::N; //~ ERROR cannot find associated type `N` in enum `E`
-    let _: ::N; //~ ERROR cannot find associated type `N` in `A`
+    let _: ::N; //~ ERROR expected trait, found enum `E`
+    let _: ::N; //~ ERROR expected trait, found type alias `A`
     ::N; //~ ERROR cannot find method or associated constant `N` in trait `Tr`
-    ::N; //~ ERROR cannot find method or associated constant `N` in enum `E`
-    ::N; //~ ERROR cannot find method or associated constant `N` in `A`
+    ::N; //~ ERROR expected trait, found enum `E`
+    ::N; //~ ERROR expected trait, found type alias `A`
     let _: ::Y; // OK
-    let _: ::Y; //~ ERROR expected associated type, found variant `E::Y`
+    let _: ::Y; //~ ERROR expected trait, found enum `E`
     ::Y; // OK
-    ::Y; //~ ERROR expected method or associated constant, found unit variant `E::Y`
+    ::Y; //~ ERROR expected trait, found enum `E`
 
     let _: ::N::NN; //~ ERROR cannot find associated type `N` in trait `Tr`
-    let _: ::N::NN; //~ ERROR cannot find associated type `N` in enum `E`
-    let _: ::N::NN; //~ ERROR cannot find associated type `N` in `A`
+    let _: ::N::NN; //~ ERROR expected trait, found enum `E`
+    let _: ::N::NN; //~ ERROR expected trait, found type alias `A`
     ::N::NN; //~ ERROR cannot find associated type `N` in trait `Tr`
-    ::N::NN; //~ ERROR cannot find associated type `N` in enum `E`
-    ::N::NN; //~ ERROR cannot find associated type `N` in `A`
+    ::N::NN; //~ ERROR expected trait, found enum `E`
+    ::N::NN; //~ ERROR expected trait, found type alias `A`
     let _: ::Y::NN; //~ ERROR ambiguous associated type
-    let _: ::Y::NN; //~ ERROR expected associated type, found variant `E::Y`
+    let _: ::Y::NN; //~ ERROR expected trait, found enum `E`
     ::Y::NN; //~ ERROR no associated item named `NN` found for type `u16`
-    ::Y::NN; //~ ERROR expected associated type, found variant `E::Y`
+    ::Y::NN; //~ ERROR expected trait, found enum `E`
 
-    let _: ::NN; //~ ERROR cannot find associated type `NN` in `Tr::N`
-    let _: ::NN; //~ ERROR cannot find associated type `NN` in `E::N`
-    let _: ::NN; //~ ERROR cannot find associated type `NN` in `A::N`
-    ::NN; //~ ERROR cannot find method or associated constant `NN` in `Tr::N`
-    ::NN; //~ ERROR cannot find method or associated constant `NN` in `E::N`
-    ::NN; //~ ERROR cannot find method or associated constant `NN` in `A::N`
-    let _: ::NN; //~ ERROR cannot find associated type `NN` in `Tr::Y`
-    let _: ::NN; //~ ERROR failed to resolve: `Y` is a variant, not a module
-    ::NN; //~ ERROR cannot find method or associated constant `NN` in `Tr::Y`
-    ::NN; //~ ERROR failed to resolve: `Y` is a variant, not a module
+    let _: ::NN; //~ ERROR cannot find trait `N` in trait `Tr`
+    let _: ::NN; //~ ERROR cannot find trait `N` in enum `E`
+    let _: ::NN; //~ ERROR cannot find trait `N` in `A`
+    ::NN; //~ ERROR cannot find trait `N` in trait `Tr`
+    ::NN; //~ ERROR cannot find trait `N` in enum `E`
+    ::NN; //~ ERROR cannot find trait `N` in `A`
+    let _: ::NN; //~ ERROR expected trait, found associated type `Tr::Y
+    let _: ::NN; //~ ERROR expected trait, found variant `E::Y`
+    ::NN; //~ ERROR expected trait, found associated type `Tr::Y`
+    ::NN; //~ ERROR expected trait, found variant `E::Y`
 
     let _: ::Z; //~ ERROR expected associated type, found associated function `Dr::Z`
     ::X; //~ ERROR expected method or associated constant, found associated type `Dr::X`
diff --git a/tests/ui/ufcs/ufcs-partially-resolved.stderr b/tests/ui/ufcs/ufcs-partially-resolved.stderr
index 72fccea8ae39..eef55c8dc686 100644
--- a/tests/ui/ufcs/ufcs-partially-resolved.stderr
+++ b/tests/ui/ufcs/ufcs-partially-resolved.stderr
@@ -1,15 +1,3 @@
-error[E0433]: failed to resolve: `Y` is a variant, not a module
-  --> $DIR/ufcs-partially-resolved.rs:48:22
-   |
-LL |     let _: ::NN;
-   |                      ^ `Y` is a variant, not a module
-
-error[E0433]: failed to resolve: `Y` is a variant, not a module
-  --> $DIR/ufcs-partially-resolved.rs:50:15
-   |
-LL |     ::NN;
-   |               ^ `Y` is a variant, not a module
-
 error[E0576]: cannot find associated type `N` in trait `Tr`
   --> $DIR/ufcs-partially-resolved.rs:19:24
    |
@@ -19,17 +7,25 @@ LL |     type Y = u16;
 LL |     let _: ::N;
    |                        ^ help: an associated type with a similar name exists: `Y`
 
-error[E0576]: cannot find associated type `N` in enum `E`
-  --> $DIR/ufcs-partially-resolved.rs:20:23
+error[E0404]: expected trait, found enum `E`
+  --> $DIR/ufcs-partially-resolved.rs:20:19
    |
 LL |     let _: ::N;
-   |                       ^ not found in `E`
+   |                   ^ help: a trait with a similar name exists: `Eq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+   = note: similarly named trait `Eq` defined here
 
-error[E0576]: cannot find associated type `N` in `A`
-  --> $DIR/ufcs-partially-resolved.rs:21:23
+error[E0404]: expected trait, found type alias `A`
+  --> $DIR/ufcs-partially-resolved.rs:21:19
    |
 LL |     let _: ::N;
-   |                       ^ not found in `A`
+   |                   ^ type aliases cannot be used as traits
+   |
+help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias
+   |
+LL | trait A = u32;
+   |
 
 error[E0576]: cannot find method or associated constant `N` in trait `Tr`
   --> $DIR/ufcs-partially-resolved.rs:22:17
@@ -40,29 +36,43 @@ LL |     fn Y() {}
 LL |     ::N;
    |                 ^ help: an associated function with a similar name exists: `Y`
 
-error[E0576]: cannot find method or associated constant `N` in enum `E`
-  --> $DIR/ufcs-partially-resolved.rs:23:16
+error[E0404]: expected trait, found enum `E`
+  --> $DIR/ufcs-partially-resolved.rs:23:12
    |
 LL |     ::N;
-   |                ^ not found in `E`
+   |            ^ help: a trait with a similar name exists: `Eq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+   = note: similarly named trait `Eq` defined here
 
-error[E0576]: cannot find method or associated constant `N` in `A`
-  --> $DIR/ufcs-partially-resolved.rs:24:16
+error[E0404]: expected trait, found type alias `A`
+  --> $DIR/ufcs-partially-resolved.rs:24:12
    |
 LL |     ::N;
-   |                ^ not found in `A`
+   |            ^ type aliases cannot be used as traits
+   |
+help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias
+   |
+LL | trait A = u32;
+   |
 
-error[E0575]: expected associated type, found variant `E::Y`
-  --> $DIR/ufcs-partially-resolved.rs:26:12
+error[E0404]: expected trait, found enum `E`
+  --> $DIR/ufcs-partially-resolved.rs:26:19
    |
 LL |     let _: ::Y;
-   |            ^^^^^^^^^^^^ not a associated type
+   |                   ^ help: a trait with a similar name exists: `Eq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+   = note: similarly named trait `Eq` defined here
 
-error[E0575]: expected method or associated constant, found unit variant `E::Y`
-  --> $DIR/ufcs-partially-resolved.rs:28:5
+error[E0404]: expected trait, found enum `E`
+  --> $DIR/ufcs-partially-resolved.rs:28:12
    |
 LL |     ::Y;
-   |     ^^^^^^^^^^^^ not a method or associated constant
+   |            ^ help: a trait with a similar name exists: `Eq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+   = note: similarly named trait `Eq` defined here
 
 error[E0576]: cannot find associated type `N` in trait `Tr`
   --> $DIR/ufcs-partially-resolved.rs:30:24
@@ -73,17 +83,25 @@ LL |     type Y = u16;
 LL |     let _: ::N::NN;
    |                        ^ help: an associated type with a similar name exists: `Y`
 
-error[E0576]: cannot find associated type `N` in enum `E`
-  --> $DIR/ufcs-partially-resolved.rs:31:23
+error[E0404]: expected trait, found enum `E`
+  --> $DIR/ufcs-partially-resolved.rs:31:19
    |
 LL |     let _: ::N::NN;
-   |                       ^ not found in `E`
+   |                   ^ help: a trait with a similar name exists: `Eq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+   = note: similarly named trait `Eq` defined here
 
-error[E0576]: cannot find associated type `N` in `A`
-  --> $DIR/ufcs-partially-resolved.rs:32:23
+error[E0404]: expected trait, found type alias `A`
+  --> $DIR/ufcs-partially-resolved.rs:32:19
    |
 LL |     let _: ::N::NN;
-   |                       ^ not found in `A`
+   |                   ^ type aliases cannot be used as traits
+   |
+help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias
+   |
+LL | trait A = u32;
+   |
 
 error[E0576]: cannot find associated type `N` in trait `Tr`
   --> $DIR/ufcs-partially-resolved.rs:33:17
@@ -94,77 +112,103 @@ LL |     type Y = u16;
 LL |     ::N::NN;
    |                 ^ help: an associated type with a similar name exists: `Y`
 
-error[E0576]: cannot find associated type `N` in enum `E`
-  --> $DIR/ufcs-partially-resolved.rs:34:16
+error[E0404]: expected trait, found enum `E`
+  --> $DIR/ufcs-partially-resolved.rs:34:12
    |
 LL |     ::N::NN;
-   |                ^ not found in `E`
+   |            ^ help: a trait with a similar name exists: `Eq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+   = note: similarly named trait `Eq` defined here
 
-error[E0576]: cannot find associated type `N` in `A`
-  --> $DIR/ufcs-partially-resolved.rs:35:16
+error[E0404]: expected trait, found type alias `A`
+  --> $DIR/ufcs-partially-resolved.rs:35:12
    |
 LL |     ::N::NN;
-   |                ^ not found in `A`
+   |            ^ type aliases cannot be used as traits
+   |
+help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias
+   |
+LL | trait A = u32;
+   |
 
-error[E0575]: expected associated type, found variant `E::Y`
-  --> $DIR/ufcs-partially-resolved.rs:37:12
+error[E0404]: expected trait, found enum `E`
+  --> $DIR/ufcs-partially-resolved.rs:37:19
    |
 LL |     let _: ::Y::NN;
-   |            ^^^^^^^^^^^^^^^^ not a associated type
+   |                   ^ help: a trait with a similar name exists: `Eq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+   = note: similarly named trait `Eq` defined here
 
-error[E0575]: expected associated type, found variant `E::Y`
-  --> $DIR/ufcs-partially-resolved.rs:39:5
+error[E0404]: expected trait, found enum `E`
+  --> $DIR/ufcs-partially-resolved.rs:39:12
    |
 LL |     ::Y::NN;
-   |     ^^^^^^^^^^^^^^^^ not a associated type
+   |            ^ help: a trait with a similar name exists: `Eq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+   = note: similarly named trait `Eq` defined here
 
-error[E0576]: cannot find associated type `NN` in `Tr::N`
-  --> $DIR/ufcs-partially-resolved.rs:41:27
+error[E0405]: cannot find trait `N` in trait `Tr`
+  --> $DIR/ufcs-partially-resolved.rs:41:23
    |
 LL |     let _: ::NN;
-   |                           ^^ not found in `Tr::N`
+   |                       ^ not found in `Tr`
 
-error[E0576]: cannot find associated type `NN` in `E::N`
-  --> $DIR/ufcs-partially-resolved.rs:42:26
+error[E0405]: cannot find trait `N` in enum `E`
+  --> $DIR/ufcs-partially-resolved.rs:42:22
    |
 LL |     let _: ::NN;
-   |                          ^^ not found in `E::N`
+   |                      ^ not found in `E`
 
-error[E0576]: cannot find associated type `NN` in `A::N`
-  --> $DIR/ufcs-partially-resolved.rs:43:26
+error[E0405]: cannot find trait `N` in `A`
+  --> $DIR/ufcs-partially-resolved.rs:43:22
    |
 LL |     let _: ::NN;
-   |                          ^^ not found in `A::N`
+   |                      ^ not found in `A`
 
-error[E0576]: cannot find method or associated constant `NN` in `Tr::N`
-  --> $DIR/ufcs-partially-resolved.rs:44:20
+error[E0405]: cannot find trait `N` in trait `Tr`
+  --> $DIR/ufcs-partially-resolved.rs:44:16
    |
 LL |     ::NN;
-   |                    ^^ not found in `Tr::N`
+   |                ^ not found in `Tr`
 
-error[E0576]: cannot find method or associated constant `NN` in `E::N`
-  --> $DIR/ufcs-partially-resolved.rs:45:19
+error[E0405]: cannot find trait `N` in enum `E`
+  --> $DIR/ufcs-partially-resolved.rs:45:15
    |
 LL |     ::NN;
-   |                   ^^ not found in `E::N`
+   |               ^ not found in `E`
 
-error[E0576]: cannot find method or associated constant `NN` in `A::N`
-  --> $DIR/ufcs-partially-resolved.rs:46:19
+error[E0405]: cannot find trait `N` in `A`
+  --> $DIR/ufcs-partially-resolved.rs:46:15
    |
 LL |     ::NN;
-   |                   ^^ not found in `A::N`
+   |               ^ not found in `A`
 
-error[E0576]: cannot find associated type `NN` in `Tr::Y`
-  --> $DIR/ufcs-partially-resolved.rs:47:27
+error[E0404]: expected trait, found associated type `Tr::Y`
+  --> $DIR/ufcs-partially-resolved.rs:47:19
    |
 LL |     let _: ::NN;
-   |                           ^^ not found in `Tr::Y`
+   |                   ^^^^^ not a trait
 
-error[E0576]: cannot find method or associated constant `NN` in `Tr::Y`
-  --> $DIR/ufcs-partially-resolved.rs:49:20
+error[E0404]: expected trait, found variant `E::Y`
+  --> $DIR/ufcs-partially-resolved.rs:48:19
+   |
+LL |     let _: ::NN;
+   |                   ^^^^ not a trait
+
+error[E0404]: expected trait, found associated type `Tr::Y`
+  --> $DIR/ufcs-partially-resolved.rs:49:12
    |
 LL |     ::NN;
-   |                    ^^ not found in `Tr::Y`
+   |            ^^^^^ not a trait
+
+error[E0404]: expected trait, found variant `E::Y`
+  --> $DIR/ufcs-partially-resolved.rs:50:12
+   |
+LL |     ::NN;
+   |            ^^^^ not a trait
 
 error[E0575]: expected associated type, found associated function `Dr::Z`
   --> $DIR/ufcs-partially-resolved.rs:52:12
@@ -226,5 +270,5 @@ LL |     ::X::N;
 
 error: aborting due to 32 previous errors
 
-Some errors have detailed explanations: E0223, E0433, E0575, E0576, E0599.
+Some errors have detailed explanations: E0223, E0404, E0405, E0575, E0576, E0599.
 For more information about an error, try `rustc --explain E0223`.
diff --git a/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr b/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr
index f4c7acd5c589..ce409f627be2 100644
--- a/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr
+++ b/tests/ui/where-clauses/higher-ranked-fn-type.verbose.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `for fn(&ReLateBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[1209]::called::'b), 'b) }) ()): Foo` is not satisfied
+error[E0277]: the trait bound `for fn(&ReLateBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[9e51]::called::'b), 'b) }) ()): Foo` is not satisfied
   --> $DIR/higher-ranked-fn-type.rs:20:5
    |
 LL |     called()
-   |     ^^^^^^ the trait `for Foo` is not implemented for `fn(&ReLateBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[1209]::called::'b), 'b) }) ())`
+   |     ^^^^^^ the trait `for Foo` is not implemented for `fn(&ReLateBound(DebruijnIndex(1), BoundRegion { var: 0, kind: BrNamed(DefId(0:6 ~ higher_ranked_fn_type[9e51]::called::'b), 'b) }) ())`
    |
 note: required by a bound in `called`
   --> $DIR/higher-ranked-fn-type.rs:12:25
diff --git a/triagebot.toml b/triagebot.toml
index 20a8be283b99..5f4de0562f89 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -186,13 +186,17 @@ trigger_files = [
     "configure",
     "Cargo.toml",
     "config.example.toml",
-    "src/stage0.json"
+    "src/stage0.json",
+    "src/tools/compiletest",
+    "src/tools/tidy",
 ]
 
 [autolabel."T-infra"]
 trigger_files = [
     "src/ci",
     "src/tools/bump-stage0",
+    "src/tools/cargotest",
+    "src/tools/tier-check",
 ]
 
 [autolabel."T-style"]
@@ -466,8 +470,8 @@ cc = ["@rust-lang/style"]
 
 [mentions."Cargo.lock"]
 message = """
-These commits modify the `Cargo.lock` file. Random changes to `Cargo.lock` can be introduced when switching branches and rebasing PRs. 
-This was probably unintentional and should be reverted before this PR is merged. 
+These commits modify the `Cargo.lock` file. Random changes to `Cargo.lock` can be introduced when switching branches and rebasing PRs.
+This was probably unintentional and should be reverted before this PR is merged.
 
 If this was intentional then you can ignore this comment.
 """
@@ -495,7 +499,6 @@ compiler-team = [
 ]
 compiler-team-contributors = [
     "@compiler-errors",
-    "@eholk",
     "@jackh726",
     "@TaKO8Ki",
     "@WaffleLapkin",