diff options
Diffstat (limited to 'compiler')
330 files changed, 4728 insertions, 2551 deletions
diff --git a/compiler/rustc_abi/src/callconv/reg.rs b/compiler/rustc_abi/src/callconv/reg.rs index 8cf140dbaad..66c8056d0c2 100644 --- a/compiler/rustc_abi/src/callconv/reg.rs +++ b/compiler/rustc_abi/src/callconv/reg.rs @@ -42,22 +42,22 @@ impl Reg { let dl = cx.data_layout(); match self.kind { RegKind::Integer => match self.size.bits() { - 1 => dl.i1_align.abi, - 2..=8 => dl.i8_align.abi, - 9..=16 => dl.i16_align.abi, - 17..=32 => dl.i32_align.abi, - 33..=64 => dl.i64_align.abi, - 65..=128 => dl.i128_align.abi, + 1 => dl.i1_align, + 2..=8 => dl.i8_align, + 9..=16 => dl.i16_align, + 17..=32 => dl.i32_align, + 33..=64 => dl.i64_align, + 65..=128 => dl.i128_align, _ => panic!("unsupported integer: {self:?}"), }, RegKind::Float => match self.size.bits() { - 16 => dl.f16_align.abi, - 32 => dl.f32_align.abi, - 64 => dl.f64_align.abi, - 128 => dl.f128_align.abi, + 16 => dl.f16_align, + 32 => dl.f32_align, + 64 => dl.f64_align, + 128 => dl.f128_align, _ => panic!("unsupported float: {self:?}"), }, - RegKind::Vector => dl.llvmlike_vector_align(self.size).abi, + RegKind::Vector => dl.llvmlike_vector_align(self.size), } } } diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 5004d0c8022..14356813b7b 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -174,11 +174,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // Non-power-of-two vectors have padding up to the next power-of-two. // If we're a packed repr, remove the padding while keeping the alignment as close // to a vector as possible. - (BackendRepr::Memory { sized: true }, AbiAlign { abi: Align::max_aligned_factor(size) }) + (BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size)) } else { (BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size)) }; - let size = size.align_to(align.abi); + let size = size.align_to(align); Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, @@ -190,7 +190,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { largest_niche: elt.largest_niche, uninhabited: false, size, - align, + align: AbiAlign::new(align), max_repr_align: None, unadjusted_abi_align: elt.align.abi, randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)), @@ -388,7 +388,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { return Err(LayoutCalculatorError::UnexpectedUnsized(*field)); } - align = align.max(field.align); + align = align.max(field.align.abi); max_repr_align = max_repr_align.max(field.max_repr_align); size = cmp::max(size, field.size); @@ -423,13 +423,13 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { } if let Some(pack) = repr.pack { - align = align.min(AbiAlign::new(pack)); + align = align.min(pack); } // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). // See documentation on `LayoutData::unadjusted_abi_align`. - let unadjusted_abi_align = align.abi; + let unadjusted_abi_align = align; if let Some(repr_align) = repr.align { - align = align.max(AbiAlign::new(repr_align)); + align = align.max(repr_align); } // `align` must not be modified after this, or `unadjusted_abi_align` could be inaccurate. let align = align; @@ -441,14 +441,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { Ok(Some((repr, _))) => match repr { // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt BackendRepr::Scalar(_) | BackendRepr::ScalarPair(_, _) - if repr.scalar_align(dl).unwrap() != align.abi => + if repr.scalar_align(dl).unwrap() != align => { BackendRepr::Memory { sized: true } } // Vectors require at least element alignment, else disable the opt - BackendRepr::SimdVector { element, count: _ } - if element.align(dl).abi > align.abi => - { + BackendRepr::SimdVector { element, count: _ } if element.align(dl).abi > align => { BackendRepr::Memory { sized: true } } // the alignment tests passed and we can use this @@ -474,8 +472,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { backend_repr, largest_niche: None, uninhabited: false, - align, - size: size.align_to(align.abi), + align: AbiAlign::new(align), + size: size.align_to(align), max_repr_align, unadjusted_abi_align, randomization_seed: combined_seed, @@ -611,7 +609,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let mut align = dl.aggregate_align; let mut max_repr_align = repr.align; - let mut unadjusted_abi_align = align.abi; + let mut unadjusted_abi_align = align; let mut variant_layouts = variants .iter_enumerated() @@ -619,7 +617,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let mut st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?; st.variants = Variants::Single { index: j }; - align = align.max(st.align); + align = align.max(st.align.abi); max_repr_align = max_repr_align.max(st.max_repr_align); unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); @@ -646,7 +644,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let (niche_start, niche_scalar) = niche.reserve(dl, count)?; let niche_offset = niche.offset; let niche_size = niche.value.size(dl); - let size = variant_layouts[largest_variant_index].size.align_to(align.abi); + let size = variant_layouts[largest_variant_index].size.align_to(align); let all_variants_fit = variant_layouts.iter_enumerated_mut().all(|(i, layout)| { if i == largest_variant_index { @@ -699,7 +697,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { .iter_enumerated() .all(|(i, layout)| i == largest_variant_index || layout.size == Size::ZERO); let same_size = size == variant_layouts[largest_variant_index].size; - let same_align = align == variant_layouts[largest_variant_index].align; + let same_align = align == variant_layouts[largest_variant_index].align.abi; let uninhabited = variant_layouts.iter().all(|v| v.is_uninhabited()); let abi = if same_size && same_align && others_zst { @@ -746,7 +744,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { largest_niche, uninhabited, size, - align, + align: AbiAlign::new(align), max_repr_align, unadjusted_abi_align, randomization_seed: combined_seed, @@ -818,7 +816,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let mut align = dl.aggregate_align; let mut max_repr_align = repr.align; - let mut unadjusted_abi_align = align.abi; + let mut unadjusted_abi_align = align; let mut size = Size::ZERO; @@ -860,7 +858,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { } } size = cmp::max(size, st.size); - align = align.max(st.align); + align = align.max(st.align.abi); max_repr_align = max_repr_align.max(st.max_repr_align); unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); Ok(st) @@ -868,7 +866,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; // Align the maximum variant size to the largest alignment. - size = size.align_to(align.abi); + size = size.align_to(align); // FIXME(oli-obk): deduplicate and harden these checks if size.bytes() >= dl.obj_size_bound() { @@ -1042,7 +1040,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { }; if pair_offsets[FieldIdx::new(0)] == Size::ZERO && pair_offsets[FieldIdx::new(1)] == *offset - && align == pair.align + && align == pair.align.abi && size == pair.size { // We can use `ScalarPair` only when it matches our @@ -1066,7 +1064,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // Also need to bump up the size and alignment, so that the entire value fits // in here. variant.size = cmp::max(variant.size, size); - variant.align.abi = cmp::max(variant.align.abi, align.abi); + variant.align.abi = cmp::max(variant.align.abi, align); } } } @@ -1092,7 +1090,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { largest_niche, uninhabited, backend_repr: abi, - align, + align: AbiAlign::new(align), size, max_repr_align, unadjusted_abi_align, @@ -1169,7 +1167,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // To allow unsizing `&Foo<Type>` -> `&Foo<dyn Trait>`, the layout of the struct must // not depend on the layout of the tail. let max_field_align = - fields_excluding_tail.iter().map(|f| f.align.abi.bytes()).max().unwrap_or(1); + fields_excluding_tail.iter().map(|f| f.align.bytes()).max().unwrap_or(1); let largest_niche_size = fields_excluding_tail .iter() .filter_map(|f| f.largest_niche) @@ -1189,7 +1187,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { } else { // Returns `log2(effective-align)`. The calculation assumes that size is an // integer multiple of align, except for ZSTs. - let align = layout.align.abi.bytes(); + let align = layout.align.bytes(); let size = layout.size.bytes(); let niche_size = layout.largest_niche.map(|n| n.available(dl)).unwrap_or(0); // Group [u8; 4] with align-4 or [u8; 6] with align-2 fields. @@ -1288,7 +1286,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { if let StructKind::Prefixed(prefix_size, prefix_align) = kind { let prefix_align = if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align }; - align = align.max(AbiAlign::new(prefix_align)); + align = align.max(prefix_align); offset = prefix_size.align_to(prefix_align); } for &i in &inverse_memory_index { @@ -1312,7 +1310,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { field.align }; offset = offset.align_to(field_align.abi); - align = align.max(field_align); + align = align.max(field_align.abi); max_repr_align = max_repr_align.max(field.max_repr_align); debug!("univariant offset: {:?} field: {:#?}", offset, field); @@ -1339,9 +1337,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). // See documentation on `LayoutData::unadjusted_abi_align`. - let unadjusted_abi_align = align.abi; + let unadjusted_abi_align = align; if let Some(repr_align) = repr.align { - align = align.max(AbiAlign::new(repr_align)); + align = align.max(repr_align); } // `align` must not be modified after this point, or `unadjusted_abi_align` could be inaccurate. let align = align; @@ -1360,7 +1358,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices())); inverse_memory_index.into_iter().map(|it| it.index() as u32).collect() }; - let size = min_size.align_to(align.abi); + let size = min_size.align_to(align); // FIXME(oli-obk): deduplicate and harden these checks if size.bytes() >= dl.obj_size_bound() { return Err(LayoutCalculatorError::SizeOverflow); @@ -1383,8 +1381,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { layout_of_single_non_zst_field = Some(field); // Field fills the struct and it has a scalar or scalar pair ABI. - if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size - { + if offsets[i].bytes() == 0 && align == field.align.abi && size == field.size { match field.backend_repr { // For plain scalars, or vectors of them, we can't unpack // newtypes for `#[repr(C)]`, as that affects C ABIs. @@ -1428,7 +1425,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { }; if offsets[i] == pair_offsets[FieldIdx::new(0)] && offsets[j] == pair_offsets[FieldIdx::new(1)] - && align == pair.align + && align == pair.align.abi && size == pair.size { // We can use `ScalarPair` only when it matches our @@ -1450,7 +1447,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { Some(l) => l.unadjusted_abi_align, None => { // `repr(transparent)` with all ZST fields. - align.abi + align } } } else { @@ -1465,7 +1462,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { backend_repr: abi, largest_niche, uninhabited, - align, + align: AbiAlign::new(align), size, max_repr_align, unadjusted_abi_align, @@ -1488,7 +1485,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { for i in layout.fields.index_by_increasing_offset() { let offset = layout.fields.offset(i); let f = &fields[FieldIdx::new(i)]; - write!(s, "[o{}a{}s{}", offset.bytes(), f.align.abi.bytes(), f.size.bytes()).unwrap(); + write!(s, "[o{}a{}s{}", offset.bytes(), f.align.bytes(), f.size.bytes()).unwrap(); if let Some(n) = f.largest_niche { write!( s, diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs index 0d0706defc2..b3807c87273 100644 --- a/compiler/rustc_abi/src/layout/simple.rs +++ b/compiler/rustc_abi/src/layout/simple.rs @@ -4,7 +4,8 @@ use rustc_hashes::Hash64; use rustc_index::{Idx, IndexVec}; use crate::{ - BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size, Variants, + AbiAlign, BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size, + Variants, }; /// "Simple" layout constructors that cannot fail. @@ -20,10 +21,10 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { backend_repr: BackendRepr::Memory { sized }, largest_niche: None, uninhabited: false, - align: dl.i8_align, + align: AbiAlign::new(dl.i8_align), size: Size::ZERO, max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, + unadjusted_abi_align: dl.i8_align, randomization_seed: Hash64::new(0), } } @@ -37,10 +38,10 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { backend_repr: BackendRepr::Memory { sized: true }, largest_niche: None, uninhabited: true, - align: dl.i8_align, + align: AbiAlign::new(dl.i8_align), size: Size::ZERO, max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, + unadjusted_abi_align: dl.i8_align, randomization_seed: Hash64::ZERO, } } @@ -89,10 +90,10 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { pub fn scalar_pair<C: HasDataLayout>(cx: &C, a: Scalar, b: Scalar) -> Self { let dl = cx.data_layout(); - let b_align = b.align(dl); - let align = a.align(dl).max(b_align).max(dl.aggregate_align); - let b_offset = a.size(dl).align_to(b_align.abi); - let size = (b_offset + b.size(dl)).align_to(align.abi); + let b_align = b.align(dl).abi; + let align = a.align(dl).abi.max(b_align).max(dl.aggregate_align); + let b_offset = a.size(dl).align_to(b_align); + let size = (b_offset + b.size(dl)).align_to(align); // HACK(nox): We iter on `b` and then `a` because `max_by_key` // returns the last maximum. @@ -112,10 +113,10 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { backend_repr: BackendRepr::ScalarPair(a, b), largest_niche, uninhabited: false, - align, + align: AbiAlign::new(align), size, max_repr_align: None, - unadjusted_abi_align: align.abi, + unadjusted_abi_align: align, randomization_seed: Hash64::new(combined_seed), } } @@ -138,10 +139,10 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { backend_repr: BackendRepr::Memory { sized: true }, largest_niche: None, uninhabited: true, - align: dl.i8_align, + align: AbiAlign::new(dl.i8_align), size: Size::ZERO, max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, + unadjusted_abi_align: dl.i8_align, randomization_seed: Hash64::ZERO, } } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 369874521e5..de44c8755a0 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -229,7 +229,7 @@ pub struct PointerSpec { /// The size of the bitwise representation of the pointer. pointer_size: Size, /// The alignment of pointers for this address space - pointer_align: AbiAlign, + pointer_align: Align, /// The size of the value a pointer can be offset by in this address space. pointer_offset: Size, /// Pointers into this address space contain extra metadata @@ -242,20 +242,20 @@ pub struct PointerSpec { #[derive(Debug, PartialEq, Eq)] pub struct TargetDataLayout { pub endian: Endian, - pub i1_align: AbiAlign, - pub i8_align: AbiAlign, - pub i16_align: AbiAlign, - pub i32_align: AbiAlign, - pub i64_align: AbiAlign, - pub i128_align: AbiAlign, - pub f16_align: AbiAlign, - pub f32_align: AbiAlign, - pub f64_align: AbiAlign, - pub f128_align: AbiAlign, - pub aggregate_align: AbiAlign, + pub i1_align: Align, + pub i8_align: Align, + pub i16_align: Align, + pub i32_align: Align, + pub i64_align: Align, + pub i128_align: Align, + pub f16_align: Align, + pub f32_align: Align, + pub f64_align: Align, + pub f128_align: Align, + pub aggregate_align: Align, /// Alignments for vector types. - pub vector_align: Vec<(Size, AbiAlign)>, + pub vector_align: Vec<(Size, Align)>, pub default_address_space: AddressSpace, pub default_address_space_pointer_spec: PointerSpec, @@ -282,25 +282,25 @@ impl Default for TargetDataLayout { let align = |bits| Align::from_bits(bits).unwrap(); TargetDataLayout { endian: Endian::Big, - i1_align: AbiAlign::new(align(8)), - i8_align: AbiAlign::new(align(8)), - i16_align: AbiAlign::new(align(16)), - i32_align: AbiAlign::new(align(32)), - i64_align: AbiAlign::new(align(32)), - i128_align: AbiAlign::new(align(32)), - f16_align: AbiAlign::new(align(16)), - f32_align: AbiAlign::new(align(32)), - f64_align: AbiAlign::new(align(64)), - f128_align: AbiAlign::new(align(128)), - aggregate_align: AbiAlign { abi: align(8) }, + i1_align: align(8), + i8_align: align(8), + i16_align: align(16), + i32_align: align(32), + i64_align: align(32), + i128_align: align(32), + f16_align: align(16), + f32_align: align(32), + f64_align: align(64), + f128_align: align(128), + aggregate_align: align(8), vector_align: vec![ - (Size::from_bits(64), AbiAlign::new(align(64))), - (Size::from_bits(128), AbiAlign::new(align(128))), + (Size::from_bits(64), align(64)), + (Size::from_bits(128), align(128)), ], default_address_space: AddressSpace::ZERO, default_address_space_pointer_spec: PointerSpec { pointer_size: Size::from_bits(64), - pointer_align: AbiAlign::new(align(64)), + pointer_align: align(64), pointer_offset: Size::from_bits(64), _is_fat: false, }, @@ -360,7 +360,7 @@ impl TargetDataLayout { .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err }) }; let abi = parse_bits(s, "alignment", cause)?; - Ok(AbiAlign::new(align_from_bits(abi)?)) + Ok(align_from_bits(abi)?) }; // Parse an alignment sequence, possibly in the form `<align>[:<preferred_alignment>]`, @@ -596,7 +596,7 @@ impl TargetDataLayout { /// psABI-mandated alignment for a vector type, if any #[inline] - fn cabi_vector_align(&self, vec_size: Size) -> Option<AbiAlign> { + fn cabi_vector_align(&self, vec_size: Size) -> Option<Align> { self.vector_align .iter() .find(|(size, _align)| *size == vec_size) @@ -605,10 +605,9 @@ impl TargetDataLayout { /// an alignment resembling the one LLVM would pick for a vector #[inline] - pub fn llvmlike_vector_align(&self, vec_size: Size) -> AbiAlign { - self.cabi_vector_align(vec_size).unwrap_or(AbiAlign::new( - Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap(), - )) + pub fn llvmlike_vector_align(&self, vec_size: Size) -> Align { + self.cabi_vector_align(vec_size) + .unwrap_or(Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap()) } /// Get the pointer size in the default data address space. @@ -654,21 +653,19 @@ impl TargetDataLayout { /// Get the pointer alignment in the default data address space. #[inline] pub fn pointer_align(&self) -> AbiAlign { - self.default_address_space_pointer_spec.pointer_align + AbiAlign::new(self.default_address_space_pointer_spec.pointer_align) } /// Get the pointer alignment in a specific address space. #[inline] pub fn pointer_align_in(&self, c: AddressSpace) -> AbiAlign { - if c == self.default_address_space { - return self.default_address_space_pointer_spec.pointer_align; - } - - if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) { + AbiAlign::new(if c == self.default_address_space { + self.default_address_space_pointer_spec.pointer_align + } else if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) { e.1.pointer_align } else { panic!("Use of unknown address space {c:?}"); - } + }) } } @@ -1185,13 +1182,13 @@ impl Integer { use Integer::*; let dl = cx.data_layout(); - match self { + AbiAlign::new(match self { I8 => dl.i8_align, I16 => dl.i16_align, I32 => dl.i32_align, I64 => dl.i64_align, I128 => dl.i128_align, - } + }) } /// Returns the largest signed value that can be represented by this Integer. @@ -1311,12 +1308,12 @@ impl Float { use Float::*; let dl = cx.data_layout(); - match self { + AbiAlign::new(match self { F16 => dl.f16_align, F32 => dl.f32_align, F64 => dl.f64_align, F128 => dl.f128_align, - } + }) } } @@ -2159,7 +2156,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1). pub fn is_1zst(&self) -> bool { - self.is_sized() && self.size.bytes() == 0 && self.align.abi.bytes() == 1 + self.is_sized() && self.size.bytes() == 0 && self.align.bytes() == 1 } /// Returns `true` if the type is a ZST and not unsized. diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3e8fddd9954..082d5e88ac7 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -114,8 +114,7 @@ impl PartialEq<Symbol> for Path { impl PartialEq<&[Symbol]> for Path { #[inline] fn eq(&self, names: &&[Symbol]) -> bool { - self.segments.len() == names.len() - && self.segments.iter().zip(names.iter()).all(|(s1, s2)| s1 == s2) + self.segments.iter().eq(*names) } } diff --git a/compiler/rustc_ast/src/expand/autodiff_attrs.rs b/compiler/rustc_ast/src/expand/autodiff_attrs.rs index 33451f99748..90f15753e99 100644 --- a/compiler/rustc_ast/src/expand/autodiff_attrs.rs +++ b/compiler/rustc_ast/src/expand/autodiff_attrs.rs @@ -6,6 +6,7 @@ use std::fmt::{self, Display, Formatter}; use std::str::FromStr; +use crate::expand::typetree::TypeTree; use crate::expand::{Decodable, Encodable, HashStable_Generic}; use crate::{Ty, TyKind}; @@ -84,6 +85,8 @@ pub struct AutoDiffItem { /// The name of the function being generated pub target: String, pub attrs: AutoDiffAttrs, + pub inputs: Vec<TypeTree>, + pub output: TypeTree, } #[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] @@ -275,14 +278,22 @@ impl AutoDiffAttrs { !matches!(self.mode, DiffMode::Error | DiffMode::Source) } - pub fn into_item(self, source: String, target: String) -> AutoDiffItem { - AutoDiffItem { source, target, attrs: self } + pub fn into_item( + self, + source: String, + target: String, + inputs: Vec<TypeTree>, + output: TypeTree, + ) -> AutoDiffItem { + AutoDiffItem { source, target, inputs, output, attrs: self } } } impl fmt::Display for AutoDiffItem { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Differentiating {} -> {}", self.source, self.target)?; - write!(f, " with attributes: {:?}", self.attrs) + write!(f, " with attributes: {:?}", self.attrs)?; + write!(f, " with inputs: {:?}", self.inputs)?; + write!(f, " with output: {:?}", self.output) } } diff --git a/compiler/rustc_ast/src/expand/typetree.rs b/compiler/rustc_ast/src/expand/typetree.rs index 9a2dd2e85e0..e7b4f3aff41 100644 --- a/compiler/rustc_ast/src/expand/typetree.rs +++ b/compiler/rustc_ast/src/expand/typetree.rs @@ -31,6 +31,7 @@ pub enum Kind { Half, Float, Double, + F128, Unknown, } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index f1951049b47..5fe218776e5 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -15,6 +15,7 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(if_let_guard)] +#![feature(iter_order_by)] #![feature(macro_metavar_expr)] #![feature(rustdoc_internals)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index a5d8fbfac61..4111182c3b7 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -48,9 +48,7 @@ impl TokenTree { match (self, other) { (TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind, (TokenTree::Delimited(.., delim, tts), TokenTree::Delimited(.., delim2, tts2)) => { - delim == delim2 - && tts.len() == tts2.len() - && tts.iter().zip(tts2.iter()).all(|(a, b)| a.eq_unspanned(b)) + delim == delim2 && tts.iter().eq_by(tts2.iter(), |a, b| a.eq_unspanned(b)) } _ => false, } diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index ec9d26eb33f..2871430030c 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -487,26 +487,6 @@ fn expand_format_args<'hir>( // Generate: // [] (vec![], ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(&[])))) - } else if argmap.len() == 1 && arguments.len() == 1 { - // Only one argument, so we don't need to make the `args` tuple. - // - // Generate: - // super let args = [<core::fmt::Argument>::new_display(&arg)]; - let args = ctx.arena.alloc_from_iter(argmap.iter().map( - |(&(arg_index, ty), &placeholder_span)| { - let arg = &arguments[arg_index]; - let placeholder_span = - placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt()); - let arg = ctx.lower_expr(&arg.expr); - let ref_arg = ctx.arena.alloc(ctx.expr_ref(arg.span.with_ctxt(macsp.ctxt()), arg)); - make_argument(ctx, placeholder_span, ref_arg, ty) - }, - )); - let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args))); - let args_ident = Ident::new(sym::args, macsp); - let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident); - let let_statement = ctx.stmt_super_let_pat(macsp, args_pat, Some(args)); - (vec![let_statement], ctx.arena.alloc(ctx.expr_ident_mut(macsp, args_ident, args_hir_id))) } else { // Generate: // super let args = (&arg0, &arg1, &…); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 9ab5b0b3547..608ccfefeb6 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -183,7 +183,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_doc!( "experimental" { cfg => doc_cfg - cfg_hide => doc_cfg_hide + auto_cfg => doc_cfg masked => doc_masked notable_trait => doc_notable_trait } diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 81ec17077c1..6c5346e8355 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -8,7 +8,15 @@ attr_parsing_deprecated_item_suggestion = attr_parsing_empty_attribute = unused attribute - .suggestion = remove this attribute + .suggestion = {$valid_without_list -> + [true] remove these parentheses + *[other] remove this attribute + } + .note = {$valid_without_list -> + [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all + *[other] using `{$attr_path}` with an empty list has no effect + } + attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target} .help = `#[{$name}]` can {$only}be applied to {$applied} diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 0a340cd5e93..20ec0fd0c7b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -1,40 +1,4 @@ -use std::num::IntErrorKind; - -use rustc_hir::limit::Limit; - use super::prelude::*; -use crate::session_diagnostics::LimitInvalid; - -impl<S: Stage> AcceptContext<'_, '_, S> { - fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> { - let Some(limit) = nv.value_as_str() else { - self.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; - - let error_str = match limit.as_str().parse() { - Ok(i) => return Some(Limit::new(i)), - Err(e) => match e.kind() { - IntErrorKind::PosOverflow => "`limit` is too large", - IntErrorKind::Empty => "`limit` must be a non-negative integer", - IntErrorKind::InvalidDigit => "not a valid integer", - IntErrorKind::NegOverflow => { - panic!( - "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead" - ) - } - IntErrorKind::Zero => { - panic!("zero is a valid `limit` so should have returned Ok() when parsing") - } - kind => panic!("unimplemented IntErrorKind variant: {:?}", kind), - }, - }; - - self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str }); - - None - } -} pub(crate) struct CrateNameParser; diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs new file mode 100644 index 00000000000..56ff10be426 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -0,0 +1,60 @@ +use rustc_hir::attrs::{DebugVisualizer, DebuggerVisualizerType}; + +use super::prelude::*; + +pub(crate) struct DebuggerViualizerParser; + +impl<S: Stage> CombineAttributeParser<S> for DebuggerViualizerParser { + const PATH: &[Symbol] = &[sym::debugger_visualizer]; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]); + const TEMPLATE: AttributeTemplate = template!( + List: &[r#"natvis_file = "...", gdb_script_file = "...""#], + "https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute" + ); + + type Item = DebugVisualizer; + const CONVERT: ConvertFn<Self::Item> = |v, _| AttributeKind::DebuggerVisualizer(v); + + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> + 'c { + let Some(l) = args.list() else { + cx.expected_list(args.span().unwrap_or(cx.attr_span)); + return None; + }; + let Some(single) = l.single() else { + cx.expected_single_argument(l.span); + return None; + }; + let Some(mi) = single.meta_item() else { + cx.expected_name_value(single.span(), None); + return None; + }; + let path = mi.path().word_sym(); + let visualizer_type = match path { + Some(sym::natvis_file) => DebuggerVisualizerType::Natvis, + Some(sym::gdb_script_file) => DebuggerVisualizerType::GdbPrettyPrinter, + _ => { + cx.expected_specific_argument( + mi.path().span(), + &[sym::natvis_file, sym::gdb_script_file], + ); + return None; + } + }; + + let Some(path) = mi.args().name_value() else { + cx.expected_name_value(single.span(), path); + return None; + }; + + let Some(path) = path.value_as_str() else { + cx.expected_string_literal(path.value_span, Some(path.value_as_lit())); + return None; + }; + + Some(DebugVisualizer { span: mi.span(), visualizer_type, path }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index a73430c9d00..a10ad27fcc6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -72,7 +72,11 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser { const PATH: &'static [Symbol] = &[sym::rustc_force_inline]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + ]); + const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason"); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 180130c7be4..849141c34f7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,3 +1,4 @@ +use rustc_ast::AttrStyle; use rustc_errors::DiagArgValue; use rustc_hir::attrs::MacroUseArgs; @@ -133,3 +134,65 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser { ]); const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span); } + +pub(crate) struct MacroExportParser; + +impl<S: Stage> SingleAttributeParser<S> for MacroExportParser { + const PATH: &[Symbol] = &[sym::macro_export]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word, List: &["local_inner_macros"]); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::MacroDef), + Error(Target::WherePredicate), + Error(Target::Crate), + ]); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let suggestions = || { + <Self as SingleAttributeParser<S>>::TEMPLATE + .suggestions(AttrStyle::Inner, "macro_export") + }; + let local_inner_macros = match args { + ArgParser::NoArgs => false, + ArgParser::List(list) => { + let Some(l) = list.single() else { + let span = cx.attr_span; + cx.emit_lint( + AttributeLintKind::InvalidMacroExportArguments { + suggestions: suggestions(), + }, + span, + ); + return None; + }; + match l.meta_item().and_then(|i| i.path().word_sym()) { + Some(sym::local_inner_macros) => true, + _ => { + let span = cx.attr_span; + cx.emit_lint( + AttributeLintKind::InvalidMacroExportArguments { + suggestions: suggestions(), + }, + span, + ); + return None; + } + } + } + ArgParser::NameValue(_) => { + let span = cx.attr_span; + let suggestions = suggestions(); + cx.emit_err(IllFormedAttributeInputLint { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + span, + }); + return None; + } + }; + Some(AttributeKind::MacroExport { span: cx.attr_span, local_inner_macros }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 4ed13d239b9..8dbf4c0ef32 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -36,6 +36,7 @@ pub(crate) mod cfg_old; pub(crate) mod codegen_attrs; pub(crate) mod confusables; pub(crate) mod crate_level; +pub(crate) mod debugger; pub(crate) mod deprecation; pub(crate) mod dummy; pub(crate) mod inline; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index a995549fc7c..cf2f5c6c790 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -49,3 +49,21 @@ impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser { Some(AttributeKind::RustcObjectLifetimeDefault) } } + +pub(crate) struct RustcSimdMonomorphizeLaneLimitParser; + +impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser { + const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let ArgParser::NameValue(nv) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?)) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 77e8c32e59d..62b72798e96 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -1,11 +1,15 @@ +use std::num::IntErrorKind; + use rustc_ast::LitKind; use rustc_ast::attr::AttributeExt; use rustc_feature::is_builtin_attr_name; use rustc_hir::RustcVersion; +use rustc_hir::limit::Limit; use rustc_span::{Symbol, sym}; use crate::context::{AcceptContext, Stage}; -use crate::parser::ArgParser; +use crate::parser::{ArgParser, NameValueParser}; +use crate::session_diagnostics::LimitInvalid; /// Parse a rustc version number written inside string literal in an attribute, /// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are @@ -85,3 +89,34 @@ pub(crate) fn parse_single_integer<S: Stage>( }; Some(num.0) } + +impl<S: Stage> AcceptContext<'_, '_, S> { + pub(crate) fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> { + let Some(limit) = nv.value_as_str() else { + self.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + + let error_str = match limit.as_str().parse() { + Ok(i) => return Some(Limit::new(i)), + Err(e) => match e.kind() { + IntErrorKind::PosOverflow => "`limit` is too large", + IntErrorKind::Empty => "`limit` must be a non-negative integer", + IntErrorKind::InvalidDigit => "not a valid integer", + IntErrorKind::NegOverflow => { + panic!( + "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead" + ) + } + IntErrorKind::Zero => { + panic!("zero is a valid `limit` so should have returned Ok() when parsing") + } + kind => panic!("unimplemented IntErrorKind variant: {:?}", kind), + }, + }; + + self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str }); + + None + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index ee5b7322b02..e8bb4caa416 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -28,6 +28,7 @@ use crate::attributes::crate_level::{ CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser, RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser, }; +use crate::attributes::debugger::DebuggerViualizerParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::dummy::DummyParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -40,7 +41,7 @@ use crate::attributes::lint_helpers::{ }; use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; use crate::attributes::macro_attrs::{ - AllowInternalUnsafeParser, MacroEscapeParser, MacroUseParser, + AllowInternalUnsafeParser, MacroEscapeParser, MacroExportParser, MacroUseParser, }; use crate::attributes::must_use::MustUseParser; use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser; @@ -53,7 +54,7 @@ use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_internal::{ RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart, - RustcObjectLifetimeDefaultParser, + RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ @@ -163,6 +164,7 @@ attribute_parsers!( // tidy-alphabetical-start Combine<AllowConstFnUnstableParser>, Combine<AllowInternalUnstableParser>, + Combine<DebuggerViualizerParser>, Combine<ForceTargetFeatureParser>, Combine<LinkParser>, Combine<ReprParser>, @@ -183,6 +185,7 @@ attribute_parsers!( Single<LinkOrdinalParser>, Single<LinkSectionParser>, Single<LinkageParser>, + Single<MacroExportParser>, Single<MoveSizeLimitParser>, Single<MustUseParser>, Single<ObjcClassParser>, @@ -197,6 +200,7 @@ attribute_parsers!( Single<RustcLayoutScalarValidRangeEnd>, Single<RustcLayoutScalarValidRangeStart>, Single<RustcObjectLifetimeDefaultParser>, + Single<RustcSimdMonomorphizeLaneLimitParser>, Single<SanitizeParser>, Single<ShouldPanicParser>, Single<SkipDuringMethodDispatchParser>, @@ -593,7 +597,12 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { } pub(crate) fn warn_empty_attribute(&mut self, span: Span) { - self.emit_lint(AttributeLintKind::EmptyAttribute { first_span: span }, span); + let attr_path = self.attr_path.clone(); + let valid_without_list = self.template.word; + self.emit_lint( + AttributeLintKind::EmptyAttribute { first_span: span, attr_path, valid_without_list }, + span, + ); } } diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index b1a971eec32..3a2a3704669 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -31,12 +31,30 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emi }, ); } - AttributeLintKind::EmptyAttribute { first_span } => lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - *id, - *first_span, - session_diagnostics::EmptyAttributeList { attr_span: *first_span }, - ), + AttributeLintKind::InvalidMacroExportArguments { suggestions } => lint_emitter + .emit_node_span_lint( + rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS, + *id, + *span, + session_diagnostics::IllFormedAttributeInput { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + }, + ), + AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { + lint_emitter.emit_node_span_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, + *id, + *first_span, + session_diagnostics::EmptyAttributeList { + attr_span: *first_span, + attr_path: attr_path.clone(), + valid_without_list: *valid_without_list, + }, + ) + } AttributeLintKind::InvalidTarget { name, target, applied, only } => lint_emitter .emit_node_span_lint( // This check is here because `deprecated` had its own lint group and removing this would be a breaking change diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 4f903594225..3f4f5679015 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -49,7 +49,7 @@ impl<'a> PathParser<'a> { } pub fn segments_is(&self, segments: &[Symbol]) -> bool { - self.len() == segments.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b) + self.segments().map(|segment| &segment.name).eq(segments) } pub fn word(&self) -> Option<Ident> { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 2c2b14c8a68..1194ac5872c 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -503,9 +503,12 @@ pub(crate) struct EmptyConfusables { #[derive(LintDiagnostic)] #[diag(attr_parsing_empty_attribute)] +#[note] pub(crate) struct EmptyAttributeList { #[suggestion(code = "", applicability = "machine-applicable")] pub attr_span: Span, + pub attr_path: AttrPath, + pub valid_without_list: bool, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 7a7624893bd..927417f89f8 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -207,10 +207,9 @@ pub fn check_attribute_safety( } } - // - Normal builtin attribute, or any non-builtin attribute - // - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is - // not permitted on non-builtin attributes or normal builtin attributes - (Some(AttributeSafety::Normal) | None, Safety::Unsafe(unsafe_span)) => { + // - Normal builtin attribute + // - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes + (Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => { psess.dcx().emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: attr_item.path.clone(), @@ -224,9 +223,8 @@ pub fn check_attribute_safety( } // - Non-builtin attribute - // - No explicit `#[unsafe(..)]` written. - (None, Safety::Default) => { - // OK + (None, Safety::Unsafe(_) | Safety::Default) => { + // OK (not checked here) } ( diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index c9be5575da5..7c9011505d6 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -426,7 +426,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> { } pub(crate) fn path_does_not_live_long_enough(&self, span: Span, path: &str) -> Diag<'infcx> { - struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path,) + struct_span_code_err!(self.dcx(), span, E0597, "{} does not live long enough", path) } pub(crate) fn cannot_return_reference_to_local( @@ -480,7 +480,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> { } pub(crate) fn temporary_value_borrowed_for_too_long(&self, span: Span) -> Diag<'infcx> { - struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",) + struct_span_code_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed") } } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7e20a5133e0..fa1be4cec1e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2992,6 +2992,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.buffer_error(err); } + #[tracing::instrument(level = "debug", skip(self, explanation))] fn report_local_value_does_not_live_long_enough( &self, location: Location, @@ -3001,13 +3002,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { borrow_spans: UseSpans<'tcx>, explanation: BorrowExplanation<'tcx>, ) -> Diag<'infcx> { - debug!( - "report_local_value_does_not_live_long_enough(\ - {:?}, {:?}, {:?}, {:?}, {:?}\ - )", - location, name, borrow, drop_span, borrow_spans - ); - let borrow_span = borrow_spans.var_or_use_path_span(); if let BorrowExplanation::MustBeValidFor { category, @@ -3974,7 +3968,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } - | ProjectionElem::Subtype(_) | ProjectionElem::Index(_) | ProjectionElem::UnwrapUnsafeBinder(_) => kind, }, diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 7ca07bb9b43..638d89f5bcb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -416,6 +416,26 @@ impl<'tcx> BorrowExplanation<'tcx> { { self.add_object_lifetime_default_note(tcx, err, unsize_ty); } + + let mut preds = path + .iter() + .filter_map(|constraint| match constraint.category { + ConstraintCategory::Predicate(pred) if !pred.is_dummy() => Some(pred), + _ => None, + }) + .collect::<Vec<Span>>(); + preds.sort(); + preds.dedup(); + if !preds.is_empty() { + let s = if preds.len() == 1 { "" } else { "s" }; + err.span_note( + preds, + format!( + "requirement{s} that the value outlives `{region_name}` introduced here" + ), + ); + } + self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name); } _ => {} diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 5642cdf87fd..e13c1c712d8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -402,7 +402,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ProjectionElem::Downcast(..) if opt.including_downcast => return None, ProjectionElem::Downcast(..) => (), ProjectionElem::OpaqueCast(..) => (), - ProjectionElem::Subtype(..) => (), ProjectionElem::UnwrapUnsafeBinder(_) => (), ProjectionElem::Field(field, _ty) => { // FIXME(project-rfc_2229#36): print capture precisely here. @@ -484,9 +483,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) } ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx), - ProjectionElem::Subtype(ty) - | ProjectionElem::OpaqueCast(ty) - | ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty), + ProjectionElem::OpaqueCast(ty) | ProjectionElem::UnwrapUnsafeBinder(ty) => { + PlaceTy::from_ty(*ty) + } ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), }, }; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 6d69040c711..727cf19cd8b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -192,7 +192,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { [ .., ProjectionElem::Index(_) - | ProjectionElem::Subtype(_) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4c380ddcf70..a85dcf64d8d 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -119,7 +119,7 @@ pub fn provide(providers: &mut Providers) { fn mir_borrowck( tcx: TyCtxt<'_>, def: LocalDefId, -) -> Result<&ConcreteOpaqueTypes<'_>, ErrorGuaranteed> { +) -> Result<&DefinitionSiteHiddenTypes<'_>, ErrorGuaranteed> { assert!(!tcx.is_typeck_child(def.to_def_id())); let (input_body, _) = tcx.mir_promoted(def); debug!("run query mir_borrowck: {}", tcx.def_path_str(def)); @@ -130,7 +130,7 @@ fn mir_borrowck( Err(guar) } else if input_body.should_skip() { debug!("Skipping borrowck because of injected body"); - let opaque_types = ConcreteOpaqueTypes(Default::default()); + let opaque_types = DefinitionSiteHiddenTypes(Default::default()); Ok(tcx.arena.alloc(opaque_types)) } else { let mut root_cx = BorrowCheckRootCtxt::new(tcx, def, None); @@ -278,7 +278,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>, ) -> Ty<'tcx> { fold_regions(tcx, self.inner, |r, depth| match r.kind() { - ty::ReBound(debruijn, br) => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) => { debug_assert_eq!(debruijn, depth); map(ty::RegionVid::from_usize(br.var.index())) } @@ -1989,10 +1989,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { }, // `OpaqueCast`: only transmutes the type, so no moves there. // `Downcast` : only changes information about a `Place` without moving. - // `Subtype` : only transmutes the type, so no moves. // So it's safe to skip these. ProjectionElem::OpaqueCast(_) - | ProjectionElem::Subtype(_) | ProjectionElem::Downcast(_, _) | ProjectionElem::UnwrapUnsafeBinder(_) => (), } @@ -2218,7 +2216,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { for (place_base, elem) in place.iter_projections().rev() { match elem { ProjectionElem::Index(_/*operand*/) | - ProjectionElem::Subtype(_) | ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } | // assigning to P[i] requires P to be valid. @@ -2610,7 +2607,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } - | ProjectionElem::Subtype(..) | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Downcast(..) | ProjectionElem::UnwrapUnsafeBinder(_) => { diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index cf3e82426e8..60676ac6b86 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -249,7 +249,6 @@ fn place_components_conflict<'tcx>( | (ProjectionElem::ConstantIndex { .. }, _, _) | (ProjectionElem::Subslice { .. }, _, _) | (ProjectionElem::OpaqueCast { .. }, _, _) - | (ProjectionElem::Subtype(_), _, _) | (ProjectionElem::Downcast { .. }, _, _) | (ProjectionElem::UnwrapUnsafeBinder(_), _, _) => { // Recursive case. This can still be disjoint on a @@ -510,7 +509,6 @@ fn place_projection_conflict<'tcx>( | ProjectionElem::Field(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subtype(_) | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..), diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index 83cca38a5c0..9e51264d8ed 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -77,9 +77,6 @@ impl<'tcx> Iterator for Prefixes<'tcx> { | ProjectionElem::Index(_) => { cursor = cursor_base; } - ProjectionElem::Subtype(..) => { - panic!("Subtype projection is not allowed before borrow check") - } ProjectionElem::Deref => { match self.kind { PrefixSet::Shallow => { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 5f4bfd9df48..e98c60e6338 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1382,10 +1382,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// The constraints we get from equating the hidden type of each use of an opaque - /// with its final concrete type may end up getting preferred over other, potentially + /// with its final hidden type may end up getting preferred over other, potentially /// longer constraint paths. /// - /// Given that we compute the final concrete type by relying on this existing constraint + /// Given that we compute the final hidden type by relying on this existing constraint /// path, this can easily end up hiding the actual reason for why we require these regions /// to be equal. /// @@ -1736,9 +1736,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { // `BoringNoLocation` constraints can point to user-written code, but are less // specific, and are not used for relations that would make sense to blame. ConstraintCategory::BoringNoLocation => 6, - // Do not blame internal constraints. - ConstraintCategory::OutlivesUnnameablePlaceholder(_) => 7, - ConstraintCategory::Internal => 8, + // Do not blame internal constraints if we can avoid it. Never blame + // the `'region: 'static` constraints introduced by placeholder outlives. + ConstraintCategory::Internal => 7, + ConstraintCategory::OutlivesUnnameablePlaceholder(_) => 8, }; debug!("constraint {constraint:?} category: {category:?}, interest: {interest:?}"); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index 0af636aa734..8d89f3e0d87 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -8,7 +8,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, OpaqueTypeStorageEntries}; use rustc_infer::traits::ObligationCause; use rustc_macros::extension; -use rustc_middle::mir::{Body, ConcreteOpaqueTypes, ConstraintCategory}; +use rustc_middle::mir::{Body, ConstraintCategory, DefinitionSiteHiddenTypes}; use rustc_middle::ty::{ self, DefiningScopeKind, EarlyBinder, FallibleTypeFolder, GenericArg, GenericArgsRef, OpaqueHiddenType, OpaqueTypeKey, Region, RegionVid, Ty, TyCtxt, TypeFoldable, @@ -129,9 +129,9 @@ fn nll_var_to_universal_region<'tcx>( /// Collect all defining uses of opaque types inside of this typeck root. This /// expects the hidden type to be mapped to the definition parameters of the opaque /// and errors if we end up with distinct hidden types. -fn add_concrete_opaque_type<'tcx>( +fn add_hidden_type<'tcx>( tcx: TyCtxt<'tcx>, - concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>, def_id: LocalDefId, hidden_ty: OpaqueHiddenType<'tcx>, ) { @@ -139,7 +139,7 @@ fn add_concrete_opaque_type<'tcx>( // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to // `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we // only know that once we convert the generic parameters to those of the opaque type. - if let Some(prev) = concrete_opaque_types.0.get_mut(&def_id) { + if let Some(prev) = hidden_types.0.get_mut(&def_id) { if prev.ty != hidden_ty.ty { let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| { let (Ok(e) | Err(e)) = prev.build_mismatch_error(&hidden_ty, tcx).map(|d| d.emit()); @@ -151,15 +151,15 @@ fn add_concrete_opaque_type<'tcx>( // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. prev.span = prev.span.substitute_dummy(hidden_ty.span); } else { - concrete_opaque_types.0.insert(def_id, hidden_ty); + hidden_types.0.insert(def_id, hidden_ty); } } -fn get_concrete_opaque_type<'tcx>( - concrete_opaque_types: &ConcreteOpaqueTypes<'tcx>, +fn get_hidden_type<'tcx>( + hidden_types: &DefinitionSiteHiddenTypes<'tcx>, def_id: LocalDefId, ) -> Option<EarlyBinder<'tcx, OpaqueHiddenType<'tcx>>> { - concrete_opaque_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty)) + hidden_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty)) } #[derive(Debug)] @@ -173,22 +173,22 @@ struct DefiningUse<'tcx> { } /// This computes the actual hidden types of the opaque types and maps them to their -/// definition sites. Outside of registering the computed concrete types this function +/// definition sites. Outside of registering the computed hidden types this function /// does not mutate the current borrowck state. /// /// While it may fail to infer the hidden type and return errors, we always apply -/// the computed concrete hidden type to all opaque type uses to check whether they +/// the computed hidden type to all opaque type uses to check whether they /// are correct. This is necessary to support non-defining uses of opaques in their /// defining scope. /// /// It also means that this whole function is not really soundness critical as we /// recheck all uses of the opaques regardless. -pub(crate) fn compute_concrete_opaque_types<'tcx>( +pub(crate) fn compute_definition_site_hidden_types<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>, constraints: &MirTypeckRegionConstraints<'tcx>, location_map: Rc<DenseLocationMap>, - concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) -> Vec<DeferredOpaqueTypeError<'tcx>> { let mut errors = Vec::new(); @@ -201,8 +201,7 @@ pub(crate) fn compute_concrete_opaque_types<'tcx>( // We start by checking each use of an opaque type during type check and // check whether the generic arguments of the opaque type are fully // universal, if so, it's a defining use. - let defining_uses = - collect_defining_uses(&mut rcx, concrete_opaque_types, opaque_types, &mut errors); + let defining_uses = collect_defining_uses(&mut rcx, hidden_types, opaque_types, &mut errors); // We now compute and apply member constraints for all regions in the hidden // types of each defining use. This mutates the region values of the `rcx` which @@ -210,11 +209,11 @@ pub(crate) fn compute_concrete_opaque_types<'tcx>( apply_member_constraints(&mut rcx, &defining_uses); // After applying member constraints, we now check whether all member regions ended - // up equal to one of their choice regions and compute the actual concrete type of + // up equal to one of their choice regions and compute the actual hidden type of // the opaque type definition. This is stored in the `root_cx`. - compute_concrete_types_from_defining_uses( + compute_definition_site_hidden_types_from_defining_uses( &rcx, - concrete_opaque_types, + hidden_types, &defining_uses, &mut errors, ); @@ -224,7 +223,7 @@ pub(crate) fn compute_concrete_opaque_types<'tcx>( #[instrument(level = "debug", skip_all, ret)] fn collect_defining_uses<'tcx>( rcx: &mut RegionCtxt<'_, 'tcx>, - concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>, ) -> Vec<DefiningUse<'tcx>> { @@ -244,9 +243,9 @@ fn collect_defining_uses<'tcx>( // with `TypingMode::Borrowck`. if infcx.tcx.use_typing_mode_borrowck() { match err { - NonDefiningUseReason::Tainted(guar) => add_concrete_opaque_type( + NonDefiningUseReason::Tainted(guar) => add_hidden_type( infcx.tcx, - concrete_opaque_types, + hidden_types, opaque_type_key.def_id, OpaqueHiddenType::new_error(infcx.tcx, guar), ), @@ -277,9 +276,9 @@ fn collect_defining_uses<'tcx>( defining_uses } -fn compute_concrete_types_from_defining_uses<'tcx>( +fn compute_definition_site_hidden_types_from_defining_uses<'tcx>( rcx: &RegionCtxt<'_, 'tcx>, - concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>, defining_uses: &[DefiningUse<'tcx>], errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>, ) { @@ -358,9 +357,9 @@ fn compute_concrete_types_from_defining_uses<'tcx>( }, )); } - add_concrete_opaque_type( + add_hidden_type( tcx, - concrete_opaque_types, + hidden_types, opaque_type_key.def_id, OpaqueHiddenType { span: hidden_type.span, ty }, ); @@ -489,20 +488,20 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ToArgRegionsFolder<'_, 'tcx> { /// /// It does this by equating the hidden type of each use with the instantiated final /// hidden type of the opaque. -pub(crate) fn apply_computed_concrete_opaque_types<'tcx>( +pub(crate) fn apply_definition_site_hidden_types<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, universal_regions: &UniversalRegions<'tcx>, region_bound_pairs: &RegionBoundPairs<'tcx>, known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>], constraints: &mut MirTypeckRegionConstraints<'tcx>, - concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>, + hidden_types: &mut DefinitionSiteHiddenTypes<'tcx>, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) -> Vec<DeferredOpaqueTypeError<'tcx>> { let tcx = infcx.tcx; let mut errors = Vec::new(); for &(key, hidden_type) in opaque_types { - let Some(expected) = get_concrete_opaque_type(concrete_opaque_types, key.def_id) else { + let Some(expected) = get_hidden_type(hidden_types, key.def_id) else { if !tcx.use_typing_mode_borrowck() { if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind() && alias_ty.def_id == key.def_id.to_def_id() @@ -521,12 +520,7 @@ pub(crate) fn apply_computed_concrete_opaque_types<'tcx>( hidden_type.span, "non-defining use in the defining scope with no defining uses", ); - add_concrete_opaque_type( - tcx, - concrete_opaque_types, - key.def_id, - OpaqueHiddenType::new_error(tcx, guar), - ); + add_hidden_type(tcx, hidden_types, key.def_id, OpaqueHiddenType::new_error(tcx, guar)); continue; }; @@ -566,18 +560,13 @@ pub(crate) fn apply_computed_concrete_opaque_types<'tcx>( "equating opaque types", ), ) { - add_concrete_opaque_type( - tcx, - concrete_opaque_types, - key.def_id, - OpaqueHiddenType::new_error(tcx, guar), - ); + add_hidden_type(tcx, hidden_types, key.def_id, OpaqueHiddenType::new_error(tcx, guar)); } } errors } -/// In theory `apply_concrete_opaque_types` could introduce new uses of opaque types. +/// In theory `apply_definition_site_hidden_types` could introduce new uses of opaque types. /// We do not check these new uses so this could be unsound. /// /// We detect any new uses and simply delay a bug if they occur. If this results in @@ -682,13 +671,6 @@ impl<'tcx> InferCtxt<'tcx> { /// /// (*) C1 and C2 were introduced in the comments on /// `register_member_constraints`. Read that comment for more context. - /// - /// # Parameters - /// - /// - `def_id`, the `impl Trait` type - /// - `args`, the args used to instantiate this opaque type - /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of - /// `opaque_defn.concrete_ty` #[instrument(level = "debug", skip(self))] fn infer_opaque_definition_from_instantiation( &self, diff --git a/compiler/rustc_borrowck/src/root_cx.rs b/compiler/rustc_borrowck/src/root_cx.rs index cd4e9683f2d..21c11e12873 100644 --- a/compiler/rustc_borrowck/src/root_cx.rs +++ b/compiler/rustc_borrowck/src/root_cx.rs @@ -12,12 +12,12 @@ use smallvec::SmallVec; use crate::consumers::BorrowckConsumer; use crate::nll::compute_closure_requirements_modulo_opaques; use crate::region_infer::opaque_types::{ - apply_computed_concrete_opaque_types, clone_and_resolve_opaque_types, - compute_concrete_opaque_types, detect_opaque_types_added_while_handling_opaque_types, + apply_definition_site_hidden_types, clone_and_resolve_opaque_types, + compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types, }; use crate::type_check::{Locations, constraint_conversion}; use crate::{ - ClosureRegionRequirements, CollectRegionConstraintsResult, ConcreteOpaqueTypes, + ClosureRegionRequirements, CollectRegionConstraintsResult, DefinitionSiteHiddenTypes, PropagatedBorrowCheckResults, borrowck_check_region_constraints, borrowck_collect_region_constraints, }; @@ -27,7 +27,7 @@ use crate::{ pub(super) struct BorrowCheckRootCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, root_def_id: LocalDefId, - concrete_opaque_types: ConcreteOpaqueTypes<'tcx>, + hidden_types: DefinitionSiteHiddenTypes<'tcx>, /// The region constraints computed by [borrowck_collect_region_constraints]. This uses /// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before /// their parents. @@ -49,7 +49,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { BorrowCheckRootCtxt { tcx, root_def_id, - concrete_opaque_types: Default::default(), + hidden_types: Default::default(), collect_region_constraints_results: Default::default(), propagated_borrowck_results: Default::default(), tainted_by_errors: None, @@ -72,11 +72,11 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { &self.propagated_borrowck_results[&nested_body_def_id].used_mut_upvars } - pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> { + pub(super) fn finalize(self) -> Result<&'tcx DefinitionSiteHiddenTypes<'tcx>, ErrorGuaranteed> { if let Some(guar) = self.tainted_by_errors { Err(guar) } else { - Ok(self.tcx.arena.alloc(self.concrete_opaque_types)) + Ok(self.tcx.arena.alloc(self.hidden_types)) } } @@ -88,12 +88,12 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { &input.universal_region_relations, &mut input.constraints, ); - input.deferred_opaque_type_errors = compute_concrete_opaque_types( + input.deferred_opaque_type_errors = compute_definition_site_hidden_types( &input.infcx, &input.universal_region_relations, &input.constraints, Rc::clone(&input.location_map), - &mut self.concrete_opaque_types, + &mut self.hidden_types, &opaque_types, ); per_body_info.push((num_entries, opaque_types)); @@ -103,14 +103,14 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { self.collect_region_constraints_results.values_mut().zip(per_body_info) { if input.deferred_opaque_type_errors.is_empty() { - input.deferred_opaque_type_errors = apply_computed_concrete_opaque_types( + input.deferred_opaque_type_errors = apply_definition_site_hidden_types( &input.infcx, &input.body_owned, &input.universal_region_relations.universal_regions, &input.region_bound_pairs, &input.known_type_outlives_obligations, &mut input.constraints, - &mut self.concrete_opaque_types, + &mut self.hidden_types, &opaque_types, ); } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 19cbcd139aa..781fb5ba113 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -505,6 +505,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let mut constraints = Default::default(); let mut liveness_constraints = LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body))); + let mut deferred_closure_requirements = Default::default(); // Don't try to add borrow_region facts for the promoted MIR as they refer // to the wrong locations. @@ -512,6 +513,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { mem::swap(this.polonius_facts, polonius_facts); mem::swap(&mut this.constraints.outlives_constraints, &mut constraints); mem::swap(&mut this.constraints.liveness_constraints, &mut liveness_constraints); + mem::swap(this.deferred_closure_requirements, &mut deferred_closure_requirements); }; swap_constraints(self); @@ -536,6 +538,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.constraints.outlives_constraints.push(constraint) } + + // If there are nested bodies in promoteds, we also need to update their + // location to something in the actual body, not the promoted. + // + // We don't update the constraint categories of the resulting constraints + // as returns in nested bodies are a proper return, even if that nested body + // is in a promoted. + for (closure_def_id, args, _locations) in deferred_closure_requirements { + self.deferred_closure_requirements.push((closure_def_id, args, locations)); + } + // If the region is live at least one location in the promoted MIR, // then add a liveness constraint to the main MIR for this region // at the location provided as an argument to this method @@ -1545,6 +1558,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ), } } + CastKind::Subtype => { + bug!("CastKind::Subtype shouldn't exist in borrowck") + } } } @@ -1869,9 +1885,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ) .unwrap(); } - ProjectionElem::Subtype(_) => { - bug!("ProjectionElem::Subtype shouldn't exist in borrowck") - } } } } @@ -2399,9 +2412,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | ProjectionElem::UnwrapUnsafeBinder(_) => { // other field access } - ProjectionElem::Subtype(_) => { - bug!("ProjectionElem::Subtype shouldn't exist in borrowck") - } } } } diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index f4a923797e2..ddc59bfe141 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -377,8 +377,7 @@ mod llvm_enzyme { (ast::AttrKind::Normal(a), ast::AttrKind::Normal(b)) => { let a = &a.item.path; let b = &b.item.path; - a.segments.len() == b.segments.len() - && a.segments.iter().zip(b.segments.iter()).all(|(a, b)| a.ident == b.ident) + a.segments.iter().eq_by(&b.segments, |a, b| a.ident == b.ident) } _ => false, } diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 75db5d77783..5b378de8bbd 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -356,21 +356,14 @@ fn contains_maybe_sized_bound(bounds: &[GenericBound]) -> bool { bounds.iter().any(is_maybe_sized_bound) } -fn path_segment_is_exact_match(path_segments: &[ast::PathSegment], syms: &[Symbol]) -> bool { - path_segments.iter().zip(syms).all(|(segment, &symbol)| segment.ident.name == symbol) -} - fn is_sized_marker(path: &ast::Path) -> bool { const CORE_UNSIZE: [Symbol; 3] = [sym::core, sym::marker, sym::Sized]; const STD_UNSIZE: [Symbol; 3] = [sym::std, sym::marker, sym::Sized]; - if path.segments.len() == 4 && path.is_global() { - path_segment_is_exact_match(&path.segments[1..], &CORE_UNSIZE) - || path_segment_is_exact_match(&path.segments[1..], &STD_UNSIZE) - } else if path.segments.len() == 3 { - path_segment_is_exact_match(&path.segments, &CORE_UNSIZE) - || path_segment_is_exact_match(&path.segments, &STD_UNSIZE) + let segments = || path.segments.iter().map(|segment| segment.ident.name); + if path.is_global() { + segments().skip(1).eq(CORE_UNSIZE) || segments().skip(1).eq(STD_UNSIZE) } else { - *path == sym::Sized + segments().eq(CORE_UNSIZE) || segments().eq(STD_UNSIZE) || *path == sym::Sized } } diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index d70888205a5..bffc0407e81 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -768,7 +768,7 @@ fn report_missing_placeholders( if !found_foreign && invalid_refs.is_empty() { // Show example if user didn't use any format specifiers - let show_example = used.iter().all(|used| !used); + let show_example = !used.contains(&true); if !show_example { if unused.len() > 1 { diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index f14b1920722..96bece2a368 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -85,7 +85,7 @@ impl AllocFnFactory<'_, '_> { body, define_opaque: None, })); - let item = self.cx.item(self.span, self.attrs(), kind); + let item = self.cx.item(self.span, self.attrs(method), kind); self.cx.stmt_item(self.ty_span, item) } @@ -100,8 +100,18 @@ impl AllocFnFactory<'_, '_> { self.cx.expr_call(self.ty_span, method, args) } - fn attrs(&self) -> AttrVec { - thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)] + fn attrs(&self, method: &AllocatorMethod) -> AttrVec { + let alloc_attr = match method.name { + sym::alloc => sym::rustc_allocator, + sym::dealloc => sym::rustc_deallocator, + sym::realloc => sym::rustc_reallocator, + sym::alloc_zeroed => sym::rustc_allocator_zeroed, + _ => unreachable!("Unknown allocator method!"), + }; + thin_vec![ + self.cx.attr_word(sym::rustc_std_internal_symbol, self.span), + self.cx.attr_word(alloc_attr, self.span) + ] } fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec<Param>) -> Box<Expr> { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 4541e2cd3b4..57cf62ea612 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -11,6 +11,7 @@ #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] +#![feature(iter_order_by)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 51089e5a1d3..82c59d5a3a2 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -63,8 +63,8 @@ pub fn inject( 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) => { + (PanicStrategy::Abort | PanicStrategy::ImmediateAbort, true) => panic_strategy, + (PanicStrategy::Abort | PanicStrategy::ImmediateAbort, false) => { if panic_strategy == platform_panic_strategy { // Silently allow compiling with panic=abort on these platforms, // but with old behavior (abort if a test fails). @@ -287,10 +287,8 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box<ast::Item> { let ecx = &cx.ext_cx; let test_ident = Ident::new(sym::test, sp); - let runner_name = match cx.panic_strategy { - PanicStrategy::Unwind => "test_main_static", - PanicStrategy::Abort => "test_main_static_abort", - }; + let runner_name = + if cx.panic_strategy.unwinds() { "test_main_static" } else { "test_main_static_abort" }; // test::test_main_static(...) let mut test_runner = cx.test_runner.clone().unwrap_or_else(|| { diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index c74efeb59f3..d1b2b9a502a 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -89,7 +89,7 @@ pub(super) fn add_local_place_comments<'tcx>( format!("{:?}", local), format!("{:?}", ty), size.bytes(), - align.abi.bytes(), + align.bytes(), if extra.is_empty() { "" } else { " " }, extra, )); diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 2031842062d..7a909a740b0 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -233,7 +233,7 @@ pub(super) fn from_casted_value<'tcx>( // It may also be smaller for example when the type is a wrapper around an integer with a // larger alignment than the integer. std::cmp::max(abi_param_size, layout_size), - u32::try_from(layout.align.abi.bytes()).unwrap(), + u32::try_from(layout.align.bytes()).unwrap(), ); let mut block_params_iter = block_params.iter().copied(); for (offset, _) in abi_params { diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 41e11e1de61..ebf2ccf74de 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -789,7 +789,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: let operand = codegen_operand(fx, operand); crate::unsize::coerce_unsized_into(fx, operand, lval); } - Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => { + Rvalue::Cast(CastKind::Transmute | CastKind::Subtype, ref operand, _to_ty) => { let operand = codegen_operand(fx, operand); lval.write_cvalue_transmute(fx, operand); } @@ -846,7 +846,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: let layout = fx.layout_of(fx.monomorphize(ty)); let val = match null_op { NullOp::SizeOf => layout.size.bytes(), - NullOp::AlignOf => layout.align.abi.bytes(), + NullOp::AlignOf => layout.align.bytes(), NullOp::OffsetOf(fields) => fx .tcx .offset_of_subfield( @@ -996,7 +996,7 @@ pub(crate) fn codegen_place<'tcx>( cplace = cplace.place_deref(fx); } PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"), - PlaceElem::Subtype(ty) | PlaceElem::UnwrapUnsafeBinder(ty) => { + PlaceElem::UnwrapUnsafeBinder(ty) => { cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)); } PlaceElem::Field(field, _ty) => { diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 2fbe5c02802..81b1814605a 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -439,7 +439,10 @@ pub(crate) struct FullyMonomorphizedLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>); impl<'tcx> LayoutOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { + if let LayoutError::SizeOverflow(_) + | LayoutError::InvalidSimd { .. } + | LayoutError::ReferencesError(_) = err + { self.0.sess.dcx().span_fatal(span, err.to_string()) } else { self.0 @@ -458,7 +461,9 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> { span: Span, fn_abi_request: FnAbiRequest<'tcx>, ) -> ! { - if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { + if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) = + err + { self.0.sess.dcx().emit_fatal(Spanned { span, node: err }) } else { match fn_abi_request { diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 286e02b986b..4c438742f3d 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -304,7 +304,7 @@ impl DebugContext { entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line)); - entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.abi.bytes())); + entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.bytes())); let mut expr = Expression::new(); expr.op_addr(address_for_data(data_id)); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs index 25b922c8be4..0d49f32373c 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs @@ -166,7 +166,7 @@ impl DebugContext { let tuple_entry = self.dwarf.unit.get_mut(tuple_type_id); tuple_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(self.dwarf.strings.add(name))); tuple_entry.set(gimli::DW_AT_byte_size, AttributeValue::Udata(layout.size.bytes())); - tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.abi.bytes())); + tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.bytes())); for (i, (ty, dw_ty)) in components.into_iter().enumerate() { let member_id = self.dwarf.unit.add(tuple_type_id, gimli::DW_TAG_member); @@ -178,9 +178,7 @@ impl DebugContext { member_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(dw_ty)); member_entry.set( gimli::DW_AT_alignment, - AttributeValue::Udata( - FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.abi.bytes(), - ), + AttributeValue::Udata(FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.bytes()), ); member_entry.set( gimli::DW_AT_data_member_location, diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 203b443269f..1306c6aa517 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -42,7 +42,10 @@ impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> { impl<'tcx> LayoutOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { + if let LayoutError::SizeOverflow(_) + | LayoutError::InvalidSimd { .. } + | LayoutError::ReferencesError(_) = err + { self.tcx.sess.dcx().span_fatal(span, err.to_string()) } else { self.tcx diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 8e34436fb5e..5fd7c4d4f41 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -165,6 +165,10 @@ impl CodegenBackend for CraneliftCodegenBackend { "" } + fn name(&self) -> &'static str { + "cranelift" + } + fn init(&self, sess: &Session) { use rustc_session::config::{InstrumentCoverage, Lto}; match sess.lto() { diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 643c7feb89a..d994f3e32ec 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -167,7 +167,7 @@ pub(crate) fn size_and_align_of<'tcx>( if layout.is_sized() { return ( fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64), - fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64), + fx.bcx.ins().iconst(fx.pointer_type, layout.align.bytes() as i64), ); } @@ -186,7 +186,7 @@ pub(crate) fn size_and_align_of<'tcx>( // times the unit size. ( fx.bcx.ins().imul_imm(info.unwrap(), unit.size.bytes() as i64), - fx.bcx.ins().iconst(fx.pointer_type, unit.align.abi.bytes() as i64), + fx.bcx.ins().iconst(fx.pointer_type, unit.align.bytes() as i64), ) } ty::Foreign(_) => { @@ -224,7 +224,7 @@ pub(crate) fn size_and_align_of<'tcx>( let unsized_offset_unadjusted = layout.fields.offset(i).bytes(); let unsized_offset_unadjusted = fx.bcx.ins().iconst(fx.pointer_type, unsized_offset_unadjusted as i64); - let sized_align = layout.align.abi.bytes(); + let sized_align = layout.align.bytes(); let sized_align = fx.bcx.ins().iconst(fx.pointer_type, sized_align as i64); // Recurse to get the size of the dynamically sized field (must be diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 4519fa1a270..db9b80c0f6a 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -383,7 +383,7 @@ impl<'tcx> CPlace<'tcx> { let stack_slot = fx.create_stack_slot( u32::try_from(layout.size.bytes()).unwrap(), - u32::try_from(layout.align.abi.bytes()).unwrap(), + u32::try_from(layout.align.bytes()).unwrap(), ); CPlace { inner: CPlaceInner::Addr(stack_slot, None), layout } } @@ -641,8 +641,8 @@ impl<'tcx> CPlace<'tcx> { let size = dst_layout.size.bytes(); // `emit_small_memory_copy` uses `u8` for alignments, just use the maximum // alignment that fits in a `u8` if the actual alignment is larger. - let src_align = src_layout.align.abi.bytes().try_into().unwrap_or(128); - let dst_align = dst_layout.align.abi.bytes().try_into().unwrap_or(128); + let src_align = src_layout.align.bytes().try_into().unwrap_or(128); + let dst_align = dst_layout.align.bytes().try_into().unwrap_or(128); fx.bcx.emit_small_memory_copy( fx.target_config, to_addr, @@ -660,7 +660,7 @@ impl<'tcx> CPlace<'tcx> { } } - /// Used for `ProjectionElem::Subtype`, `ty` has to be monomorphized before + /// Used for `ProjectionElem::UnwrapUnsafeBinder`, `ty` has to be monomorphized before /// passed on. pub(crate) fn place_transmute_type( self, diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 17e2e028b16..a14881c502c 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -698,8 +698,12 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str { InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v", - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) - | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + InlineAsmRegClass::PowerPC( + PowerPCInlineAsmRegClass::cr + | PowerPCInlineAsmRegClass::ctr + | PowerPCInlineAsmRegClass::lr + | PowerPCInlineAsmRegClass::xer, + ) => { unreachable!("clobber-only") } InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", @@ -777,8 +781,12 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => { cx.type_vector(cx.type_i32(), 4) } - InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) - | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + InlineAsmRegClass::PowerPC( + PowerPCInlineAsmRegClass::cr + | PowerPCInlineAsmRegClass::ctr + | PowerPCInlineAsmRegClass::lr + | PowerPCInlineAsmRegClass::xer, + ) => { unreachable!("clobber-only") } InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index e9d72e457a0..e8672f49580 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -15,9 +15,9 @@ use rustc_middle::mir::mono::Visibility; use rustc_middle::ty::TyCtxt; use rustc_session::config::DebugInfo; use rustc_span::Symbol; +use rustc_target::spec::RelocModel; #[cfg(feature = "master")] use rustc_target::spec::SymbolVisibility; -use rustc_target::spec::{PanicStrategy, RelocModel}; use crate::builder::Builder; use crate::context::CodegenCx; @@ -101,7 +101,7 @@ pub fn compile_codegen_unit( // Instantiate monomorphizations without filling out definitions yet... let context = new_context(tcx); - if tcx.sess.panic_strategy() == PanicStrategy::Unwind { + if tcx.sess.panic_strategy().unwinds() { context.add_command_line_option("-fexceptions"); context.add_driver_option("-fexceptions"); } diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index f7a7a3f8c7e..5657620879c 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1383,6 +1383,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _src_align: Align, size: RValue<'gcc>, flags: MemFlags, + _tt: Option<rustc_ast::expand::typetree::FncTree>, // Autodiff TypeTrees are LLVM-only, ignored in GCC backend ) { assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported"); let size = self.intcast(size, self.type_size_t(), false); diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 665cf22ddba..c9ae96777de 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -147,7 +147,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let layout = tcx .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type)) .unwrap(); - let align = layout.align.abi.bytes(); + let align = layout.align.bytes(); // For types with size 1, the alignment can be 1 and only 1 // So, we can skip the call to ``get_aligned`. // In the future, we can add a GCC API to query the type align, @@ -186,9 +186,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { (i128_type, u128_type) } else { /*let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.i128)).unwrap(); - let i128_align = layout.align.abi.bytes(); + let i128_align = layout.align.bytes(); let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.u128)).unwrap(); - let u128_align = layout.align.abi.bytes();*/ + let u128_align = layout.align.bytes();*/ // TODO(antoyo): re-enable the alignment when libgccjit fixed the issue in // gcc_jit_context_new_array_constructor (it should not use reinterpret_cast). @@ -529,7 +529,10 @@ impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> { impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { + if let LayoutError::SizeOverflow(_) + | LayoutError::InvalidSimd { .. } + | LayoutError::ReferencesError(_) = err + { self.tcx.dcx().emit_fatal(respan(span, err.into_diagnostic())) } else { self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err }) @@ -545,7 +548,9 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { span: Span, fn_abi_request: FnAbiRequest<'tcx>, ) -> ! { - if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { + if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) = + err + { self.tcx.dcx().emit_fatal(respan(span, err)) } else { match fn_abi_request { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 84fa56cf903..99a4f9b9f7e 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -29,7 +29,6 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{Span, Symbol, sym}; use rustc_target::callconv::{ArgAbi, PassMode}; -use rustc_target::spec::PanicStrategy; #[cfg(feature = "master")] use crate::abi::FnAbiGccExt; @@ -771,6 +770,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { scratch_align, bx.const_usize(self.layout.size.bytes()), MemFlags::empty(), + None, ); bx.lifetime_end(scratch, scratch_size); @@ -1334,7 +1334,7 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( _catch_func: RValue<'gcc>, dest: PlaceRef<'tcx, RValue<'gcc>>, ) { - if bx.sess().panic_strategy() == PanicStrategy::Abort { + if !bx.sess().panic_strategy().unwinds() { bx.call(bx.type_void(), None, None, try_func, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index f76f933cad4..ec7eab8489a 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -184,6 +184,10 @@ impl CodegenBackend for GccCodegenBackend { crate::DEFAULT_LOCALE_RESOURCE } + fn name(&self) -> &'static str { + "gcc" + } + fn init(&self, _sess: &Session) { #[cfg(feature = "master")] { diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 11be7041167..1703cab942b 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -246,6 +246,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { scratch_align, bx.const_usize(copy_bytes), MemFlags::empty(), + None, ); bx.lifetime_end(llscratch, scratch_size); } @@ -538,7 +539,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { // If the declaration has an associated instance, compute extra attributes based on that. if let Some(instance) = instance { - llfn_attrs_from_instance(cx, llfn, instance); + llfn_attrs_from_instance( + cx, + cx.tcx, + llfn, + &cx.tcx.codegen_instance_attrs(instance.def), + Some(instance), + ); } } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index df3e49279d9..896d6755c75 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -5,15 +5,17 @@ use rustc_ast::expand::allocator::{ }; use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _; use rustc_middle::bug; +use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DebugInfo, OomStrategy}; +use rustc_span::sym; use rustc_symbol_mangling::mangle_internal_symbol; -use smallvec::SmallVec; +use crate::attributes::llfn_attrs_from_instance; use crate::builder::SBuilder; use crate::declare::declare_simple_fn; use crate::llvm::{self, FALSE, TRUE, Type, Value}; -use crate::{SimpleCx, attributes, debuginfo, llvm_util}; +use crate::{SimpleCx, attributes, debuginfo}; pub(crate) unsafe fn codegen( tcx: TyCtxt<'_>, @@ -58,7 +60,26 @@ pub(crate) unsafe fn codegen( let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); - create_wrapper_function(tcx, &cx, &from_name, Some(&to_name), &args, output, false); + let alloc_attr_flag = match method.name { + sym::alloc => CodegenFnAttrFlags::ALLOCATOR, + sym::dealloc => CodegenFnAttrFlags::DEALLOCATOR, + sym::realloc => CodegenFnAttrFlags::REALLOCATOR, + sym::alloc_zeroed => CodegenFnAttrFlags::ALLOCATOR_ZEROED, + _ => unreachable!("Unknown allocator method!"), + }; + + let mut attrs = CodegenFnAttrs::new(); + attrs.flags |= alloc_attr_flag; + create_wrapper_function( + tcx, + &cx, + &from_name, + Some(&to_name), + &args, + output, + false, + &attrs, + ); } } @@ -71,6 +92,7 @@ pub(crate) unsafe fn codegen( &[usize, usize], // size, align None, true, + &CodegenFnAttrs::new(), ); unsafe { @@ -92,6 +114,7 @@ pub(crate) unsafe fn codegen( &[], None, false, + &CodegenFnAttrs::new(), ); } @@ -138,6 +161,7 @@ fn create_wrapper_function( args: &[&Type], output: Option<&Type>, no_return: bool, + attrs: &CodegenFnAttrs, ) { let ty = cx.type_func(args, output.unwrap_or_else(|| cx.type_void())); let llfn = declare_simple_fn( @@ -149,18 +173,7 @@ fn create_wrapper_function( ty, ); - let mut attrs = SmallVec::<[_; 2]>::new(); - - let target_cpu = llvm_util::target_cpu(tcx.sess); - let target_cpu_attr = llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu); - - let tune_cpu_attr = llvm_util::tune_cpu(tcx.sess) - .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu)); - - attrs.push(target_cpu_attr); - attrs.extend(tune_cpu_attr); - - attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &attrs); + llfn_attrs_from_instance(cx, tcx, llfn, attrs, None); let no_return = if no_return { // -> ! DIFlagNoReturn @@ -171,12 +184,6 @@ fn create_wrapper_function( None }; - if tcx.sess.must_emit_unwind_tables() { - let uwtable = - attributes::uwtable_attr(cx.llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); - attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); - } - let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) }; let mut bx = SBuilder::build(&cx, llbb); diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index b79176e9098..93b1cf272ab 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -340,8 +340,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { attrs.push(llvm::AttributeKind::WillReturn.create_attr(self.cx.llcx)); } else if options.contains(InlineAsmOptions::NOMEM) { attrs.push(llvm::MemoryEffects::InaccessibleMemOnly.create_attr(self.cx.llcx)); - } else { - // LLVM doesn't have an attribute to represent ReadOnly + SideEffect + } else if options.contains(InlineAsmOptions::READONLY) { + attrs.push(llvm::MemoryEffects::ReadOnlyNotPure.create_attr(self.cx.llcx)); } attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs }); @@ -538,9 +538,7 @@ pub(crate) fn inline_asm_call<'ll>( bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)), ) })); - let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) }; - let md = bx.get_metadata_value(md); - llvm::LLVMSetMetadata(call, kind, md); + bx.cx.set_metadata_node(call, kind, &srcloc); Some(call) } @@ -662,7 +660,12 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", PowerPC(PowerPCInlineAsmRegClass::freg) => "f", PowerPC(PowerPCInlineAsmRegClass::vreg) => "v", - PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => { + PowerPC( + PowerPCInlineAsmRegClass::cr + | PowerPCInlineAsmRegClass::ctr + | PowerPCInlineAsmRegClass::lr + | PowerPCInlineAsmRegClass::xer, + ) => { unreachable!("clobber-only") } RiscV(RiscVInlineAsmRegClass::reg) => "r", @@ -830,7 +833,12 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), PowerPC(PowerPCInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i32(), 4), - PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => { + PowerPC( + PowerPCInlineAsmRegClass::cr + | PowerPCInlineAsmRegClass::ctr + | PowerPCInlineAsmRegClass::lr + | PowerPCInlineAsmRegClass::xer, + ) => { unreachable!("clobber-only") } RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 573c51a9539..8070ea0b3e9 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -1,20 +1,21 @@ //! Set and unset common attributes on LLVM values. -use rustc_codegen_ssa::traits::*; use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_hir::def_id::DefId; -use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry}; +use rustc_middle::middle::codegen_fn_attrs::{ + CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, +}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet}; use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector}; use smallvec::SmallVec; -use crate::context::CodegenCx; +use crate::context::SimpleCx; use crate::errors::SanitizerMemtagRequiresMte; use crate::llvm::AttributePlace::Function; use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects}; use crate::value::Value; -use crate::{attributes, llvm_util}; +use crate::{Session, attributes, llvm_util}; pub(crate) fn apply_to_llfn(llfn: &Value, idx: AttributePlace, attrs: &[&Attribute]) { if !attrs.is_empty() { @@ -30,18 +31,19 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[ /// Get LLVM attribute for the provided inline heuristic. pub(crate) fn inline_attr<'ll, 'tcx>( - cx: &CodegenCx<'ll, 'tcx>, + cx: &SimpleCx<'ll>, + tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>, ) -> Option<&'ll Attribute> { // `optnone` requires `noinline` - let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id()); let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) { (_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never, - (InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint, + (InlineAttr::None, _) if instance.def.requires_inline(tcx) => InlineAttr::Hint, (inline, _) => inline, }; - if !cx.tcx.sess.opts.unstable_opts.inline_llvm { + if !tcx.sess.opts.unstable_opts.inline_llvm { // disable LLVM inlining return Some(AttributeKind::NoInline.create_attr(cx.llcx)); } @@ -51,7 +53,7 @@ pub(crate) fn inline_attr<'ll, 'tcx>( Some(AttributeKind::AlwaysInline.create_attr(cx.llcx)) } InlineAttr::Never => { - if cx.sess().target.arch != "amdgpu" { + if tcx.sess.target.arch != "amdgpu" { Some(AttributeKind::NoInline.create_attr(cx.llcx)) } else { None @@ -63,12 +65,13 @@ pub(crate) fn inline_attr<'ll, 'tcx>( #[inline] fn patchable_function_entry_attrs<'ll>( - cx: &CodegenCx<'ll, '_>, + cx: &SimpleCx<'ll>, + sess: &Session, attr: Option<PatchableFunctionEntry>, ) -> SmallVec<[&'ll Attribute; 2]> { let mut attrs = SmallVec::new(); let patchable_spec = attr.unwrap_or_else(|| { - PatchableFunctionEntry::from_config(cx.tcx.sess.opts.unstable_opts.patchable_function_entry) + PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry) }); let entry = patchable_spec.entry(); let prefix = patchable_spec.prefix(); @@ -91,12 +94,13 @@ fn patchable_function_entry_attrs<'ll>( /// Get LLVM sanitize attributes. #[inline] -pub(crate) fn sanitize_attrs<'ll>( - cx: &CodegenCx<'ll, '_>, +pub(crate) fn sanitize_attrs<'ll, 'tcx>( + cx: &SimpleCx<'ll>, + tcx: TyCtxt<'tcx>, no_sanitize: SanitizerSet, ) -> SmallVec<[&'ll Attribute; 4]> { let mut attrs = SmallVec::new(); - let enabled = cx.tcx.sess.opts.unstable_opts.sanitizer - no_sanitize; + let enabled = tcx.sess.opts.unstable_opts.sanitizer - no_sanitize; if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) { attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx)); } @@ -114,11 +118,11 @@ pub(crate) fn sanitize_attrs<'ll>( } if enabled.contains(SanitizerSet::MEMTAG) { // Check to make sure the mte target feature is actually enabled. - let features = cx.tcx.global_backend_features(()); + let features = tcx.global_backend_features(()); let mte_feature = features.iter().map(|s| &s[..]).rfind(|n| ["+mte", "-mte"].contains(&&n[..])); if let None | Some("-mte") = mte_feature { - cx.tcx.dcx().emit_err(SanitizerMemtagRequiresMte); + tcx.dcx().emit_err(SanitizerMemtagRequiresMte); } attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx)); @@ -139,9 +143,12 @@ pub(crate) fn uwtable_attr(llcx: &llvm::Context, use_sync_unwind: Option<bool>) llvm::CreateUWTableAttr(llcx, async_unwind) } -pub(crate) fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { - let mut fp = cx.sess().target.frame_pointer; - let opts = &cx.sess().opts; +pub(crate) fn frame_pointer_type_attr<'ll>( + cx: &SimpleCx<'ll>, + sess: &Session, +) -> Option<&'ll Attribute> { + let mut fp = sess.target.frame_pointer; + let opts = &sess.opts; // "mcount" function relies on stack pointer. // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>. if opts.unstable_opts.instrument_mcount { @@ -156,8 +163,8 @@ pub(crate) fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&' Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value)) } -fn function_return_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { - let function_return_attr = match cx.sess().opts.unstable_opts.function_return { +fn function_return_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> { + let function_return_attr = match sess.opts.unstable_opts.function_return { FunctionReturn::Keep => return None, FunctionReturn::ThunkExtern => AttributeKind::FnRetThunkExtern, }; @@ -167,17 +174,20 @@ fn function_return_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> /// Tell LLVM what instrument function to insert. #[inline] -fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 4]> { +fn instrument_function_attr<'ll>( + cx: &SimpleCx<'ll>, + sess: &Session, +) -> SmallVec<[&'ll Attribute; 4]> { let mut attrs = SmallVec::new(); - if cx.sess().opts.unstable_opts.instrument_mcount { + if sess.opts.unstable_opts.instrument_mcount { // Similar to `clang -pg` behavior. Handled by the // `post-inline-ee-instrument` LLVM pass. // The function name varies on platforms. // See test/CodeGen/mcount.c in clang. - let mcount_name = match &cx.sess().target.llvm_mcount_intrinsic { + let mcount_name = match &sess.target.llvm_mcount_intrinsic { Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(), - None => cx.sess().target.mcount.as_ref(), + None => sess.target.mcount.as_ref(), }; attrs.push(llvm::CreateAttrStringValue( @@ -186,7 +196,7 @@ fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attr mcount_name, )); } - if let Some(options) = &cx.sess().opts.unstable_opts.instrument_xray { + if let Some(options) = &sess.opts.unstable_opts.instrument_xray { // XRay instrumentation is similar to __cyg_profile_func_{enter,exit}. // Function prologue and epilogue are instrumented with NOP sleds, // a runtime library later replaces them with detours into tracing code. @@ -217,20 +227,20 @@ fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attr attrs } -fn nojumptables_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { - if !cx.sess().opts.unstable_opts.no_jump_tables { +fn nojumptables_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> { + if !sess.opts.unstable_opts.no_jump_tables { return None; } Some(llvm::CreateAttrStringValue(cx.llcx, "no-jump-tables", "true")) } -fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { +fn probestack_attr<'ll, 'tcx>(cx: &SimpleCx<'ll>, tcx: TyCtxt<'tcx>) -> Option<&'ll Attribute> { // Currently stack probes seem somewhat incompatible with the address // sanitizer and thread sanitizer. With asan we're already protected from // stack overflow anyway so we don't really need stack probes regardless. - if cx - .sess() + if tcx + .sess .opts .unstable_opts .sanitizer @@ -240,22 +250,22 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { } // probestack doesn't play nice either with `-C profile-generate`. - if cx.sess().opts.cg.profile_generate.enabled() { + if tcx.sess.opts.cg.profile_generate.enabled() { return None; } - let attr_value = match cx.sess().target.stack_probes { + let attr_value = match tcx.sess.target.stack_probes { StackProbeType::None => return None, // Request LLVM to generate the probes inline. If the given LLVM version does not support // this, no probe is generated at all (even if the attribute is specified). StackProbeType::Inline => "inline-asm", // Flag our internal `__rust_probestack` function as the stack probe symbol. // This is defined in the `compiler-builtins` crate for each architecture. - StackProbeType::Call => &mangle_internal_symbol(cx.tcx, "__rust_probestack"), + StackProbeType::Call => &mangle_internal_symbol(tcx, "__rust_probestack"), // Pick from the two above based on the LLVM version. StackProbeType::InlineOrCall { min_llvm_version_for_inline } => { if llvm_util::get_version() < min_llvm_version_for_inline { - &mangle_internal_symbol(cx.tcx, "__rust_probestack") + &mangle_internal_symbol(tcx, "__rust_probestack") } else { "inline-asm" } @@ -264,8 +274,8 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { Some(llvm::CreateAttrStringValue(cx.llcx, "probe-stack", attr_value)) } -fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { - let sspattr = match cx.sess().stack_protector() { +fn stackprotector_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> { + let sspattr = match sess.stack_protector() { StackProtector::None => return None, StackProtector::All => AttributeKind::StackProtectReq, StackProtector::Strong => AttributeKind::StackProtectStrong, @@ -275,33 +285,34 @@ fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { Some(sspattr.create_attr(cx.llcx)) } -fn backchain_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { - if cx.sess().target.arch != "s390x" { +fn backchain_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> { + if sess.target.arch != "s390x" { return None; } - let requested_features = cx.sess().opts.cg.target_feature.split(','); + let requested_features = sess.opts.cg.target_feature.split(','); let found_positive = requested_features.clone().any(|r| r == "+backchain"); if found_positive { Some(llvm::CreateAttrString(cx.llcx, "backchain")) } else { None } } -pub(crate) fn target_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll Attribute { - let target_cpu = llvm_util::target_cpu(cx.tcx.sess); +pub(crate) fn target_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> &'ll Attribute { + let target_cpu = llvm_util::target_cpu(sess); llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu) } -pub(crate) fn tune_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { - llvm_util::tune_cpu(cx.tcx.sess) +pub(crate) fn tune_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> { + llvm_util::tune_cpu(sess) .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu)) } /// Get the `target-features` LLVM attribute. -pub(crate) fn target_features_attr<'ll>( - cx: &CodegenCx<'ll, '_>, +pub(crate) fn target_features_attr<'ll, 'tcx>( + cx: &SimpleCx<'ll>, + tcx: TyCtxt<'tcx>, function_features: Vec<String>, ) -> Option<&'ll Attribute> { - let global_features = cx.tcx.global_backend_features(()).iter().map(String::as_str); + let global_features = tcx.global_backend_features(()).iter().map(String::as_str); let function_features = function_features.iter().map(String::as_str); let target_features = global_features.chain(function_features).intersperse(",").collect::<String>(); @@ -311,22 +322,22 @@ pub(crate) fn target_features_attr<'ll>( /// Get the `NonLazyBind` LLVM attribute, /// if the codegen options allow skipping the PLT. -pub(crate) fn non_lazy_bind_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { +pub(crate) fn non_lazy_bind_attr<'ll>( + cx: &SimpleCx<'ll>, + sess: &Session, +) -> Option<&'ll Attribute> { // Don't generate calls through PLT if it's not necessary - if !cx.sess().needs_plt() { - Some(AttributeKind::NonLazyBind.create_attr(cx.llcx)) - } else { - None - } + if !sess.needs_plt() { Some(AttributeKind::NonLazyBind.create_attr(cx.llcx)) } else { None } } /// Get the default optimizations attrs for a function. #[inline] pub(crate) fn default_optimisation_attrs<'ll>( - cx: &CodegenCx<'ll, '_>, + cx: &SimpleCx<'ll>, + sess: &Session, ) -> SmallVec<[&'ll Attribute; 2]> { let mut attrs = SmallVec::new(); - match cx.sess().opts.optimize { + match sess.opts.optimize { OptLevel::Size => { attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx)); } @@ -347,17 +358,18 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute { /// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`) /// attributes. pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( - cx: &CodegenCx<'ll, 'tcx>, + cx: &SimpleCx<'ll>, + tcx: TyCtxt<'tcx>, llfn: &'ll Value, - instance: ty::Instance<'tcx>, + codegen_fn_attrs: &CodegenFnAttrs, + instance: Option<ty::Instance<'tcx>>, ) { - let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def); - + let sess = tcx.sess; let mut to_add = SmallVec::<[_; 16]>::new(); match codegen_fn_attrs.optimize { OptimizeAttr::Default => { - to_add.extend(default_optimisation_attrs(cx)); + to_add.extend(default_optimisation_attrs(cx, sess)); } OptimizeAttr::DoNotOptimize => { to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx)); @@ -369,21 +381,21 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( OptimizeAttr::Speed => {} } - if cx.sess().must_emit_unwind_tables() { - to_add.push(uwtable_attr(cx.llcx, cx.sess().opts.unstable_opts.use_sync_unwind)); + if sess.must_emit_unwind_tables() { + to_add.push(uwtable_attr(cx.llcx, sess.opts.unstable_opts.use_sync_unwind)); } - if cx.sess().opts.unstable_opts.profile_sample_use.is_some() { + if sess.opts.unstable_opts.profile_sample_use.is_some() { to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile")); } // FIXME: none of these functions interact with source level attributes. - to_add.extend(frame_pointer_type_attr(cx)); - to_add.extend(function_return_attr(cx)); - to_add.extend(instrument_function_attr(cx)); - to_add.extend(nojumptables_attr(cx)); - to_add.extend(probestack_attr(cx)); - to_add.extend(stackprotector_attr(cx)); + to_add.extend(frame_pointer_type_attr(cx, sess)); + to_add.extend(function_return_attr(cx, sess)); + to_add.extend(instrument_function_attr(cx, sess)); + to_add.extend(nojumptables_attr(cx, sess)); + to_add.extend(probestack_attr(cx, tcx)); + to_add.extend(stackprotector_attr(cx, sess)); if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_BUILTINS) { to_add.push(llvm::CreateAttrString(cx.llcx, "no-builtins")); @@ -404,16 +416,19 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( // not used. } else { // Do not set sanitizer attributes for naked functions. - to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); + to_add.extend(sanitize_attrs(cx, tcx, codegen_fn_attrs.no_sanitize)); // For non-naked functions, set branch protection attributes on aarch64. - if let Some(BranchProtection { bti, pac_ret }) = - cx.sess().opts.unstable_opts.branch_protection + if let Some(BranchProtection { bti, pac_ret, gcs }) = + sess.opts.unstable_opts.branch_protection { - assert!(cx.sess().target.arch == "aarch64"); + assert!(sess.target.arch == "aarch64"); if bti { to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement")); } + if gcs { + to_add.push(llvm::CreateAttrString(cx.llcx, "guarded-control-stack")); + } if let Some(PacRet { leaf, pc, key }) = pac_ret { if pc { to_add.push(llvm::CreateAttrString(cx.llcx, "branch-protection-pauth-lr")); @@ -435,14 +450,15 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED) { to_add.push(create_alloc_family_attr(cx.llcx)); - if let Some(zv) = - cx.tcx.get_attr(instance.def_id(), rustc_span::sym::rustc_allocator_zeroed_variant) + if let Some(instance) = instance + && let Some(zv) = + tcx.get_attr(instance.def_id(), rustc_span::sym::rustc_allocator_zeroed_variant) && let Some(name) = zv.value_str() { to_add.push(llvm::CreateAttrStringValue( cx.llcx, "alloc-variant-zeroed", - &mangle_internal_symbol(cx.tcx, name.as_str()), + &mangle_internal_symbol(tcx, name.as_str()), )); } // apply to argument place instead of function @@ -487,18 +503,22 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); } - if let Some(backchain) = backchain_attr(cx) { + if let Some(backchain) = backchain_attr(cx, sess) { to_add.push(backchain); } - to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry)); + to_add.extend(patchable_function_entry_attrs( + cx, + sess, + codegen_fn_attrs.patchable_function_entry, + )); // Always annotate functions with the target-cpu they are compiled for. // Without this, ThinLTO won't inline Rust functions into Clang generated // functions (because Clang annotates functions this way too). - to_add.push(target_cpu_attr(cx)); + to_add.push(target_cpu_attr(cx, sess)); // tune-cpu is only conveyed through the attribute for our purpose. // The target doesn't care; the subtarget reads our attribute. - to_add.extend(tune_cpu_attr(cx)); + to_add.extend(tune_cpu_attr(cx, sess)); let function_features = codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>(); @@ -506,7 +526,9 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( // Apply function attributes as per usual if there are no user defined // target features otherwise this will get applied at the callsite. if function_features.is_empty() { - if let Some(inline_attr) = inline_attr(cx, instance) { + if let Some(instance) = instance + && let Some(inline_attr) = inline_attr(cx, tcx, instance) + { to_add.push(inline_attr); } } @@ -514,7 +536,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let function_features = function_features .iter() // Convert to LLVMFeatures and filter out unavailable ones - .flat_map(|feat| llvm_util::to_llvm_features(cx.tcx.sess, feat)) + .flat_map(|feat| llvm_util::to_llvm_features(sess, feat)) // Convert LLVMFeatures & dependencies to +<feats>s .flat_map(|feat| feat.into_iter().map(|f| format!("+{f}"))) .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x { @@ -523,20 +545,22 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( })) .collect::<Vec<String>>(); - if cx.tcx.sess.target.is_like_wasm { + if sess.target.is_like_wasm { // If this function is an import from the environment but the wasm // import has a specific module/name, apply them here. - if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) { + if let Some(instance) = instance + && let Some(module) = wasm_import_module(tcx, instance.def_id()) + { to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-module", module)); let name = - codegen_fn_attrs.symbol_name.unwrap_or_else(|| cx.tcx.item_name(instance.def_id())); + codegen_fn_attrs.symbol_name.unwrap_or_else(|| tcx.item_name(instance.def_id())); let name = name.as_str(); to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name)); } } - to_add.extend(target_features_attr(cx, function_features)); + to_add.extend(target_features_attr(cx, tcx, function_features)); attributes::apply_to_llfn(llfn, Function, &to_add); } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 78107d95e5a..5ac3a87c158 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -563,6 +563,8 @@ fn enable_autodiff_settings(ad: &[config::AutoDiff]) { config::AutoDiff::Enable => {} // We handle this below config::AutoDiff::NoPostopt => {} + // Disables TypeTree generation + config::AutoDiff::NoTT => {} } } // This helps with handling enums for now. diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index d5228f0e0de..903a882916e 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -95,8 +95,6 @@ impl Drop for OwnedTargetMachine { // SAFETY: constructing ensures we have a valid pointer created by // llvm::LLVMRustCreateTargetMachine OwnedTargetMachine is not copyable so there is no // double free or use after free. - unsafe { - llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_ptr()); - } + unsafe { llvm::LLVMDisposeTargetMachine(self.tm_unique) }; } } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index c4881f0aafc..1950b8288d1 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -204,6 +204,9 @@ pub(crate) fn target_machine_factory( optlvl: config::OptLevel, target_features: &[String], ) -> TargetMachineFactoryFn<LlvmCodegenBackend> { + // Self-profile timer for creating a _factory_. + let _prof_timer = sess.prof.generic_activity("target_machine_factory"); + let reloc_model = to_llvm_relocation_model(sess.relocation_model()); let (opt_level, _) = to_llvm_opt_settings(optlvl); @@ -259,6 +262,9 @@ pub(crate) fn target_machine_factory( .into_string() .unwrap_or_default(); let command_line_args = quote_command_line_args(&sess.expanded_args); + // Self-profile counter for the number of bytes produced by command-line quoting. + // Values are summed, so the summary result is cumulative across all TM factories. + sess.prof.artifact_size("quoted_command_line_args", "-", command_line_args.len() as u64); let debuginfo_compression = sess.opts.debuginfo_compression.to_string(); match sess.opts.debuginfo_compression { @@ -281,7 +287,11 @@ pub(crate) fn target_machine_factory( let use_wasm_eh = wants_wasm_eh(sess); + let prof = SelfProfilerRef::clone(&sess.prof); Arc::new(move |config: TargetMachineFactoryConfig| { + // Self-profile timer for invoking a factory to create a target machine. + let _prof_timer = prof.generic_activity("target_machine_factory_inner"); + let path_to_cstring_helper = |path: Option<PathBuf>| -> CString { let path = path.unwrap_or_default(); let path = path_mapping diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 978134cc32b..6d12b511e9c 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -105,7 +105,7 @@ pub(crate) fn compile_codegen_unit( if let Some(entry) = maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx, cx.codegen_unit) { - let attrs = attributes::sanitize_attrs(&cx, SanitizerSet::empty()); + let attrs = attributes::sanitize_attrs(&cx, tcx, SanitizerSet::empty()); attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs); } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 0f17cc9063a..e7cb18ab22d 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1,11 +1,12 @@ use std::borrow::{Borrow, Cow}; +use std::iter; use std::ops::Deref; -use std::{iter, ptr}; +use rustc_ast::expand::typetree::FncTree; pub(crate) mod autodiff; pub(crate) mod gpu_offload; -use libc::{c_char, c_uint, size_t}; +use libc::{c_char, c_uint}; use rustc_abi as abi; use rustc_abi::{Align, Size, WrappingRange}; use rustc_codegen_ssa::MemFlags; @@ -395,10 +396,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { md.push(weight(is_cold)); } - unsafe { - let md_node = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len() as size_t); - self.cx.set_metadata(switch, llvm::MD_prof, md_node); - } + self.cx.set_metadata_node(switch, llvm::MD_prof, &md); } fn invoke( @@ -800,22 +798,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { return; } - unsafe { - let llty = self.cx.val_ty(load); - let md = [ - llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)), - llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))), - ]; - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len()); - self.set_metadata(load, llvm::MD_range, md); - } + let llty = self.cx.val_ty(load); + let md = [ + llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)), + llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))), + ]; + self.set_metadata_node(load, llvm::MD_range, &md); } fn nonnull_metadata(&mut self, load: &'ll Value) { - unsafe { - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); - self.set_metadata(load, llvm::MD_nonnull, md); - } + self.set_metadata_node(load, llvm::MD_nonnull, &[]); } fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value { @@ -864,8 +856,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // // [1]: https://llvm.org/docs/LangRef.html#store-instruction let one = llvm::LLVMValueAsMetadata(self.cx.const_i32(1)); - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, &one, 1); - self.set_metadata(store, llvm::MD_nontemporal, md); + self.set_metadata_node(store, llvm::MD_nontemporal, &[one]); } } store @@ -1107,11 +1098,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { src_align: Align, size: &'ll Value, flags: MemFlags, + tt: Option<FncTree>, ) { assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported"); let size = self.intcast(size, self.type_isize(), false); let is_volatile = flags.contains(MemFlags::VOLATILE); - unsafe { + let memcpy = unsafe { llvm::LLVMRustBuildMemCpy( self.llbuilder, dst, @@ -1120,7 +1112,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { src_align.bytes() as c_uint, size, is_volatile, - ); + ) + }; + + // TypeTree metadata for memcpy is especially important: when Enzyme encounters + // a memcpy during autodiff, it needs to know the structure of the data being + // copied to properly track derivatives. For example, copying an array of floats + // vs. copying a struct with mixed types requires different derivative handling. + // The TypeTree tells Enzyme exactly what memory layout to expect. + if let Some(tt) = tt { + crate::typetree::add_tt(self.cx().llmod, self.cx().llcx, memcpy, tt); } } @@ -1370,10 +1371,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn set_invariant_load(&mut self, load: &'ll Value) { - unsafe { - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); - self.set_metadata(load, llvm::MD_invariant_load, md); - } + self.set_metadata_node(load, llvm::MD_invariant_load, &[]); } fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) { @@ -1433,7 +1431,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // If there is an inline attribute and a target feature that matches // we will add the attribute to the callsite otherwise we'll omit // this and not add the attribute to prevent soundness issues. - && let Some(inlining_rule) = attributes::inline_attr(&self.cx, instance) + && let Some(inlining_rule) = attributes::inline_attr(&self.cx, self.cx.tcx, instance) && self.cx.tcx.is_target_feature_call_safe( &fn_call_attrs.target_features, &fn_defn_attrs.target_features, @@ -1517,25 +1515,16 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> { } impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { fn align_metadata(&mut self, load: &'ll Value, align: Align) { - unsafe { - let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))]; - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len()); - self.set_metadata(load, llvm::MD_align, md); - } + let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))]; + self.set_metadata_node(load, llvm::MD_align, &md); } fn noundef_metadata(&mut self, load: &'ll Value) { - unsafe { - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); - self.set_metadata(load, llvm::MD_noundef, md); - } + self.set_metadata_node(load, llvm::MD_noundef, &[]); } pub(crate) fn set_unpredictable(&mut self, inst: &'ll Value) { - unsafe { - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); - self.set_metadata(inst, llvm::MD_unpredictable, md); - } + self.set_metadata_node(inst, llvm::MD_unpredictable, &[]); } } impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> { diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index b66e3dfdeec..4a749642265 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -1,6 +1,7 @@ use std::ptr; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; +use rustc_ast::expand::typetree::FncTree; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; use rustc_middle::ty::{Instance, PseudoCanonicalInput, TyCtxt, TypingEnv}; @@ -294,6 +295,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( fn_args: &[&'ll Value], attrs: AutoDiffAttrs, dest: PlaceRef<'tcx, &'ll Value>, + fnc_tree: FncTree, ) { // We have to pick the name depending on whether we want forward or reverse mode autodiff. let mut ad_name: String = match attrs.mode { @@ -370,7 +372,18 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( fn_args, ); + if !fnc_tree.args.is_empty() || !fnc_tree.ret.0.is_empty() { + crate::typetree::add_tt(cx.llmod, cx.llcx, fn_to_diff, fnc_tree); + } + let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None); - builder.store_to_place(call, dest.val); + let fn_ret_ty = builder.cx.val_ty(call); + if fn_ret_ty != builder.cx.type_void() && fn_ret_ty != builder.cx.type_struct(&[], false) { + // If we return void or an empty struct, then our caller (due to how we generated it) + // does not expect a return value. As such, we have no pointer (or place) into which + // we could store our value, and would store into an undef, which would cause UB. + // As such, we just ignore the return value in those cases. + builder.store_to_place(call, dest.val); + } } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index a110ecbb75d..b4ca85a26c8 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -494,16 +494,7 @@ impl<'ll> CodegenCx<'ll, '_> { let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); let alloc = self.create_metadata(bytes); let data = [section, alloc]; - let meta = - unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) }; - let val = self.get_metadata_value(meta); - unsafe { - llvm::LLVMAddNamedMetadataOperand( - self.llmod, - c"wasm.custom_sections".as_ptr(), - val, - ) - }; + self.module_add_named_metadata_node(self.llmod(), c"wasm.custom_sections", &data); } } else { base::set_link_section(g, attrs); @@ -564,7 +555,7 @@ impl<'ll> CodegenCx<'ll, '_> { let g = self.define_global(&sym, llty).unwrap_or_else(|| { bug!("symbol `{}` is already defined", sym); }); - set_global_alignment(self, g, self.tcx.data_layout.i8_align.abi); + set_global_alignment(self, g, self.tcx.data_layout.i8_align); llvm::set_initializer(g, llval); llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); llvm::set_section(g, c"__TEXT,__cstring,cstring_literals"); @@ -680,7 +671,7 @@ impl<'ll> CodegenCx<'ll, '_> { let methname_g = self.define_global(&methname_sym, methname_llty).unwrap_or_else(|| { bug!("symbol `{}` is already defined", methname_sym); }); - set_global_alignment(self, methname_g, self.tcx.data_layout.i8_align.abi); + set_global_alignment(self, methname_g, self.tcx.data_layout.i8_align); llvm::set_initializer(methname_g, methname_llval); llvm::set_linkage(methname_g, llvm::Linkage::PrivateLinkage); llvm::set_section( diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4a8ea11a3a8..922575dd63c 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,7 +34,7 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; -use crate::llvm::Metadata; +use crate::llvm::{Metadata, MetadataKindId, Module}; use crate::type_::Type; use crate::value::Value; use crate::{attributes, common, coverageinfo, debuginfo, llvm, llvm_util}; @@ -370,7 +370,8 @@ pub(crate) unsafe fn create_module<'ll>( ); } - if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection { + if let Some(BranchProtection { bti, pac_ret, gcs }) = sess.opts.unstable_opts.branch_protection + { if sess.target.arch == "aarch64" { llvm::add_module_flag_u32( llmod, @@ -403,6 +404,12 @@ pub(crate) unsafe fn create_module<'ll>( "sign-return-address-with-bkey", u32::from(pac_opts.key == PAuthKey::B), ); + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Min, + "guarded-control-stack", + gcs.into(), + ); } else { bug!( "branch-protection used on non-AArch64 target; \ @@ -488,14 +495,7 @@ pub(crate) unsafe fn create_module<'ll>( format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); let name_metadata = cx.create_metadata(rustc_producer.as_bytes()); - - unsafe { - llvm::LLVMAddNamedMetadataOperand( - llmod, - c"llvm.ident".as_ptr(), - &cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), - ); - } + cx.module_add_named_metadata_node(llmod, c"llvm.ident", &[name_metadata]); // Emit RISC-V specific target-abi metadata // to workaround lld as the LTO plugin not @@ -869,7 +869,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } else { let fty = self.type_variadic_func(&[], self.type_i32()); let llfn = self.declare_cfn(name, llvm::UnnamedAddr::Global, fty); - let target_cpu = attributes::target_cpu_attr(self); + let target_cpu = attributes::target_cpu_attr(self, self.sess()); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[target_cpu]); llfn } @@ -884,15 +884,15 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn set_frame_pointer_type(&self, llfn: &'ll Value) { - if let Some(attr) = attributes::frame_pointer_type_attr(self) { + if let Some(attr) = attributes::frame_pointer_type_attr(self, self.sess()) { attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[attr]); } } fn apply_target_cpu_attr(&self, llfn: &'ll Value) { let mut attrs = SmallVec::<[_; 2]>::new(); - attrs.push(attributes::target_cpu_attr(self)); - attrs.extend(attributes::tune_cpu_attr(self)); + attrs.push(attributes::target_cpu_attr(self, self.sess())); + attrs.extend(attributes::tune_cpu_attr(self, self.sess())); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &attrs); } @@ -911,7 +911,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { attributes::apply_to_llfn( llfn, llvm::AttributePlace::Function, - attributes::target_features_attr(self, vec![]).as_slice(), + attributes::target_features_attr(self, self.tcx, vec![]).as_slice(), ); Some(llfn) } else { @@ -995,15 +995,75 @@ impl CodegenCx<'_, '_> { } impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { + /// Wrapper for `LLVMMDNodeInContext2`, i.e. `llvm::MDNode::get`. + pub(crate) fn md_node_in_context(&self, md_list: &[&'ll Metadata]) -> &'ll Metadata { + unsafe { llvm::LLVMMDNodeInContext2(self.llcx(), md_list.as_ptr(), md_list.len()) } + } + /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`. pub(crate) fn set_metadata<'a>( &self, val: &'a Value, - kind_id: impl Into<llvm::MetadataKindId>, + kind_id: MetadataKindId, md: &'ll Metadata, ) { let node = self.get_metadata_value(md); - llvm::LLVMSetMetadata(val, kind_id.into(), node); + llvm::LLVMSetMetadata(val, kind_id, node); + } + + /// Helper method for the sequence of calls: + /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata) + /// - `LLVMMetadataAsValue` (to adapt that node to an `llvm::Value`) + /// - `LLVMSetMetadata` (to set that node as metadata of `kind_id` for `instruction`) + pub(crate) fn set_metadata_node( + &self, + instruction: &'ll Value, + kind_id: MetadataKindId, + md_list: &[&'ll Metadata], + ) { + let md = self.md_node_in_context(md_list); + self.set_metadata(instruction, kind_id, md); + } + + /// Helper method for the sequence of calls: + /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata) + /// - `LLVMMetadataAsValue` (to adapt that node to an `llvm::Value`) + /// - `LLVMAddNamedMetadataOperand` (to set that node as metadata of `kind_name` for `module`) + pub(crate) fn module_add_named_metadata_node( + &self, + module: &'ll Module, + kind_name: &CStr, + md_list: &[&'ll Metadata], + ) { + let md = self.md_node_in_context(md_list); + let md_as_val = self.get_metadata_value(md); + unsafe { llvm::LLVMAddNamedMetadataOperand(module, kind_name.as_ptr(), md_as_val) }; + } + + /// Helper method for the sequence of calls: + /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata) + /// - `LLVMRustGlobalAddMetadata` (to set that node as metadata of `kind_id` for `global`) + pub(crate) fn global_add_metadata_node( + &self, + global: &'ll Value, + kind_id: MetadataKindId, + md_list: &[&'ll Metadata], + ) { + let md = self.md_node_in_context(md_list); + unsafe { llvm::LLVMRustGlobalAddMetadata(global, kind_id, md) }; + } + + /// Helper method for the sequence of calls: + /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata) + /// - `LLVMGlobalSetMetadata` (to set that node as metadata of `kind_id` for `global`) + pub(crate) fn global_set_metadata_node( + &self, + global: &'ll Value, + kind_id: MetadataKindId, + md_list: &[&'ll Metadata], + ) { + let md = self.md_node_in_context(md_list); + unsafe { llvm::LLVMGlobalSetMetadata(global, kind_id, md) }; } } @@ -1037,7 +1097,10 @@ impl<'tcx, 'll> HasTypingEnv<'tcx> for CodegenCx<'ll, 'tcx> { impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { + if let LayoutError::SizeOverflow(_) + | LayoutError::ReferencesError(_) + | LayoutError::InvalidSimd { .. } = err + { self.tcx.dcx().emit_fatal(Spanned { span, node: err.into_diagnostic() }) } else { self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err }) @@ -1054,7 +1117,11 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> { fn_abi_request: FnAbiRequest<'tcx>, ) -> ! { match err { - FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::Cycle(_)) => { + FnAbiError::Layout( + LayoutError::SizeOverflow(_) + | LayoutError::Cycle(_) + | LayoutError::InvalidSimd { .. }, + ) => { self.tcx.dcx().emit_fatal(Spanned { span, node: err }); } _ => match fn_abi_request { diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs index bc4f6bb6a82..d50eb533ffd 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs @@ -2,26 +2,25 @@ use std::ffi::CString; -use crate::common::AsCCharPtr; use crate::coverageinfo::ffi; use crate::llvm; pub(crate) fn covmap_var_name() -> CString { - CString::new(llvm::build_byte_buffer(|s| unsafe { + CString::new(llvm::build_byte_buffer(|s| { llvm::LLVMRustCoverageWriteCovmapVarNameToString(s); })) .expect("covmap variable name should not contain NUL") } pub(crate) fn covmap_section_name(llmod: &llvm::Module) -> CString { - CString::new(llvm::build_byte_buffer(|s| unsafe { + CString::new(llvm::build_byte_buffer(|s| { llvm::LLVMRustCoverageWriteCovmapSectionNameToString(llmod, s); })) .expect("covmap section name should not contain NUL") } pub(crate) fn covfun_section_name(llmod: &llvm::Module) -> CString { - CString::new(llvm::build_byte_buffer(|s| unsafe { + CString::new(llvm::build_byte_buffer(|s| { llvm::LLVMRustCoverageWriteCovfunSectionNameToString(llmod, s); })) .expect("covfun section name should not contain NUL") @@ -34,7 +33,7 @@ pub(crate) fn create_pgo_func_name_var<'ll>( unsafe { llvm::LLVMRustCoverageCreatePGOFuncNameVar( llfn, - mangled_fn_name.as_c_char_ptr(), + mangled_fn_name.as_ptr(), mangled_fn_name.len(), ) } @@ -44,7 +43,7 @@ pub(crate) fn write_filenames_to_buffer(filenames: &[impl AsRef<str>]) -> Vec<u8 let (pointers, lengths) = filenames .into_iter() .map(AsRef::as_ref) - .map(|s: &str| (s.as_c_char_ptr(), s.len())) + .map(|s: &str| (s.as_ptr(), s.len())) .unzip::<_, _, Vec<_>, Vec<_>>(); llvm::build_byte_buffer(|buffer| unsafe { @@ -89,12 +88,12 @@ pub(crate) fn write_function_mappings_to_buffer( /// Hashes some bytes into a 64-bit hash, via LLVM's `IndexedInstrProf::ComputeHash`, /// as required for parts of the LLVM coverage mapping format. pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 { - unsafe { llvm::LLVMRustCoverageHashBytes(bytes.as_c_char_ptr(), bytes.len()) } + unsafe { llvm::LLVMRustCoverageHashBytes(bytes.as_ptr(), bytes.len()) } } /// Returns LLVM's `coverage::CovMapVersion::CurrentVersion` (CoverageMapping.h) /// as a raw numeric value. For historical reasons, the numeric value is 1 less /// than the number in the version's name, so `Version7` is actually `6u32`. pub(crate) fn mapping_version() -> u32 { - unsafe { llvm::LLVMRustCoverageMappingVersion() } + llvm::LLVMRustCoverageMappingVersion() } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 7a6dc008c7b..3081badb821 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -2,9 +2,9 @@ use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive; use rustc_codegen_ssa::traits::*; +use rustc_hir::attrs::DebuggerVisualizerType; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; -use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerType; use rustc_session::config::{CrateType, DebugInfo}; use crate::builder::Builder; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index aa8b8bd152d..2f9e7cae54f 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -117,7 +117,7 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>( .try_to_target_usize(cx.tcx) .expect("expected monomorphic const in codegen") as c_longlong; - let subrange = unsafe { llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) }; + let subrange = unsafe { llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) }; let subscripts = &[subrange]; let di_node = unsafe { @@ -477,8 +477,8 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>( ty::CoroutineClosure(..) => build_closure_env_di_node(cx, unique_type_id), ty::Coroutine(..) => enums::build_coroutine_di_node(cx, unique_type_id), ty::Adt(def, ..) => match def.adt_kind() { - AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id), - AdtKind::Union => build_union_type_di_node(cx, unique_type_id), + AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id, span), + AdtKind::Union => build_union_type_di_node(cx, unique_type_id, span), AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id, span), }, ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id), @@ -1043,7 +1043,7 @@ fn create_member_type<'ll, 'tcx>( file_metadata, line_number, layout.size.bits(), - layout.align.abi.bits() as u32, + layout.align.bits() as u32, offset.bits(), flags, type_di_node, @@ -1076,6 +1076,7 @@ fn visibility_di_flags<'ll, 'tcx>( fn build_struct_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId<'tcx>, + span: Span, ) -> DINodeCreationResult<'ll> { let struct_type = unique_type_id.expect_ty(); let ty::Adt(adt_def, _) = struct_type.kind() else { @@ -1083,7 +1084,7 @@ fn build_struct_type_di_node<'ll, 'tcx>( }; assert!(adt_def.is_struct()); let containing_scope = get_namespace_for_item(cx, adt_def.did()); - let struct_type_and_layout = cx.layout_of(struct_type); + let struct_type_and_layout = cx.spanned_layout_of(struct_type, span); let variant_def = adt_def.non_enum_variant(); let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers { Some(file_metadata_from_def_id(cx, Some(adt_def.did()))) @@ -1276,6 +1277,7 @@ fn build_closure_env_di_node<'ll, 'tcx>( fn build_union_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId<'tcx>, + span: Span, ) -> DINodeCreationResult<'ll> { let union_type = unique_type_id.expect_ty(); let (union_def_id, variant_def) = match union_type.kind() { @@ -1283,7 +1285,7 @@ fn build_union_type_di_node<'ll, 'tcx>( _ => bug!("build_union_type_di_node on a non-ADT"), }; let containing_scope = get_namespace_for_item(cx, union_def_id); - let union_ty_and_layout = cx.layout_of(union_type); + let union_ty_and_layout = cx.spanned_layout_of(union_type, span); let type_name = compute_debuginfo_type_name(cx.tcx, union_type, false); let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers { Some(file_metadata_from_def_id(cx, Some(union_def_id))) @@ -1605,21 +1607,11 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); let typeid = cx.create_metadata(trait_ref_typeid.as_bytes()); - unsafe { - let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; - llvm::LLVMRustGlobalAddMetadata( - vtable, - llvm::MD_type as c_uint, - llvm::LLVMMDNodeInContext2(cx.llcx, v.as_ptr(), v.len()), - ); - let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64)); - let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1); - llvm::LLVMGlobalSetMetadata( - vtable, - llvm::MetadataType::MD_vcall_visibility as c_uint, - vcall_visibility_metadata, - ); - } + let type_ = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; + cx.global_add_metadata_node(vtable, llvm::MD_type, &type_); + + let vcall_visibility = [llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64))]; + cx.global_set_metadata_node(vtable, llvm::MD_vcall_visibility, &vcall_visibility); } /// Creates debug information for the given vtable, which is for the diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 62d38d463ab..1ae6e6e5eec 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -289,7 +289,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>( file_metadata, line_number, enum_type_and_layout.size.bits(), - enum_type_and_layout.align.abi.bits() as u32, + enum_type_and_layout.align.bits() as u32, DIFlags::FlagZero, tag_member_di_node, create_DIArray(DIB(cx), &[]), @@ -449,7 +449,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>( file_di_node, line_number, enum_type_and_layout.size.bits(), - enum_type_and_layout.align.abi.bits() as u32, + enum_type_and_layout.align.bits() as u32, Size::ZERO.bits(), discr, DIFlags::FlagZero, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 126082aa3aa..af64e4ebed0 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -52,15 +52,6 @@ mod utils; use self::create_scope_map::compute_mir_scopes; pub(crate) use self::metadata::build_global_var_di_node; -// FIXME(Zalathar): These `DW_TAG_*` constants are fake values that were -// removed from LLVM in 2015, and are only used by our own `RustWrapper.cpp` -// to decide which C++ API to call. Instead, we should just have two separate -// FFI functions and choose the correct one on the Rust side. -#[allow(non_upper_case_globals)] -const DW_TAG_auto_variable: c_uint = 0x100; -#[allow(non_upper_case_globals)] -const DW_TAG_arg_variable: c_uint = 0x101; - /// A context object for maintaining all state needed by the debuginfo module. pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> { llmod: &'ll llvm::Module, @@ -174,35 +165,38 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { if direct_offset.bytes() > 0 { addr_ops.push(DW_OP_plus_uconst); - addr_ops.push(direct_offset.bytes() as u64); + addr_ops.push(direct_offset.bytes()); } for &offset in indirect_offsets { addr_ops.push(DW_OP_deref); if offset.bytes() > 0 { addr_ops.push(DW_OP_plus_uconst); - addr_ops.push(offset.bytes() as u64); + addr_ops.push(offset.bytes()); } } if let Some(fragment) = fragment { // `DW_OP_LLVM_fragment` takes as arguments the fragment's // offset and size, both of them in bits. addr_ops.push(DW_OP_LLVM_fragment); - addr_ops.push(fragment.start.bits() as u64); - addr_ops.push((fragment.end - fragment.start).bits() as u64); + addr_ops.push(fragment.start.bits()); + addr_ops.push((fragment.end - fragment.start).bits()); } + let di_builder = DIB(self.cx()); + let addr_expr = unsafe { + llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len()) + }; unsafe { // FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`. - llvm::LLVMRustDIBuilderInsertDeclareAtEnd( - DIB(self.cx()), + llvm::LLVMDIBuilderInsertDeclareRecordAtEnd( + di_builder, variable_alloca, dbg_var, - addr_ops.as_ptr(), - addr_ops.len() as c_uint, + addr_expr, dbg_loc, self.llbb(), - ); - } + ) + }; } fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) { @@ -630,28 +624,39 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let type_metadata = spanned_type_di_node(self, variable_type, span); - let (argument_index, dwarf_tag) = match variable_kind { - ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable), - LocalVariable => (0, DW_TAG_auto_variable), - }; let align = self.align_of(variable_type); let name = variable_name.as_str(); - unsafe { - llvm::LLVMRustDIBuilderCreateVariable( - DIB(self), - dwarf_tag, - scope_metadata, - name.as_c_char_ptr(), - name.len(), - file_metadata, - loc.line, - type_metadata, - true, - DIFlags::FlagZero, - argument_index, - align.bits() as u32, - ) + + match variable_kind { + ArgumentVariable(arg_index) => unsafe { + llvm::LLVMDIBuilderCreateParameterVariable( + DIB(self), + scope_metadata, + name.as_ptr(), + name.len(), + arg_index as c_uint, + file_metadata, + loc.line, + type_metadata, + llvm::Bool::TRUE, // (preserve descriptor during optimizations) + DIFlags::FlagZero, + ) + }, + LocalVariable => unsafe { + llvm::LLVMDIBuilderCreateAutoVariable( + DIB(self), + scope_metadata, + name.as_ptr(), + name.len(), + file_metadata, + loc.line, + type_metadata, + llvm::Bool::TRUE, // (preserve descriptor during optimizations) + DIFlags::FlagZero, + align.bits() as u32, + ) + }, } } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index cc1d504b430..7e1e49310f6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -28,7 +28,7 @@ pub(crate) fn create_DIArray<'ll>( builder: &DIBuilder<'ll>, arr: &[Option<&'ll DIDescriptor>], ) -> &'ll DIArray { - unsafe { llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) } + unsafe { llvm::LLVMDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len()) } } #[inline] diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 960a895a203..36cdb498839 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -76,7 +76,7 @@ pub(crate) fn declare_raw_fn<'ll, 'tcx>( attrs.push(llvm::AttributeKind::NoRedZone.create_attr(cx.llcx)); } - attrs.extend(attributes::non_lazy_bind_attr(cx)); + attrs.extend(attributes::non_lazy_bind_attr(cx, cx.tcx.sess)); attributes::apply_to_llfn(llfn, Function, &attrs); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e7f4a357048..467655b0bfc 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -18,7 +18,6 @@ use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate}; use rustc_target::callconv::PassMode; -use rustc_target::spec::PanicStrategy; use tracing::debug; use crate::abi::FnAbiLlvmExt; @@ -298,7 +297,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let align = if name == sym::unaligned_volatile_load { 1 } else { - result.layout.align.abi.bytes() as u32 + result.layout.align.bytes() as u32 }; unsafe { llvm::LLVMSetAlignment(load, align); @@ -674,7 +673,7 @@ fn catch_unwind_intrinsic<'ll, 'tcx>( catch_func: &'ll Value, dest: PlaceRef<'tcx, &'ll Value>, ) { - if bx.sess().panic_strategy() == PanicStrategy::Abort { + if !bx.sess().panic_strategy().unwinds() { let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); bx.call(try_func_ty, None, None, try_func, &[data], None, None); // Return 0 unconditionally from the intrinsic call; @@ -1048,7 +1047,7 @@ fn codegen_emcc_try<'ll, 'tcx>( // create an alloca and pass a pointer to that. let ptr_size = bx.tcx().data_layout.pointer_size(); let ptr_align = bx.tcx().data_layout.pointer_align().abi; - let i8_align = bx.tcx().data_layout.i8_align.abi; + let i8_align = bx.tcx().data_layout.i8_align; // Required in order for there to be no padding between the fields. assert!(i8_align <= ptr_align); let catch_data = bx.alloca(2 * ptr_size, ptr_align); @@ -1213,6 +1212,9 @@ fn codegen_autodiff<'ll, 'tcx>( &mut diff_attrs.input_activity, ); + let fnc_tree = + rustc_middle::ty::fnc_typetrees(tcx, fn_source.ty(tcx, TypingEnv::fully_monomorphized())); + // Build body generate_enzyme_call( bx, @@ -1223,6 +1225,7 @@ fn codegen_autodiff<'ll, 'tcx>( &val_arr, diff_attrs.clone(), result, + fnc_tree, ); } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 13bdb7cb1a2..2405a25c702 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -68,6 +68,7 @@ mod llvm_util; mod mono_item; mod type_; mod type_of; +mod typetree; mod va_arg; mod value; @@ -231,6 +232,10 @@ impl CodegenBackend for LlvmCodegenBackend { crate::DEFAULT_LOCALE_RESOURCE } + fn name(&self) -> &'static str { + "llvm" + } + fn init(&self, sess: &Session) { llvm_util::init(sess); // Make sure llvm is inited } @@ -349,7 +354,14 @@ impl CodegenBackend for LlvmCodegenBackend { // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, metadata, outputs); + link_binary( + sess, + &LlvmArchiveBuilderBuilder, + codegen_results, + metadata, + outputs, + self.name(), + ); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 695435eb6da..e63043b2122 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -3,9 +3,36 @@ use libc::{c_char, c_uint}; use super::MetadataKindId; -use super::ffi::{AttributeKind, BasicBlock, Metadata, Module, Type, Value}; +use super::ffi::{AttributeKind, BasicBlock, Context, Metadata, Module, Type, Value}; use crate::llvm::{Bool, Builder}; +// TypeTree types +pub(crate) type CTypeTreeRef = *mut EnzymeTypeTree; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub(crate) struct EnzymeTypeTree { + _unused: [u8; 0], +} + +#[repr(u32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[allow(non_camel_case_types)] +pub(crate) enum CConcreteType { + DT_Anything = 0, + DT_Integer = 1, + DT_Pointer = 2, + DT_Half = 3, + DT_Float = 4, + DT_Double = 5, + DT_Unknown = 6, + DT_FP128 = 9, +} + +pub(crate) struct TypeTree { + pub(crate) inner: CTypeTreeRef, +} + #[link(name = "llvm-wrapper", kind = "static")] unsafe extern "C" { // Enzyme @@ -68,10 +95,40 @@ pub(crate) mod Enzyme_AD { use libc::c_void; + use super::{CConcreteType, CTypeTreeRef, Context}; + unsafe extern "C" { pub(crate) fn EnzymeSetCLBool(arg1: *mut ::std::os::raw::c_void, arg2: u8); pub(crate) fn EnzymeSetCLString(arg1: *mut ::std::os::raw::c_void, arg2: *const c_char); } + + // TypeTree functions + unsafe extern "C" { + pub(crate) fn EnzymeNewTypeTree() -> CTypeTreeRef; + pub(crate) fn EnzymeNewTypeTreeCT(arg1: CConcreteType, ctx: &Context) -> CTypeTreeRef; + pub(crate) fn EnzymeNewTypeTreeTR(arg1: CTypeTreeRef) -> CTypeTreeRef; + pub(crate) fn EnzymeFreeTypeTree(CTT: CTypeTreeRef); + pub(crate) fn EnzymeMergeTypeTree(arg1: CTypeTreeRef, arg2: CTypeTreeRef) -> bool; + pub(crate) fn EnzymeTypeTreeOnlyEq(arg1: CTypeTreeRef, pos: i64); + pub(crate) fn EnzymeTypeTreeData0Eq(arg1: CTypeTreeRef); + pub(crate) fn EnzymeTypeTreeShiftIndiciesEq( + arg1: CTypeTreeRef, + data_layout: *const c_char, + offset: i64, + max_size: i64, + add_offset: u64, + ); + pub(crate) fn EnzymeTypeTreeInsertEq( + CTT: CTypeTreeRef, + indices: *const i64, + len: usize, + ct: CConcreteType, + ctx: &Context, + ); + pub(crate) fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char; + pub(crate) fn EnzymeTypeTreeToStringFree(arg1: *const c_char); + } + unsafe extern "C" { static mut EnzymePrintPerf: c_void; static mut EnzymePrintActivity: c_void; @@ -141,6 +198,67 @@ pub(crate) use self::Fallback_AD::*; pub(crate) mod Fallback_AD { #![allow(unused_variables)] + use libc::c_char; + + use super::{CConcreteType, CTypeTreeRef, Context}; + + // TypeTree function fallbacks + pub(crate) unsafe fn EnzymeNewTypeTree() -> CTypeTreeRef { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeNewTypeTreeCT(arg1: CConcreteType, ctx: &Context) -> CTypeTreeRef { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeNewTypeTreeTR(arg1: CTypeTreeRef) -> CTypeTreeRef { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeFreeTypeTree(CTT: CTypeTreeRef) { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeMergeTypeTree(arg1: CTypeTreeRef, arg2: CTypeTreeRef) -> bool { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeTypeTreeOnlyEq(arg1: CTypeTreeRef, pos: i64) { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeTypeTreeData0Eq(arg1: CTypeTreeRef) { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeTypeTreeShiftIndiciesEq( + arg1: CTypeTreeRef, + data_layout: *const c_char, + offset: i64, + max_size: i64, + add_offset: u64, + ) { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeTypeTreeInsertEq( + CTT: CTypeTreeRef, + indices: *const i64, + len: usize, + ct: CConcreteType, + ctx: &Context, + ) { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char { + unimplemented!() + } + + pub(crate) unsafe fn EnzymeTypeTreeToStringFree(arg1: *const c_char) { + unimplemented!() + } + pub(crate) fn set_inline(val: bool) { unimplemented!() } @@ -169,3 +287,89 @@ pub(crate) mod Fallback_AD { unimplemented!() } } + +impl TypeTree { + pub(crate) fn new() -> TypeTree { + let inner = unsafe { EnzymeNewTypeTree() }; + TypeTree { inner } + } + + pub(crate) fn from_type(t: CConcreteType, ctx: &Context) -> TypeTree { + let inner = unsafe { EnzymeNewTypeTreeCT(t, ctx) }; + TypeTree { inner } + } + + pub(crate) fn merge(self, other: Self) -> Self { + unsafe { + EnzymeMergeTypeTree(self.inner, other.inner); + } + drop(other); + self + } + + #[must_use] + pub(crate) fn shift( + self, + layout: &str, + offset: isize, + max_size: isize, + add_offset: usize, + ) -> Self { + let layout = std::ffi::CString::new(layout).unwrap(); + + unsafe { + EnzymeTypeTreeShiftIndiciesEq( + self.inner, + layout.as_ptr(), + offset as i64, + max_size as i64, + add_offset as u64, + ); + } + + self + } + + pub(crate) fn insert(&mut self, indices: &[i64], ct: CConcreteType, ctx: &Context) { + unsafe { + EnzymeTypeTreeInsertEq(self.inner, indices.as_ptr(), indices.len(), ct, ctx); + } + } +} + +impl Clone for TypeTree { + fn clone(&self) -> Self { + let inner = unsafe { EnzymeNewTypeTreeTR(self.inner) }; + TypeTree { inner } + } +} + +impl std::fmt::Display for TypeTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let ptr = unsafe { EnzymeTypeTreeToString(self.inner) }; + let cstr = unsafe { std::ffi::CStr::from_ptr(ptr) }; + match cstr.to_str() { + Ok(x) => write!(f, "{}", x)?, + Err(err) => write!(f, "could not parse: {}", err)?, + } + + // delete C string pointer + unsafe { + EnzymeTypeTreeToStringFree(ptr); + } + + Ok(()) + } +} + +impl std::fmt::Debug for TypeTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + <Self as std::fmt::Display>::fmt(self, f) + } +} + +impl Drop for TypeTree { + fn drop(&mut self) { + unsafe { EnzymeFreeTypeTree(self.inner) } + } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 9a86e4373d8..e9f92267a7d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -25,10 +25,11 @@ use rustc_target::spec::SymbolVisibility; use super::RustString; use super::debuginfo::{ DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags, - DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram, DISubrange, - DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind, + DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram, + DITemplateTypeParameter, DIType, DebugEmissionKind, DebugNameTableKind, }; use crate::llvm; +use crate::llvm::MetadataKindId; /// In the LLVM-C API, boolean values are passed as `typedef int LLVMBool`, /// which has a different ABI from Rust or C++ `bool`. @@ -513,31 +514,6 @@ pub(crate) enum FileType { ObjectFile, } -/// LLVMMetadataType -#[derive(Copy, Clone)] -#[repr(C)] -#[expect(dead_code, reason = "Some variants are unused, but are kept to match LLVM-C")] -pub(crate) enum MetadataType { - MD_dbg = 0, - MD_tbaa = 1, - MD_prof = 2, - MD_fpmath = 3, - MD_range = 4, - MD_tbaa_struct = 5, - MD_invariant_load = 6, - MD_alias_scope = 7, - MD_noalias = 8, - MD_nontemporal = 9, - MD_mem_parallel_loop_access = 10, - MD_nonnull = 11, - MD_unpredictable = 15, - MD_align = 17, - MD_type = 19, - MD_vcall_visibility = 28, - MD_noundef = 29, - MD_kcfi_type = 36, -} - /// Must match the layout of `LLVMInlineAsmDialect`. #[derive(Copy, Clone, PartialEq)] #[repr(C)] @@ -710,6 +686,7 @@ pub(crate) enum MemoryEffects { None, ReadOnly, InaccessibleMemOnly, + ReadOnlyNotPure, } /// LLVMOpcode @@ -806,6 +783,8 @@ unsafe extern "C" { pub(crate) type Metadata; pub(crate) type BasicBlock; pub(crate) type Comdat; + /// `&'ll DbgRecord` represents `LLVMDbgRecordRef`. + pub(crate) type DbgRecord; } #[repr(C)] pub(crate) struct Builder<'a>(InvariantOpaque<'a>); @@ -890,7 +869,6 @@ pub(crate) mod debuginfo { pub(crate) type DIVariable = DIDescriptor; pub(crate) type DIGlobalVariableExpression = DIDescriptor; pub(crate) type DIArray = DIDescriptor; - pub(crate) type DISubrange = DIDescriptor; pub(crate) type DIEnumerator = DIDescriptor; pub(crate) type DITemplateTypeParameter = DIDescriptor; @@ -1033,16 +1011,6 @@ pub(crate) type GetSymbolsCallback = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void; pub(crate) type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void; -#[derive(Copy, Clone)] -#[repr(transparent)] -pub(crate) struct MetadataKindId(c_uint); - -impl From<MetadataType> for MetadataKindId { - fn from(value: MetadataType) -> Self { - Self(value as c_uint) - } -} - unsafe extern "C" { // Create and destroy contexts. pub(crate) fn LLVMContextDispose(C: &'static mut Context); @@ -1052,6 +1020,8 @@ unsafe extern "C" { SLen: c_uint, ) -> MetadataKindId; + pub(crate) fn LLVMDisposeTargetMachine(T: ptr::NonNull<TargetMachine>); + // Create modules. pub(crate) fn LLVMModuleCreateWithNameInContext( ModuleID: *const c_char, @@ -1135,7 +1105,11 @@ unsafe extern "C" { pub(crate) fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t); pub(crate) fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value); pub(crate) safe fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: MetadataKindId, Node: &'a Value); - pub(crate) fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); + pub(crate) fn LLVMGlobalSetMetadata<'a>( + Val: &'a Value, + KindID: MetadataKindId, + Metadata: &'a Metadata, + ); pub(crate) safe fn LLVMValueAsMetadata(Node: &Value) -> &Metadata; // Operations on constants of any type @@ -1989,6 +1963,59 @@ unsafe extern "C" { Scope: Option<&'ll Metadata>, AlignInBits: u32, // (optional; default is 0) ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderGetOrCreateSubrange<'ll>( + Builder: &DIBuilder<'ll>, + LowerBound: i64, + Count: i64, + ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderGetOrCreateArray<'ll>( + Builder: &DIBuilder<'ll>, + Data: *const Option<&'ll Metadata>, + NumElements: size_t, + ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderCreateExpression<'ll>( + Builder: &DIBuilder<'ll>, + Addr: *const u64, + Length: size_t, + ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderInsertDeclareRecordAtEnd<'ll>( + Builder: &DIBuilder<'ll>, + Storage: &'ll Value, + VarInfo: &'ll Metadata, + Expr: &'ll Metadata, + DebugLoc: &'ll Metadata, + Block: &'ll BasicBlock, + ) -> &'ll DbgRecord; + + pub(crate) fn LLVMDIBuilderCreateAutoVariable<'ll>( + Builder: &DIBuilder<'ll>, + Scope: &'ll Metadata, + Name: *const c_uchar, // See "PTR_LEN_STR". + NameLen: size_t, + File: &'ll Metadata, + LineNo: c_uint, + Ty: &'ll Metadata, + AlwaysPreserve: llvm::Bool, // "If true, this descriptor will survive optimizations." + Flags: DIFlags, + AlignInBits: u32, + ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderCreateParameterVariable<'ll>( + Builder: &DIBuilder<'ll>, + Scope: &'ll Metadata, + Name: *const c_uchar, // See "PTR_LEN_STR". + NameLen: size_t, + ArgNo: c_uint, + File: &'ll Metadata, + LineNo: c_uint, + Ty: &'ll Metadata, + AlwaysPreserve: llvm::Bool, // "If true, this descriptor will survive optimizations." + Flags: DIFlags, + ) -> &'ll Metadata; } #[link(name = "llvm-wrapper", kind = "static")] @@ -2002,7 +2029,7 @@ unsafe extern "C" { // Operations on all values pub(crate) fn LLVMRustGlobalAddMetadata<'a>( Val: &'a Value, - KindID: c_uint, + KindID: MetadataKindId, Metadata: &'a Metadata, ); pub(crate) fn LLVMRustIsNonGVFunctionPointerTy(Val: &Value) -> bool; @@ -2199,8 +2226,11 @@ unsafe extern "C" { ConstraintsLen: size_t, ) -> bool; + /// A list of pointer-length strings is passed as two pointer-length slices, + /// one slice containing pointers and one slice containing their corresponding + /// lengths. The implementation will check that both slices have the same length. pub(crate) fn LLVMRustCoverageWriteFilenamesToBuffer( - Filenames: *const *const c_char, + Filenames: *const *const c_uchar, // See "PTR_LEN_STR". FilenamesLen: size_t, Lengths: *const size_t, LengthsLen: size_t, @@ -2223,18 +2253,25 @@ unsafe extern "C" { pub(crate) fn LLVMRustCoverageCreatePGOFuncNameVar( F: &Value, - FuncName: *const c_char, + FuncName: *const c_uchar, // See "PTR_LEN_STR". FuncNameLen: size_t, ) -> &Value; - pub(crate) fn LLVMRustCoverageHashBytes(Bytes: *const c_char, NumBytes: size_t) -> u64; - - pub(crate) fn LLVMRustCoverageWriteCovmapSectionNameToString(M: &Module, OutStr: &RustString); - - pub(crate) fn LLVMRustCoverageWriteCovfunSectionNameToString(M: &Module, OutStr: &RustString); + pub(crate) fn LLVMRustCoverageHashBytes( + Bytes: *const c_uchar, // See "PTR_LEN_STR". + NumBytes: size_t, + ) -> u64; - pub(crate) fn LLVMRustCoverageWriteCovmapVarNameToString(OutStr: &RustString); + pub(crate) safe fn LLVMRustCoverageWriteCovmapSectionNameToString( + M: &Module, + OutStr: &RustString, + ); + pub(crate) safe fn LLVMRustCoverageWriteCovfunSectionNameToString( + M: &Module, + OutStr: &RustString, + ); + pub(crate) safe fn LLVMRustCoverageWriteCovmapVarNameToString(OutStr: &RustString); - pub(crate) fn LLVMRustCoverageMappingVersion() -> u32; + pub(crate) safe fn LLVMRustCoverageMappingVersion() -> u32; pub(crate) fn LLVMRustDebugMetadataVersion() -> u32; pub(crate) fn LLVMRustVersionMajor() -> u32; pub(crate) fn LLVMRustVersionMinor() -> u32; @@ -2355,43 +2392,6 @@ unsafe extern "C" { AlignInBits: u32, ) -> &'a DIGlobalVariableExpression; - pub(crate) fn LLVMRustDIBuilderCreateVariable<'a>( - Builder: &DIBuilder<'a>, - Tag: c_uint, - Scope: &'a DIDescriptor, - Name: *const c_char, - NameLen: size_t, - File: &'a DIFile, - LineNo: c_uint, - Ty: &'a DIType, - AlwaysPreserve: bool, - Flags: DIFlags, - ArgNo: c_uint, - AlignInBits: u32, - ) -> &'a DIVariable; - - pub(crate) fn LLVMRustDIBuilderGetOrCreateSubrange<'a>( - Builder: &DIBuilder<'a>, - Lo: i64, - Count: i64, - ) -> &'a DISubrange; - - pub(crate) fn LLVMRustDIBuilderGetOrCreateArray<'a>( - Builder: &DIBuilder<'a>, - Ptr: *const Option<&'a DIDescriptor>, - Count: c_uint, - ) -> &'a DIArray; - - pub(crate) fn LLVMRustDIBuilderInsertDeclareAtEnd<'a>( - Builder: &DIBuilder<'a>, - Val: &'a Value, - VarInfo: &'a DIVariable, - AddrOps: *const u64, - AddrOpsCount: c_uint, - DL: &'a DILocation, - InsertAtEnd: &'a BasicBlock, - ); - pub(crate) fn LLVMRustDIBuilderCreateEnumerator<'a>( Builder: &DIBuilder<'a>, Name: *const c_char, @@ -2498,7 +2498,6 @@ unsafe extern "C" { UseWasmEH: bool, ) -> *mut TargetMachine; - pub(crate) fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine); pub(crate) fn LLVMRustAddLibraryInfo<'a>( PM: &PassManager<'a>, M: &'a Module, diff --git a/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs b/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs new file mode 100644 index 00000000000..a8a671b5c85 --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/llvm/metadata_kind.rs @@ -0,0 +1,71 @@ +use libc::c_uint; + +pub(crate) use self::fixed_kinds::*; + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub(crate) struct MetadataKindId(c_uint); + +macro_rules! declare_fixed_metadata_kinds { + ( + $( + FIXED_MD_KIND($variant:ident, $value:literal) + )* + ) => { + // Use a submodule to group all declarations into one `#[expect(..)]`. + #[expect(dead_code)] + mod fixed_kinds { + use super::MetadataKindId; + $( + #[expect(non_upper_case_globals)] + pub(crate) const $variant: MetadataKindId = MetadataKindId($value); + )* + } + }; +} + +// Must be kept in sync with the corresponding static assertions in `RustWrapper.cpp`. +declare_fixed_metadata_kinds! { + FIXED_MD_KIND(MD_dbg, 0) + FIXED_MD_KIND(MD_tbaa, 1) + FIXED_MD_KIND(MD_prof, 2) + FIXED_MD_KIND(MD_fpmath, 3) + FIXED_MD_KIND(MD_range, 4) + FIXED_MD_KIND(MD_tbaa_struct, 5) + FIXED_MD_KIND(MD_invariant_load, 6) + FIXED_MD_KIND(MD_alias_scope, 7) + FIXED_MD_KIND(MD_noalias, 8) + FIXED_MD_KIND(MD_nontemporal, 9) + FIXED_MD_KIND(MD_mem_parallel_loop_access, 10) + FIXED_MD_KIND(MD_nonnull, 11) + FIXED_MD_KIND(MD_dereferenceable, 12) + FIXED_MD_KIND(MD_dereferenceable_or_null, 13) + FIXED_MD_KIND(MD_make_implicit, 14) + FIXED_MD_KIND(MD_unpredictable, 15) + FIXED_MD_KIND(MD_invariant_group, 16) + FIXED_MD_KIND(MD_align, 17) + FIXED_MD_KIND(MD_loop, 18) + FIXED_MD_KIND(MD_type, 19) + FIXED_MD_KIND(MD_section_prefix, 20) + FIXED_MD_KIND(MD_absolute_symbol, 21) + FIXED_MD_KIND(MD_associated, 22) + FIXED_MD_KIND(MD_callees, 23) + FIXED_MD_KIND(MD_irr_loop, 24) + FIXED_MD_KIND(MD_access_group, 25) + FIXED_MD_KIND(MD_callback, 26) + FIXED_MD_KIND(MD_preserve_access_index, 27) + FIXED_MD_KIND(MD_vcall_visibility, 28) + FIXED_MD_KIND(MD_noundef, 29) + FIXED_MD_KIND(MD_annotation, 30) + FIXED_MD_KIND(MD_nosanitize, 31) + FIXED_MD_KIND(MD_func_sanitize, 32) + FIXED_MD_KIND(MD_exclude, 33) + FIXED_MD_KIND(MD_memprof, 34) + FIXED_MD_KIND(MD_callsite, 35) + FIXED_MD_KIND(MD_kcfi_type, 36) + FIXED_MD_KIND(MD_pcsections, 37) + FIXED_MD_KIND(MD_DIAssignID, 38) + FIXED_MD_KIND(MD_coro_outside_frame, 39) + FIXED_MD_KIND(MD_mmra, 40) + FIXED_MD_KIND(MD_noalias_addrspace, 41) +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 1115d82fa85..9a53dacb1df 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -11,13 +11,14 @@ use rustc_llvm::RustString; pub(crate) use self::CallConv::*; pub(crate) use self::CodeGenOptSize::*; -pub(crate) use self::MetadataType::*; pub(crate) use self::ffi::*; +pub(crate) use self::metadata_kind::*; use crate::common::AsCCharPtr; pub(crate) mod diagnostic; pub(crate) mod enzyme_ffi; mod ffi; +mod metadata_kind; pub(crate) use self::enzyme_ffi::*; diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 45c5c9aa551..3b920168e06 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -106,7 +106,7 @@ unsafe fn configure_llvm(sess: &Session) { if sess.target.os == "emscripten" && !sess.opts.unstable_opts.emscripten_wasm_eh - && sess.panic_strategy() == PanicStrategy::Unwind + && sess.panic_strategy().unwinds() { add("-enable-emscripten-cxx-exceptions", false); } diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 9ecaf5f24fe..1e5cf8374e3 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -302,26 +302,14 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { let typeid_metadata = self.create_metadata(typeid); - unsafe { - let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; - llvm::LLVMRustGlobalAddMetadata( - function, - llvm::MD_type as c_uint, - llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()), - ) - } + let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; + self.global_add_metadata_node(function, llvm::MD_type, &v); } fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { let typeid_metadata = self.create_metadata(typeid); - unsafe { - let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; - llvm::LLVMGlobalSetMetadata( - function, - llvm::MD_type as c_uint, - llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()), - ) - } + let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; + self.global_set_metadata_node(function, llvm::MD_type, &v); } fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> { @@ -329,32 +317,12 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { - let kcfi_type_metadata = self.const_u32(kcfi_typeid); - unsafe { - llvm::LLVMRustGlobalAddMetadata( - function, - llvm::MD_kcfi_type as c_uint, - llvm::LLVMMDNodeInContext2( - self.llcx, - &llvm::LLVMValueAsMetadata(kcfi_type_metadata), - 1, - ), - ) - } + let kcfi_type_metadata = [llvm::LLVMValueAsMetadata(self.const_u32(kcfi_typeid))]; + self.global_add_metadata_node(function, llvm::MD_kcfi_type, &kcfi_type_metadata); } fn set_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { - let kcfi_type_metadata = self.const_u32(kcfi_typeid); - unsafe { - llvm::LLVMGlobalSetMetadata( - function, - llvm::MD_kcfi_type as c_uint, - llvm::LLVMMDNodeInContext2( - self.llcx, - &llvm::LLVMValueAsMetadata(kcfi_type_metadata), - 1, - ), - ) - } + let kcfi_type_metadata = [llvm::LLVMValueAsMetadata(self.const_u32(kcfi_typeid))]; + self.global_set_metadata_node(function, llvm::MD_kcfi_type, &kcfi_type_metadata); } } diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs new file mode 100644 index 00000000000..7e263503700 --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/typetree.rs @@ -0,0 +1,122 @@ +use rustc_ast::expand::typetree::FncTree; +#[cfg(feature = "llvm_enzyme")] +use { + crate::attributes, + rustc_ast::expand::typetree::TypeTree as RustTypeTree, + std::ffi::{CString, c_char, c_uint}, +}; + +use crate::llvm::{self, Value}; + +#[cfg(feature = "llvm_enzyme")] +fn to_enzyme_typetree( + rust_typetree: RustTypeTree, + _data_layout: &str, + llcx: &llvm::Context, +) -> llvm::TypeTree { + let mut enzyme_tt = llvm::TypeTree::new(); + process_typetree_recursive(&mut enzyme_tt, &rust_typetree, &[], llcx); + enzyme_tt +} +#[cfg(feature = "llvm_enzyme")] +fn process_typetree_recursive( + enzyme_tt: &mut llvm::TypeTree, + rust_typetree: &RustTypeTree, + parent_indices: &[i64], + llcx: &llvm::Context, +) { + for rust_type in &rust_typetree.0 { + let concrete_type = match rust_type.kind { + rustc_ast::expand::typetree::Kind::Anything => llvm::CConcreteType::DT_Anything, + rustc_ast::expand::typetree::Kind::Integer => llvm::CConcreteType::DT_Integer, + rustc_ast::expand::typetree::Kind::Pointer => llvm::CConcreteType::DT_Pointer, + rustc_ast::expand::typetree::Kind::Half => llvm::CConcreteType::DT_Half, + rustc_ast::expand::typetree::Kind::Float => llvm::CConcreteType::DT_Float, + rustc_ast::expand::typetree::Kind::Double => llvm::CConcreteType::DT_Double, + rustc_ast::expand::typetree::Kind::F128 => llvm::CConcreteType::DT_FP128, + rustc_ast::expand::typetree::Kind::Unknown => llvm::CConcreteType::DT_Unknown, + }; + + let mut indices = parent_indices.to_vec(); + if !parent_indices.is_empty() { + indices.push(rust_type.offset as i64); + } else if rust_type.offset == -1 { + indices.push(-1); + } else { + indices.push(rust_type.offset as i64); + } + + enzyme_tt.insert(&indices, concrete_type, llcx); + + if rust_type.kind == rustc_ast::expand::typetree::Kind::Pointer + && !rust_type.child.0.is_empty() + { + process_typetree_recursive(enzyme_tt, &rust_type.child, &indices, llcx); + } + } +} + +#[cfg(feature = "llvm_enzyme")] +pub(crate) fn add_tt<'ll>( + llmod: &'ll llvm::Module, + llcx: &'ll llvm::Context, + fn_def: &'ll Value, + tt: FncTree, +) { + let inputs = tt.args; + let ret_tt: RustTypeTree = tt.ret; + + let llvm_data_layout: *const c_char = unsafe { llvm::LLVMGetDataLayoutStr(&*llmod) }; + let llvm_data_layout = + std::str::from_utf8(unsafe { std::ffi::CStr::from_ptr(llvm_data_layout) }.to_bytes()) + .expect("got a non-UTF8 data-layout from LLVM"); + + let attr_name = "enzyme_type"; + let c_attr_name = CString::new(attr_name).unwrap(); + + for (i, input) in inputs.iter().enumerate() { + unsafe { + let enzyme_tt = to_enzyme_typetree(input.clone(), llvm_data_layout, llcx); + let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner); + let c_str = std::ffi::CStr::from_ptr(c_str); + + let attr = llvm::LLVMCreateStringAttribute( + llcx, + c_attr_name.as_ptr(), + c_attr_name.as_bytes().len() as c_uint, + c_str.as_ptr(), + c_str.to_bytes().len() as c_uint, + ); + + attributes::apply_to_llfn(fn_def, llvm::AttributePlace::Argument(i as u32), &[attr]); + llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr()); + } + } + + unsafe { + let enzyme_tt = to_enzyme_typetree(ret_tt, llvm_data_layout, llcx); + let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner); + let c_str = std::ffi::CStr::from_ptr(c_str); + + let ret_attr = llvm::LLVMCreateStringAttribute( + llcx, + c_attr_name.as_ptr(), + c_attr_name.as_bytes().len() as c_uint, + c_str.as_ptr(), + c_str.to_bytes().len() as c_uint, + ); + + attributes::apply_to_llfn(fn_def, llvm::AttributePlace::ReturnValue, &[ret_attr]); + llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr()); + } +} + +#[cfg(not(feature = "llvm_enzyme"))] +pub(crate) fn add_tt<'ll>( + _llmod: &'ll llvm::Module, + _llcx: &'ll llvm::Context, + _fn_def: &'ll Value, + _tt: FncTree, +) { + unimplemented!() +} diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index ab08125217f..234366e491c 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -193,7 +193,7 @@ fn emit_aapcs_va_arg<'ll, 'tcx>( // the offset again. bx.switch_to_block(maybe_reg); - if gr_type && layout.align.abi.bytes() > 8 { + if gr_type && layout.align.bytes() > 8 { reg_off_v = bx.add(reg_off_v, bx.const_i32(15)); reg_off_v = bx.and(reg_off_v, bx.const_i32(-16)); } @@ -291,7 +291,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( bx.inbounds_ptradd(va_list_addr, bx.const_usize(1)) // fpr }; - let mut num_regs = bx.load(bx.type_i8(), num_regs_addr, dl.i8_align.abi); + let mut num_regs = bx.load(bx.type_i8(), num_regs_addr, dl.i8_align); // "Align" the register count when the type is passed as `i64`. if is_i64 || (is_f64 && is_soft_float_abi) { @@ -329,7 +329,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( // Increase the used-register count. let reg_incr = if is_i64 || (is_f64 && is_soft_float_abi) { 2 } else { 1 }; let new_num_regs = bx.add(num_regs, bx.cx.const_u8(reg_incr)); - bx.store(new_num_regs, num_regs_addr, dl.i8_align.abi); + bx.store(new_num_regs, num_regs_addr, dl.i8_align); bx.br(end); @@ -339,7 +339,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( let mem_addr = { bx.switch_to_block(in_mem); - bx.store(bx.const_u8(max_regs), num_regs_addr, dl.i8_align.abi); + bx.store(bx.const_u8(max_regs), num_regs_addr, dl.i8_align); // Everything in the overflow area is rounded up to a size of at least 4. let overflow_area_align = Align::from_bytes(4).unwrap(); @@ -738,6 +738,7 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>( src_align, bx.const_u32(layout.layout.size().bytes() as u32), MemFlags::empty(), + None, ); tmp } else { @@ -760,7 +761,7 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>( // byte boundary if alignment needed by type exceeds 8 byte boundary. // It isn't stated explicitly in the standard, but in practice we use // alignment greater than 16 where necessary. - if layout.layout.align.abi.bytes() > 8 { + if layout.layout.align.bytes() > 8 { unreachable!("all instances of VaArgSafe have an alignment <= 8"); } @@ -813,7 +814,7 @@ fn emit_xtensa_va_arg<'ll, 'tcx>( let va_ndx_offset = va_reg_offset + 4; let offset_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(va_ndx_offset)); - let offset = bx.load(bx.type_i32(), offset_ptr, bx.tcx().data_layout.i32_align.abi); + let offset = bx.load(bx.type_i32(), offset_ptr, bx.tcx().data_layout.i32_align); let offset = round_up_to_alignment(bx, offset, layout.align.abi); let slot_size = layout.size.align_to(Align::from_bytes(4).unwrap()).bytes() as i32; diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 5462163f4ff..9c5a3d839ce 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -8,9 +8,7 @@ edition = "2024" ar_archive_writer = "0.5" bitflags = "2.4.1" bstr = "1.11.3" -# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version -# per crate", so if you change this, you need to also change it in `rustc_llvm` and `rustc_windows_rc`. -cc = "=1.2.16" +find-msvc-tools = "0.1.2" itertools = "0.12" pathdiff = "0.2.0" regex = "1.4" diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 48b01ea2df1..db2f2dd65b0 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -9,7 +9,7 @@ use std::path::{Path, PathBuf}; use std::process::{Output, Stdio}; use std::{env, fmt, fs, io, mem, str}; -use cc::windows_registry; +use find_msvc_tools; use itertools::Itertools; use regex::Regex; use rustc_arena::TypedArena; @@ -47,8 +47,8 @@ use rustc_span::Symbol; use rustc_target::spec::crt_objects::CrtObjects; use rustc_target::spec::{ BinaryFormat, Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, - LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, - SanitizerSet, SplitDebuginfo, + LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, RelocModel, RelroLevel, SanitizerSet, + SplitDebuginfo, }; use tracing::{debug, info, warn}; @@ -79,6 +79,7 @@ pub fn link_binary( codegen_results: CodegenResults, metadata: EncodedMetadata, outputs: &OutputFilenames, + codegen_backend: &'static str, ) { let _timer = sess.timer("link_binary"); let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); @@ -154,6 +155,7 @@ pub fn link_binary( &codegen_results, &metadata, path.as_ref(), + codegen_backend, ); } } @@ -680,6 +682,7 @@ fn link_natively( codegen_results: &CodegenResults, metadata: &EncodedMetadata, tmpdir: &Path, + codegen_backend: &'static str, ) { info!("preparing {:?} to {:?}", crate_type, out_filename); let (linker_path, flavor) = linker_and_flavor(sess); @@ -705,6 +708,7 @@ fn link_natively( codegen_results, metadata, self_contained_components, + codegen_backend, ); linker::disable_localization(&mut cmd); @@ -877,9 +881,9 @@ fn link_natively( // All Microsoft `link.exe` linking ror codes are // four digit numbers in the range 1000 to 9999 inclusive if is_msvc_link_exe && (code < 1000 || code > 9999) { - let is_vs_installed = windows_registry::find_vs_version().is_ok(); + let is_vs_installed = find_msvc_tools::find_vs_version().is_ok(); let has_linker = - windows_registry::find_tool(&sess.target.arch, "link.exe").is_some(); + find_msvc_tools::find_tool(&sess.target.arch, "link.exe").is_some(); sess.dcx().emit_note(errors::LinkExeUnexpectedError); @@ -2208,6 +2212,7 @@ fn linker_with_args( codegen_results: &CodegenResults, metadata: &EncodedMetadata, self_contained_components: LinkSelfContainedComponents, + codegen_backend: &'static str, ) -> Command { let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled(); let cmd = &mut *super::linker::get_linker( @@ -2216,6 +2221,7 @@ fn linker_with_args( flavor, self_contained_components.are_any_components_enabled(), &codegen_results.crate_info.target_cpu, + codegen_backend, ); let link_output_kind = link_output_kind(sess, crate_type); @@ -2512,10 +2518,10 @@ fn add_order_independent_options( if sess.target.os == "emscripten" { cmd.cc_arg(if sess.opts.unstable_opts.emscripten_wasm_eh { "-fwasm-exceptions" - } else if sess.panic_strategy() == PanicStrategy::Abort { - "-sDISABLE_EXCEPTION_CATCHING=1" - } else { + } else if sess.panic_strategy().unwinds() { "-sDISABLE_EXCEPTION_CATCHING=0" + } else { + "-sDISABLE_EXCEPTION_CATCHING=1" }); } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index a2efd420a32..ac123143738 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -4,7 +4,7 @@ use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::{env, io, iter, mem, str}; -use cc::windows_registry; +use find_msvc_tools; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::{ find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library, @@ -17,7 +17,6 @@ use rustc_middle::middle::exported_symbols::{ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; -use rustc_span::sym; use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld}; use tracing::{debug, warn}; @@ -52,8 +51,9 @@ pub(crate) fn get_linker<'a>( flavor: LinkerFlavor, self_contained: bool, target_cpu: &'a str, + codegen_backend: &'static str, ) -> Box<dyn Linker + 'a> { - let msvc_tool = windows_registry::find_tool(&sess.target.arch, "link.exe"); + let msvc_tool = find_msvc_tools::find_tool(&sess.target.arch, "link.exe"); // If our linker looks like a batch script on Windows then to execute this // we'll need to spawn `cmd` explicitly. This is primarily done to handle @@ -117,7 +117,6 @@ pub(crate) fn get_linker<'a>( if sess.target.is_like_msvc && let Some(ref tool) = msvc_tool { - cmd.args(tool.args()); for (k, v) in tool.env() { if k == "PATH" { new_path.extend(env::split_paths(v)); @@ -155,6 +154,7 @@ pub(crate) fn get_linker<'a>( is_ld: cc == Cc::No, is_gnu: flavor.is_gnu(), uses_lld: flavor.uses_lld(), + codegen_backend, }) as Box<dyn Linker>, LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>, LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>, @@ -368,6 +368,7 @@ struct GccLinker<'a> { is_ld: bool, is_gnu: bool, uses_lld: bool, + codegen_backend: &'static str, } impl<'a> GccLinker<'a> { @@ -424,9 +425,15 @@ impl<'a> GccLinker<'a> { if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use { self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display())); }; + let prefix = if self.codegen_backend == "gcc" { + // The GCC linker plugin requires a leading dash. + "-" + } else { + "" + }; self.link_args(&[ - &format!("-plugin-opt={opt_level}"), - &format!("-plugin-opt=mcpu={}", self.target_cpu), + &format!("-plugin-opt={prefix}{opt_level}"), + &format!("-plugin-opt={prefix}mcpu={}", self.target_cpu), ]); } @@ -845,6 +852,11 @@ impl<'a> Linker for GccLinker<'a> { self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error }); } self.link_arg("--dynamic-list").link_arg(path); + } else if self.sess.target.is_like_wasm { + self.link_arg("--no-export-dynamic"); + for (sym, _) in symbols { + self.link_arg("--export").link_arg(sym); + } } else { // Write an LD version script let res: io::Result<()> = try { @@ -1311,37 +1323,7 @@ struct WasmLd<'a> { impl<'a> WasmLd<'a> { fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> { - // If the atomics feature is enabled for wasm then we need a whole bunch - // of flags: - // - // * `--shared-memory` - the link won't even succeed without this, flags - // the one linear memory as `shared` - // - // * `--max-memory=1G` - when specifying a shared memory this must also - // be specified. We conservatively choose 1GB but users should be able - // to override this with `-C link-arg`. - // - // * `--import-memory` - it doesn't make much sense for memory to be - // exported in a threaded module because typically you're - // sharing memory and instantiating the module multiple times. As a - // result if it were exported then we'd just have no sharing. - // - // On wasm32-unknown-unknown, we also export symbols for glue code to use: - // * `--export=*tls*` - when `#[thread_local]` symbols are used these - // symbols are how the TLS segments are initialized and configured. - let mut wasm_ld = WasmLd { cmd, sess }; - if sess.target_features.contains(&sym::atomics) { - wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]); - if sess.target.os == "unknown" || sess.target.os == "none" { - wasm_ld.link_args(&[ - "--export=__wasm_init_tls", - "--export=__tls_size", - "--export=__tls_align", - "--export=__tls_base", - ]); - } - } - wasm_ld + WasmLd { cmd, sess } } } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 68a2f43ec67..422b06350e1 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -11,12 +11,12 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; use rustc_data_structures::unord::UnordMap; -use rustc_hir::attrs::OptimizeAttr; +use rustc_hir::attrs::{DebuggerVisualizerType, OptimizeAttr}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ItemId, Target}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::exported_symbols::{self, SymbolExportKind}; use rustc_middle::middle::lang_items; diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index c2c023af090..45bc5451946 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -150,10 +150,6 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx> { layout.for_variant(self.fx.cx, vidx) } - mir::PlaceElem::Subtype(subtype_ty) => { - let subtype_ty = self.fx.monomorphize(subtype_ty); - self.fx.cx.layout_of(subtype_ty) - } _ => { self.locals[place_ref.local] = LocalKind::Memory; return; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1b218a0d339..b2dc4fe32b0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1626,6 +1626,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { align, bx.const_usize(copy_bytes), MemFlags::empty(), + None, ); // ...and then load it with the ABI type. llval = load_cast(bx, cast, llscratch, scratch_align); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 3c667b8e882..befa00c6861 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -30,7 +30,7 @@ fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if allow_overlap { bx.memmove(dst, align, src, align, size, flags); } else { - bx.memcpy(dst, align, src, align, size, flags); + bx.memcpy(dst, align, src, align, size, flags, None); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index d851c332980..5f7f87fc692 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -956,11 +956,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let layout = o.layout.for_variant(bx.cx(), vidx); o = OperandRef { val: o.val, layout } } - mir::PlaceElem::Subtype(subtype_ty) => { - let subtype_ty = self.monomorphize(subtype_ty); - let layout = self.cx.layout_of(subtype_ty); - o = OperandRef { val: o.val, layout } - } _ => return None, } } diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 0090be9fdef..50f56f913a5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -347,7 +347,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::ProjectionElem::OpaqueCast(ty) => { bug!("encountered OpaqueCast({ty}) in codegen") } - mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)), mir::ProjectionElem::UnwrapUnsafeBinder(ty) => { cg_base.project_type(bx, self.monomorphize(ty)) } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 2602bf82095..d629003bff5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -86,7 +86,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => { + mir::Rvalue::Cast( + mir::CastKind::Transmute | mir::CastKind::Subtype, + ref operand, + _ty, + ) => { let src = self.codegen_operand(bx, operand); self.codegen_transmute(bx, src, dest); } @@ -486,7 +490,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("Unsupported cast of {operand:?} to {cast:?}"); }) } - mir::CastKind::Transmute => { + mir::CastKind::Transmute | mir::CastKind::Subtype => { self.codegen_transmute_operand(bx, operand, cast) } }; @@ -617,7 +621,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::NullOp::AlignOf => { assert!(bx.cx().type_is_sized(ty)); - let val = layout.align.abi.bytes(); + let val = layout.align.bytes(); bx.cx().const_usize(val) } mir::NullOp::OffsetOf(fields) => { diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index f164e0f9123..0a50d7f18db 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -90,7 +90,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let align = pointee_layout.align; let dst = dst_val.immediate(); let src = src_val.immediate(); - bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty()); + bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty(), None); } mir::StatementKind::FakeRead(..) | mir::StatementKind::Retag { .. } diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 577012151e4..e1bd8014d7a 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -21,7 +21,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( trace!("size_and_align_of_dst(ty={}, info={:?}): layout: {:?}", t, info, layout); if layout.is_sized() { let size = bx.const_usize(layout.size.bytes()); - let align = bx.const_usize(layout.align.abi.bytes()); + let align = bx.const_usize(layout.align.bytes()); return (size, align); } match t.kind() { @@ -49,7 +49,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // All slice sizes must fit into `isize`, so this multiplication cannot // wrap -- neither signed nor unsigned. bx.unchecked_sumul(info.unwrap(), bx.const_usize(unit.size.bytes())), - bx.const_usize(unit.align.abi.bytes()), + bx.const_usize(unit.align.bytes()), ) } ty::Foreign(_) => { @@ -82,7 +82,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // This function does not return so we can now return whatever we want. let size = bx.const_usize(layout.size.bytes()); - let align = bx.const_usize(layout.align.abi.bytes()); + let align = bx.const_usize(layout.align.bytes()); (size, align) } ty::Adt(..) | ty::Tuple(..) => { @@ -94,7 +94,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let i = layout.fields.count() - 1; let unsized_offset_unadjusted = layout.fields.offset(i).bytes(); - let sized_align = layout.align.abi.bytes(); + let sized_align = layout.align.bytes(); debug!( "DST {} offset of dyn field: {}, statically sized align: {}", t, unsized_offset_unadjusted, sized_align diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 29ec7eb1da3..2400160075e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -41,6 +41,8 @@ pub trait CodegenBackend { /// Called before `init` so that all other functions are able to emit translatable diagnostics. fn locale_resource(&self) -> &'static str; + fn name(&self) -> &'static str; + fn init(&self, _sess: &Session) {} fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {} @@ -96,7 +98,14 @@ pub trait CodegenBackend { metadata: EncodedMetadata, outputs: &OutputFilenames, ) { - link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, metadata, outputs); + link_binary( + sess, + &ArArchiveBuilderBuilder, + codegen_results, + metadata, + outputs, + self.name(), + ); } } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 4a5694e97fa..60296e36e0c 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -451,6 +451,7 @@ pub trait BuilderMethods<'a, 'tcx>: src_align: Align, size: Self::Value, flags: MemFlags, + tt: Option<rustc_ast::expand::typetree::FncTree>, ); fn memmove( &mut self, @@ -507,7 +508,7 @@ pub trait BuilderMethods<'a, 'tcx>: temp.val.store_with_flags(self, dst.with_type(layout), flags); } else if !layout.is_zst() { let bytes = self.const_usize(layout.size.bytes()); - self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags); + self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags, None); } } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 700d7c26752..010ffa60c7a 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -476,14 +476,20 @@ const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wid const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in `const` value const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!` -const_eval_validation_null_box = {$front_matter}: encountered a null box +const_eval_validation_null_box = {$front_matter}: encountered a {$maybe -> + [true] maybe-null + *[false] null + } box const_eval_validation_null_fn_ptr = {$front_matter}: encountered a null function pointer -const_eval_validation_null_ref = {$front_matter}: encountered a null reference -const_eval_validation_nullable_ptr_out_of_range = {$front_matter}: encountered a potentially null pointer, but expected something that cannot possibly fail to be {$in_range} +const_eval_validation_null_ref = {$front_matter}: encountered a {$maybe -> + [true] maybe-null + *[false] null + } reference +const_eval_validation_nonnull_ptr_out_of_range = {$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range} const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected} -const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range} +const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer with unknown absolute address, but expected something that is definitely {$in_range} const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty} const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes}) const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes}) diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 34d1fdd8c86..8a6827bca2b 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -293,7 +293,6 @@ where ProjectionElem::Index(index) if in_local(index) => return true, ProjectionElem::Deref - | ProjectionElem::Subtype(_) | ProjectionElem::Field(_, _) | ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 2d412ee5ec2..d352a638424 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -668,7 +668,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { MutableRefInConst => const_eval_validation_mutable_ref_in_const, NullFnPtr => const_eval_validation_null_fn_ptr, NeverVal => const_eval_validation_never_val, - NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range, + NonnullPtrMaybeNull { .. } => const_eval_validation_nonnull_ptr_out_of_range, PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range, OutOfRange { .. } => const_eval_validation_out_of_range, UnsafeCellInImmutable => const_eval_validation_unsafe_cell, @@ -696,8 +696,8 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { } UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box, - NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box, - NullPtr { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_null_ref, + NullPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_null_box, + NullPtr { ptr_kind: PointerKind::Ref(_), .. } => const_eval_validation_null_ref, DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => { const_eval_validation_dangling_box_no_provenance } @@ -804,9 +804,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { | InvalidFnPtr { value } => { err.arg("value", value); } - NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => { - add_range_arg(range, max_value, err) - } + PtrOutOfRange { range, max_value } => add_range_arg(range, max_value, err), OutOfRange { range, max_value, value } => { err.arg("value", value); add_range_arg(range, max_value, err); @@ -822,10 +820,13 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { err.arg("vtable_dyn_type", vtable_dyn_type.to_string()); err.arg("expected_dyn_type", expected_dyn_type.to_string()); } - NullPtr { .. } - | MutableRefToImmutable + NullPtr { maybe, .. } => { + err.arg("maybe", maybe); + } + MutableRefToImmutable | MutableRefInConst | NullFnPtr + | NonnullPtrMaybeNull | NeverVal | UnsafeCellInImmutable | InvalidMetaSliceTooLarge { .. } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 0075740e031..b058d4b8ad4 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -133,7 +133,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - CastKind::Transmute => { + CastKind::Transmute | CastKind::Subtype => { assert!(src.layout.is_sized()); assert!(dest.layout.is_sized()); assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely... diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 418dd658121..785978b4d71 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -636,6 +636,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { dest, rustc_apfloat::Round::NearestTiesToEven, )?, + sym::fmaf16 => self.fma_intrinsic::<Half>(args, dest)?, + sym::fmaf32 => self.fma_intrinsic::<Single>(args, dest)?, + sym::fmaf64 => self.fma_intrinsic::<Double>(args, dest)?, + sym::fmaf128 => self.fma_intrinsic::<Quad>(args, dest)?, + sym::fmuladdf16 => self.float_muladd_intrinsic::<Half>(args, dest)?, + sym::fmuladdf32 => self.float_muladd_intrinsic::<Single>(args, dest)?, + sym::fmuladdf64 => self.float_muladd_intrinsic::<Double>(args, dest)?, + sym::fmuladdf128 => self.float_muladd_intrinsic::<Quad>(args, dest)?, // Unsupported intrinsic: skip the return_to_block below. _ => return interp_ok(false), @@ -1035,4 +1043,42 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(res, dest)?; interp_ok(()) } + + fn fma_intrinsic<F>( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &PlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>, + { + let a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + let c: F = self.read_scalar(&args[2])?.to_float()?; + + let res = a.mul_add(b, c).value; + let res = self.adjust_nan(res, &[a, b, c]); + self.write_scalar(res, dest)?; + interp_ok(()) + } + + fn float_muladd_intrinsic<F>( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &PlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>, + { + let a: F = self.read_scalar(&args[0])?.to_float()?; + let b: F = self.read_scalar(&args[1])?.to_float()?; + let c: F = self.read_scalar(&args[2])?.to_float()?; + + let fuse = M::float_fuse_mul_add(self); + + let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value }; + let res = self.adjust_nan(res, &[a, b, c]); + self.write_scalar(res, dest)?; + interp_ok(()) + } } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index e22629993fb..1725635e0b4 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -289,6 +289,9 @@ pub trait Machine<'tcx>: Sized { a } + /// Determines whether the `fmuladd` intrinsics fuse the multiply-add or use separate operations. + fn float_fuse_mul_add(_ecx: &mut InterpCx<'tcx, Self>) -> bool; + /// Called before a basic block terminator is executed. #[inline] fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { @@ -673,6 +676,11 @@ pub macro compile_time_machine(<$tcx: lifetime>) { } #[inline(always)] + fn float_fuse_mul_add(_ecx: &mut InterpCx<$tcx, Self>) -> bool { + true + } + + #[inline(always)] fn ub_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> { // We can't look at `tcx.sess` here as that can differ across crates, which can lead to // unsound differences in evaluating the same constant at different instantiation sites. diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 74f8a0a7b09..f0819423aa0 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -528,7 +528,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !layout.is_sized() { span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`"); } - let val = layout.align.abi.bytes(); + let val = layout.align.bytes(); ImmTy::from_uint(val, usize_layout()) } OffsetOf(fields) => { diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index d05871bfc77..2fd1657f6ba 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -395,8 +395,6 @@ where span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck") } UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?, - // We don't want anything happening here, this is here as a dummy. - Subtype(_) => base.transmute(base.layout(), self)?, Field(field, _) => self.project_field(base, field)?, Downcast(_, variant) => self.project_downcast(base, variant)?, Deref => self.deref_pointer(&base.to_op(self)?)?.into(), diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 9adc3fa4631..5f088fe37e8 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -511,7 +511,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message ), self.path, - Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind }, + Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind, maybe: false }, Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance { ptr_kind, // FIXME this says "null pointer" when null but we need translate @@ -538,8 +538,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { ); // Make sure this is non-null. We checked dereferenceability above, but if `size` is zero // that does not imply non-null. - if self.ecx.scalar_may_be_null(Scalar::from_maybe_pointer(place.ptr(), self.ecx))? { - throw_validation_failure!(self.path, NullPtr { ptr_kind }) + let scalar = Scalar::from_maybe_pointer(place.ptr(), self.ecx); + if self.ecx.scalar_may_be_null(scalar)? { + let maybe = !M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..)); + throw_validation_failure!(self.path, NullPtr { ptr_kind, maybe }) } // Do not allow references to uninhabited types. if place.layout.is_uninhabited() { @@ -757,6 +759,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } else { // Otherwise (for standalone Miri), we have to still check it to be non-null. if self.ecx.scalar_may_be_null(scalar)? { + let maybe = + !M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..)); + // This can't be a "maybe-null" pointer since the check for this being + // a fn ptr at all already ensures that the pointer is inbounds. + assert!(!maybe); throw_validation_failure!(self.path, NullFnPtr); } } @@ -819,10 +826,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if start == 1 && end == max_value { // Only null is the niche. So make sure the ptr is NOT null. if self.ecx.scalar_may_be_null(scalar)? { - throw_validation_failure!( - self.path, - NullablePtrOutOfRange { range: valid_range, max_value } - ) + throw_validation_failure!(self.path, NonnullPtrMaybeNull) } else { return interp_ok(()); } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 8ace560d85d..9c0ec4e51a0 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,7 +1,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![cfg_attr(bootstrap, feature(strict_overflow_ops))] #![doc(rust_logo)] #![feature(array_try_map)] #![feature(assert_matches)] diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs index 9507b24f603..9aafc7efd8a 100644 --- a/compiler/rustc_const_eval/src/util/alignment.rs +++ b/compiler/rustc_const_eval/src/util/alignment.rs @@ -37,7 +37,7 @@ where debug!( "is_disaligned({:?}) - align = {}, packed = {}; not disaligned", place, - layout.align.abi.bytes(), + layout.align.bytes(), pack.bytes() ); false diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 5249b32eca4..4e7c8310007 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -61,7 +61,7 @@ pub(crate) fn const_caller_location_provider( trace!("const_caller_location: {}:{}:{}", file, line, col); let mut ecx = mk_eval_cx_to_read_const_val( tcx, - rustc_span::DUMMY_SP, // FIXME: use a proper span here? + rustc_span::DUMMY_SP, // This interpreter cannot fail, so the span is irrelevant. ty::TypingEnv::fully_monomorphized(), CanAccessMutGlobal::No, ); diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index b1f29598750..1dea7e4252d 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -129,7 +129,7 @@ fn check_validity_requirement_lax<'tcx>( if let Some(pointee) = this.ty.builtin_deref(false) { let pointee = cx.layout_of(pointee)?; // We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied. - if pointee.align.abi.bytes() > 1 { + if pointee.align.bytes() > 1 { // 0x01-filling is not aligned. return Ok(false); } diff --git a/compiler/rustc_error_codes/src/error_codes/E0608.md b/compiler/rustc_error_codes/src/error_codes/E0608.md index d0ebc3a26f0..3c29484f575 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0608.md +++ b/compiler/rustc_error_codes/src/error_codes/E0608.md @@ -1,5 +1,5 @@ -An attempt to use index on a type which doesn't implement the `std::ops::Index` -trait was performed. +Attempted to index a value whose type doesn't implement the +`std::ops::Index` trait. Erroneous code example: @@ -7,8 +7,8 @@ Erroneous code example: 0u8[2]; // error: cannot index into a value of type `u8` ``` -To be able to index into a type it needs to implement the `std::ops::Index` -trait. Example: +Only values with types that implement the `std::ops::Index` trait +can be indexed with square brackets. Example: ``` let v: Vec<u8> = vec![0, 1, 2, 3]; @@ -16,3 +16,10 @@ let v: Vec<u8> = vec![0, 1, 2, 3]; // The `Vec` type implements the `Index` trait so you can do: println!("{}", v[2]); ``` + +Tuples and structs are indexed with dot (`.`), not with brackets (`[]`), +and tuple element names are their positions: +```ignore(pseudo code) +// this (pseudo code) expression is true for any tuple: +tuple == (tuple.0, tuple.1, ...) +``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0719.md b/compiler/rustc_error_codes/src/error_codes/E0719.md index cd981db1058..6aec38b42a3 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0719.md +++ b/compiler/rustc_error_codes/src/error_codes/E0719.md @@ -1,4 +1,4 @@ -An associated type value was specified more than once. +An associated item was specified more than once in a trait object. Erroneous code example: @@ -7,21 +7,15 @@ trait FooTrait {} trait BarTrait {} // error: associated type `Item` in trait `Iterator` is specified twice -struct Foo<T: Iterator<Item: FooTrait, Item: BarTrait>> { f: T } +type Foo = dyn Iterator<Item = u32, Item = u32>; ``` -`Item` in trait `Iterator` cannot be specified multiple times for struct `Foo`. -To fix this, create a new trait that is a combination of the desired traits and -specify the associated type with the new trait. +To fix this, remove the duplicate specifier: Corrected example: ``` -trait FooTrait {} -trait BarTrait {} -trait FooBarTrait: FooTrait + BarTrait {} - -struct Foo<T: Iterator<Item: FooBarTrait>> { f: T } // ok! +type Foo = dyn Iterator<Item = u32>; // ok! ``` For more information about associated types, see [the book][bk-at]. For more diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 88f88f30a8c..810a5a21a05 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -10,7 +10,7 @@ use rustc_ast::attr::{AttributeExt, MarkedAttrs}; use rustc_ast::token::MetaVarKind; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; -use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; +use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind, Safety}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync; use rustc_errors::{BufferedEarlyLint, DiagCtxtHandle, ErrorGuaranteed, PResult}; @@ -324,16 +324,16 @@ pub trait BangProcMacro { impl<F> BangProcMacro for F where - F: Fn(TokenStream) -> TokenStream, + F: Fn(&mut ExtCtxt<'_>, Span, TokenStream) -> Result<TokenStream, ErrorGuaranteed>, { fn expand<'cx>( &self, - _ecx: &'cx mut ExtCtxt<'_>, - _span: Span, + ecx: &'cx mut ExtCtxt<'_>, + span: Span, ts: TokenStream, ) -> Result<TokenStream, ErrorGuaranteed> { // FIXME setup implicit context in TLS before calling self. - Ok(self(ts)) + self(ecx, span, ts) } } @@ -345,6 +345,21 @@ pub trait AttrProcMacro { annotation: TokenStream, annotated: TokenStream, ) -> Result<TokenStream, ErrorGuaranteed>; + + // Default implementation for safe attributes; override if the attribute can be unsafe. + fn expand_with_safety<'cx>( + &self, + ecx: &'cx mut ExtCtxt<'_>, + safety: Safety, + span: Span, + annotation: TokenStream, + annotated: TokenStream, + ) -> Result<TokenStream, ErrorGuaranteed> { + if let Safety::Unsafe(span) = safety { + ecx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute"); + } + self.expand(ecx, span, annotation, annotated) + } } impl<F> AttrProcMacro for F @@ -942,9 +957,9 @@ impl SyntaxExtension { .unwrap_or_default(); let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe(_)); - let local_inner_macros = ast::attr::find_by_name(attrs, sym::macro_export) - .and_then(|macro_export| macro_export.meta_item_list()) - .is_some_and(|l| ast::attr::list_contains_name(&l, sym::local_inner_macros)); + let local_inner_macros = + *find_attr!(attrs, AttributeKind::MacroExport {local_inner_macros: l, ..} => l) + .unwrap_or(&false); let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, !is_local); tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe); @@ -999,17 +1014,14 @@ impl SyntaxExtension { /// A dummy bang macro `foo!()`. pub fn dummy_bang(edition: Edition) -> SyntaxExtension { - fn expander<'cx>( - cx: &'cx mut ExtCtxt<'_>, + fn expand( + ecx: &mut ExtCtxt<'_>, span: Span, - _: TokenStream, - ) -> MacroExpanderResult<'cx> { - ExpandResult::Ready(DummyResult::any( - span, - cx.dcx().span_delayed_bug(span, "expanded a dummy bang macro"), - )) + _ts: TokenStream, + ) -> Result<TokenStream, ErrorGuaranteed> { + Err(ecx.dcx().span_delayed_bug(span, "expanded a dummy bang macro")) } - SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Arc::new(expander)), edition) + SyntaxExtension::default(SyntaxExtensionKind::Bang(Arc::new(expand)), edition) } /// A dummy derive macro `#[derive(Foo)]`. diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 4c0e0bbfe26..3dfa3cdcc35 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -812,11 +812,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => item.to_tokens(), }; let attr_item = attr.get_normal_item(); + let safety = attr_item.unsafety; if let AttrArgs::Eq { .. } = attr_item.args { self.cx.dcx().emit_err(UnsupportedKeyValue { span }); } let inner_tokens = attr_item.args.inner_tokens(); - match expander.expand(self.cx, span, inner_tokens, tokens) { + match expander.expand_with_safety(self.cx, safety, span, inner_tokens, tokens) { Ok(tok_result) => { let fragment = self.parse_ast_fragment( tok_result, @@ -840,6 +841,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), } } else if let SyntaxExtensionKind::LegacyAttr(expander) = ext { + // `LegacyAttr` is only used for builtin attribute macros, which have their + // safety checked by `check_builtin_meta_item`, so we don't need to check + // `unsafety` here. match validate_attr::parse_meta(&self.cx.sess.psess, &attr) { Ok(meta) => { let item_clone = macro_stats.then(|| item.clone()); @@ -882,6 +886,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } } else if let SyntaxExtensionKind::NonMacroAttr = ext { + if let ast::Safety::Unsafe(span) = attr.get_normal_item().unsafety { + self.cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute"); + } // `-Zmacro-stats` ignores these because they don't do any real expansion. self.cx.expanded_inert_attrs.mark(&attr); item.visit_attrs(|attrs| attrs.insert(pos, attr)); @@ -971,7 +978,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); } }, - SyntaxExtensionKind::LegacyBang(..) => { + SyntaxExtensionKind::Bang(..) => { let msg = "expanded a dummy glob delegation"; let guar = self.cx.dcx().span_delayed_bug(span, msg); return ExpandResult::Ready(fragment_kind.dummy(span, guar)); diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index ebd6e887f7d..0eae44a05e7 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -210,8 +210,7 @@ pub(super) fn check_meta_variables( guar.map_or(Ok(()), Err) } -/// Checks `lhs` as part of the LHS of a macro definition, extends `binders` with new binders, and -/// sets `valid` to false in case of errors. +/// Checks `lhs` as part of the LHS of a macro definition. /// /// Arguments: /// - `psess` is used to emit diagnostics and lints @@ -306,8 +305,7 @@ fn get_binder_info<'a>( binders.get(&name).or_else(|| macros.find_map(|state| state.binders.get(&name))) } -/// Checks `rhs` as part of the RHS of a macro definition and sets `valid` to false in case of -/// errors. +/// Checks `rhs` as part of the RHS of a macro definition. /// /// Arguments: /// - `psess` is used to emit diagnostics and lints @@ -372,7 +370,7 @@ enum NestedMacroState { } /// Checks `tts` as part of the RHS of a macro definition, tries to recognize nested macro -/// definitions, and sets `valid` to false in case of errors. +/// definitions. /// /// Arguments: /// - `psess` is used to emit diagnostics and lints @@ -491,8 +489,7 @@ fn check_nested_occurrences( } } -/// Checks the body of nested macro, returns where the check stopped, and sets `valid` to false in -/// case of errors. +/// Checks the body of nested macro, returns where the check stopped. /// /// The token trees are checked as long as they look like a list of (LHS) => {RHS} token trees. This /// check is a best-effort to detect a macro definition. It returns the position in `tts` where we diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 1d147a0385c..c548cea537f 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -8,7 +8,7 @@ use rustc_ast::token::NtPatKind::*; use rustc_ast::token::TokenKind::*; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{self, DelimSpan, TokenStream}; -use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; +use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId, Safety}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan}; @@ -33,8 +33,8 @@ use super::diagnostics::{FailedMacro, failed_to_match_macro}; use super::macro_parser::{NamedMatches, NamedParseResult}; use super::{SequenceRepetition, diagnostics}; use crate::base::{ - AttrProcMacro, DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, - SyntaxExtension, SyntaxExtensionKind, TTMacroExpander, + AttrProcMacro, BangProcMacro, DummyResult, ExpandResult, ExtCtxt, MacResult, + MacroExpanderResult, SyntaxExtension, SyntaxExtensionKind, TTMacroExpander, }; use crate::errors; use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment}; @@ -131,6 +131,7 @@ pub(super) enum MacroRule { Func { lhs: Vec<MatcherLoc>, lhs_span: Span, rhs: mbe::TokenTree }, /// An attr rule, for use with `#[m]` Attr { + unsafe_rule: bool, args: Vec<MatcherLoc>, args_span: Span, body: Vec<MatcherLoc>, @@ -248,7 +249,18 @@ impl TTMacroExpander for MacroRulesMacroExpander { impl AttrProcMacro for MacroRulesMacroExpander { fn expand( &self, + _cx: &mut ExtCtxt<'_>, + _sp: Span, + _args: TokenStream, + _body: TokenStream, + ) -> Result<TokenStream, ErrorGuaranteed> { + unreachable!("`expand` called on `MacroRulesMacroExpander`, expected `expand_with_safety`") + } + + fn expand_with_safety( + &self, cx: &mut ExtCtxt<'_>, + safety: Safety, sp: Span, args: TokenStream, body: TokenStream, @@ -260,6 +272,7 @@ impl AttrProcMacro for MacroRulesMacroExpander { self.node_id, self.name, self.transparency, + safety, args, body, &self.rules, @@ -267,16 +280,16 @@ impl AttrProcMacro for MacroRulesMacroExpander { } } -struct DummyExpander(ErrorGuaranteed); +struct DummyBang(ErrorGuaranteed); -impl TTMacroExpander for DummyExpander { +impl BangProcMacro for DummyBang { fn expand<'cx>( &self, _: &'cx mut ExtCtxt<'_>, - span: Span, + _: Span, _: TokenStream, - ) -> ExpandResult<Box<dyn MacResult + 'cx>, ()> { - ExpandResult::Ready(DummyResult::any(span, self.0)) + ) -> Result<TokenStream, ErrorGuaranteed> { + Err(self.0) } } @@ -408,6 +421,7 @@ fn expand_macro_attr( node_id: NodeId, name: Ident, transparency: Transparency, + safety: Safety, args: TokenStream, body: TokenStream, rules: &[MacroRule], @@ -429,13 +443,26 @@ fn expand_macro_attr( // Track nothing for the best performance. match try_match_macro_attr(psess, name, &args, &body, rules, &mut NoopTracker) { Ok((i, rule, named_matches)) => { - let MacroRule::Attr { rhs, .. } = rule else { + let MacroRule::Attr { rhs, unsafe_rule, .. } = rule else { panic!("try_macro_match_attr returned non-attr rule"); }; let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else { cx.dcx().span_bug(sp, "malformed macro rhs"); }; + match (safety, unsafe_rule) { + (Safety::Default, false) | (Safety::Unsafe(_), true) => {} + (Safety::Default, true) => { + cx.dcx().span_err(sp, "unsafe attribute invocation requires `unsafe`"); + } + (Safety::Unsafe(span), false) => { + cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute invocation"); + } + (Safety::Safe(span), _) => { + cx.dcx().span_bug(span, "unexpected `safe` keyword"); + } + } + let id = cx.current_expansion.id; let tts = transcribe(psess, &named_matches, rhs, *rhs_span, transparency, id) .map_err(|e| e.emit())?; @@ -664,7 +691,7 @@ pub fn compile_declarative_macro( SyntaxExtension::new(sess, kind, span, Vec::new(), edition, ident.name, attrs, is_local) }; let dummy_syn_ext = - |guar| (mk_syn_ext(SyntaxExtensionKind::LegacyBang(Arc::new(DummyExpander(guar)))), 0); + |guar| (mk_syn_ext(SyntaxExtensionKind::Bang(Arc::new(DummyBang(guar)))), 0); let macro_rules = macro_def.macro_rules; let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) }; @@ -681,6 +708,11 @@ pub fn compile_declarative_macro( let mut rules = Vec::new(); while p.token != token::Eof { + let unsafe_rule = p.eat_keyword_noexpect(kw::Unsafe); + let unsafe_keyword_span = p.prev_token.span; + if unsafe_rule && let Some(guar) = check_no_eof(sess, &p, "expected `attr`") { + return dummy_syn_ext(guar); + } let (args, is_derive) = if p.eat_keyword_noexpect(sym::attr) { kinds |= MacroKinds::ATTR; if !features.macro_attr() { @@ -705,6 +737,10 @@ pub fn compile_declarative_macro( feature_err(sess, sym::macro_derive, span, "`macro_rules!` derives are unstable") .emit(); } + if unsafe_rule { + sess.dcx() + .span_err(unsafe_keyword_span, "`unsafe` is only supported on `attr` rules"); + } if let Some(guar) = check_no_eof(sess, &p, "expected `()` after `derive`") { return dummy_syn_ext(guar); } @@ -730,6 +766,10 @@ pub fn compile_declarative_macro( (None, true) } else { kinds |= MacroKinds::BANG; + if unsafe_rule { + sess.dcx() + .span_err(unsafe_keyword_span, "`unsafe` is only supported on `attr` rules"); + } (None, false) }; let lhs_tt = p.parse_token_tree(); @@ -741,10 +781,10 @@ pub fn compile_declarative_macro( if let Some(guar) = check_no_eof(sess, &p, "expected right-hand side of macro rule") { return dummy_syn_ext(guar); } - let rhs_tt = p.parse_token_tree(); - let rhs_tt = parse_one_tt(rhs_tt, RulePart::Body, sess, node_id, features, edition); - check_emission(check_rhs(sess, &rhs_tt)); - check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs_tt)); + let rhs = p.parse_token_tree(); + let rhs = parse_one_tt(rhs, RulePart::Body, sess, node_id, features, edition); + check_emission(check_rhs(sess, &rhs)); + check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs)); let lhs_span = lhs_tt.span(); // Convert the lhs into `MatcherLoc` form, which is better for doing the // actual matching. @@ -760,11 +800,11 @@ pub fn compile_declarative_macro( }; let args = mbe::macro_parser::compute_locs(&delimited.tts); let body_span = lhs_span; - rules.push(MacroRule::Attr { args, args_span, body: lhs, body_span, rhs: rhs_tt }); + rules.push(MacroRule::Attr { unsafe_rule, args, args_span, body: lhs, body_span, rhs }); } else if is_derive { - rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs: rhs_tt }); + rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs }); } else { - rules.push(MacroRule::Func { lhs, lhs_span, rhs: rhs_tt }); + rules.push(MacroRule::Func { lhs, lhs_span, rhs }); } if p.token == token::Eof { break; @@ -894,12 +934,12 @@ fn check_redundant_vis_repetition( seq: &SequenceRepetition, span: &DelimSpan, ) { - let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne; - let is_vis = seq.tts.first().map_or(false, |tt| { - matches!(tt, mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. }) - }); - - if is_vis && is_zero_or_one { + if seq.kleene.op == KleeneOp::ZeroOrOne + && matches!( + seq.tts.first(), + Some(mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. }) + ) + { err.note("a `vis` fragment can already be empty"); err.multipart_suggestion( "remove the `$(` and `)?`", diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index d2b275ad20a..70d796cda11 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -5,7 +5,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, PResult}; use rustc_macros::{Decodable, Encodable}; use rustc_session::parse::ParseSess; -use rustc_span::{Ident, Span, Symbol}; +use rustc_span::{Ident, Span, Symbol, sym}; use crate::errors; @@ -69,15 +69,15 @@ impl MetaVarExpr { } let mut iter = args.iter(); - let rslt = match ident.as_str() { - "concat" => parse_concat(&mut iter, psess, outer_span, ident.span)?, - "count" => parse_count(&mut iter, psess, ident.span)?, - "ignore" => { + let rslt = match ident.name { + sym::concat => parse_concat(&mut iter, psess, outer_span, ident.span)?, + sym::count => parse_count(&mut iter, psess, ident.span)?, + sym::ignore => { eat_dollar(&mut iter, psess, ident.span)?; MetaVarExpr::Ignore(parse_ident(&mut iter, psess, ident.span)?) } - "index" => MetaVarExpr::Index(parse_depth(&mut iter, psess, ident.span)?), - "len" => MetaVarExpr::Len(parse_depth(&mut iter, psess, ident.span)?), + sym::index => MetaVarExpr::Index(parse_depth(&mut iter, psess, ident.span)?), + sym::len => MetaVarExpr::Len(parse_depth(&mut iter, psess, ident.span)?), _ => { let err = errors::MveUnrecognizedExpr { span: ident.span, @@ -119,14 +119,13 @@ fn check_trailing_tokens<'psess>( } // `None` for max indicates the arg count must be exact, `Some` indicates a range is accepted. - let (min_or_exact_args, max_args) = match ident.as_str() { - "concat" => panic!("concat takes unlimited tokens but didn't eat them all"), - "ignore" => (1, None), + let (min_or_exact_args, max_args) = match ident.name { + sym::concat => panic!("concat takes unlimited tokens but didn't eat them all"), + sym::ignore => (1, None), // 1 or 2 args - "count" => (1, Some(2)), + sym::count => (1, Some(2)), // 0 or 1 arg - "index" => (0, Some(1)), - "len" => (0, Some(1)), + sym::index | sym::len => (0, Some(1)), other => unreachable!("unknown MVEs should be rejected earlier (got `{other}`)"), }; diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 6a3f1f62c91..dddd62a4945 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -375,6 +375,19 @@ fn transcribe_metavar<'tx>( return Ok(()); }; + let MatchedSingle(pnr) = cur_matched else { + // We were unable to descend far enough. This is an error. + return Err(dcx.create_err(MacroVarStillRepeating { span: sp, ident })); + }; + + transcribe_pnr(tscx, sp, pnr) +} + +fn transcribe_pnr<'tx>( + tscx: &mut TranscrCtx<'tx, '_>, + mut sp: Span, + pnr: &ParseNtResult, +) -> PResult<'tx, ()> { // We wrap the tokens in invisible delimiters, unless they are already wrapped // in invisible delimiters with the same `MetaVarKind`. Because some proc // macros can't handle multiple layers of invisible delimiters of the same @@ -404,33 +417,33 @@ fn transcribe_metavar<'tx>( ) }; - let tt = match cur_matched { - MatchedSingle(ParseNtResult::Tt(tt)) => { + let tt = match pnr { + ParseNtResult::Tt(tt) => { // `tt`s are emitted into the output stream directly as "raw tokens", // without wrapping them into groups. Other variables are emitted into // the output stream as groups with `Delimiter::Invisible` to maintain // parsing priorities. maybe_use_metavar_location(tscx.psess, &tscx.stack, sp, tt, &mut tscx.marker) } - MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => { + ParseNtResult::Ident(ident, is_raw) => { tscx.marker.mark_span(&mut sp); with_metavar_spans(|mspans| mspans.insert(ident.span, sp)); let kind = token::NtIdent(*ident, *is_raw); TokenTree::token_alone(kind, sp) } - MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => { + ParseNtResult::Lifetime(ident, is_raw) => { tscx.marker.mark_span(&mut sp); with_metavar_spans(|mspans| mspans.insert(ident.span, sp)); let kind = token::NtLifetime(*ident, *is_raw); TokenTree::token_alone(kind, sp) } - MatchedSingle(ParseNtResult::Item(item)) => { + ParseNtResult::Item(item) => { mk_delimited(item.span, MetaVarKind::Item, TokenStream::from_ast(item)) } - MatchedSingle(ParseNtResult::Block(block)) => { + ParseNtResult::Block(block) => { mk_delimited(block.span, MetaVarKind::Block, TokenStream::from_ast(block)) } - MatchedSingle(ParseNtResult::Stmt(stmt)) => { + ParseNtResult::Stmt(stmt) => { let stream = if let StmtKind::Empty = stmt.kind { // FIXME: Properly collect tokens for empty statements. TokenStream::token_alone(token::Semi, stmt.span) @@ -439,10 +452,10 @@ fn transcribe_metavar<'tx>( }; mk_delimited(stmt.span, MetaVarKind::Stmt, stream) } - MatchedSingle(ParseNtResult::Pat(pat, pat_kind)) => { + ParseNtResult::Pat(pat, pat_kind) => { mk_delimited(pat.span, MetaVarKind::Pat(*pat_kind), TokenStream::from_ast(pat)) } - MatchedSingle(ParseNtResult::Expr(expr, kind)) => { + ParseNtResult::Expr(expr, kind) => { let (can_begin_literal_maybe_minus, can_begin_string_literal) = match &expr.kind { ExprKind::Lit(_) => (true, true), ExprKind::Unary(UnOp::Neg, e) if matches!(&e.kind, ExprKind::Lit(_)) => { @@ -460,14 +473,14 @@ fn transcribe_metavar<'tx>( TokenStream::from_ast(expr), ) } - MatchedSingle(ParseNtResult::Literal(lit)) => { + ParseNtResult::Literal(lit) => { mk_delimited(lit.span, MetaVarKind::Literal, TokenStream::from_ast(lit)) } - MatchedSingle(ParseNtResult::Ty(ty)) => { + ParseNtResult::Ty(ty) => { let is_path = matches!(&ty.kind, TyKind::Path(None, _path)); mk_delimited(ty.span, MetaVarKind::Ty { is_path }, TokenStream::from_ast(ty)) } - MatchedSingle(ParseNtResult::Meta(attr_item)) => { + ParseNtResult::Meta(attr_item) => { let has_meta_form = attr_item.meta_kind().is_some(); mk_delimited( attr_item.span(), @@ -475,16 +488,12 @@ fn transcribe_metavar<'tx>( TokenStream::from_ast(attr_item), ) } - MatchedSingle(ParseNtResult::Path(path)) => { + ParseNtResult::Path(path) => { mk_delimited(path.span, MetaVarKind::Path, TokenStream::from_ast(path)) } - MatchedSingle(ParseNtResult::Vis(vis)) => { + ParseNtResult::Vis(vis) => { mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis)) } - MatchedSeq(..) => { - // We were unable to descend far enough. This is an error. - return Err(dcx.create_err(MacroVarStillRepeating { span: sp, ident })); - } }; tscx.result.push(tt); diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 6af4cfb0e56..364a1202b05 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -205,7 +205,7 @@ declare_features! ( (accepted, extended_key_value_attributes, "1.54.0", Some(78835)), /// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions /// for functions with varargs. - (accepted, extended_varargs_abi_support, "CURRENT_RUSTC_VERSION", Some(100189)), + (accepted, extended_varargs_abi_support, "1.91.0", Some(100189)), /// Allows resolving absolute paths as paths from other crates. (accepted, extern_absolute_paths, "1.30.0", Some(44660)), /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. @@ -400,7 +400,7 @@ declare_features! ( /// Allows use of `&foo[a..b]` as a slicing syntax. (accepted, slicing_syntax, "1.0.0", None), /// Allows use of `sse4a` target feature. - (accepted, sse4a_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), + (accepted, sse4a_target_feature, "1.91.0", Some(44839)), /// Allows elision of `'static` lifetimes in `static`s and `const`s. (accepted, static_in_const, "1.17.0", Some(35897)), /// Allows the definition recursive static items. @@ -414,7 +414,7 @@ declare_features! ( /// Allows the use of `#[target_feature]` on safe functions. (accepted, target_feature_11, "1.86.0", Some(69098)), /// Allows use of `tbm` target feature. - (accepted, tbm_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), + (accepted, tbm_target_feature, "1.91.0", Some(44839)), /// Allows `fn main()` with return types which implements `Termination` (RFC 1937). (accepted, termination_trait, "1.26.0", Some(43301)), /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 99d6e93faa9..220388ffe43 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1212,6 +1212,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ niche optimizations in the standard library", ), rustc_attr!( + rustc_simd_monomorphize_lane_limit, Normal, template!(NameValueStr: "N"), ErrorFollowing, + EncodeCrossCrate::Yes, + "the `#[rustc_simd_monomorphize_lane_limit]` attribute is just used by std::simd \ + for better error messages", + ), + rustc_attr!( rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \ diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index e37fc6b7bfc..539d67e0b6b 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -101,6 +101,10 @@ declare_features! ( Some("never properly implemented; requires significant design work"), 127655), /// Allows deriving traits as per `SmartPointer` specification (removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284), + /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. + (removed, doc_auto_cfg, "CURRENT_RUSTC_VERSION", Some(43781), Some("merged into `doc_cfg`"), 138907), + /// Allows `#[doc(cfg_hide(...))]`. + (removed, doc_cfg_hide, "CURRENT_RUSTC_VERSION", Some(43781), Some("merged into `doc_cfg`"), 138907), /// Allows using `#[doc(keyword = "...")]`. (removed, doc_keyword, "1.58.0", Some(51315), Some("merged into `#![feature(rustdoc_internals)]`"), 90420), @@ -192,7 +196,7 @@ declare_features! ( (removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand"), 69667), // Allows the use of `no_sanitize` attribute. /// The feature was renamed to `sanitize` and the attribute to `#[sanitize(xyz = "on|off")]` - (removed, no_sanitize, "CURRENT_RUSTC_VERSION", Some(39699), Some(r#"renamed to sanitize(xyz = "on|off")"#), 142681), + (removed, no_sanitize, "1.91.0", Some(39699), Some(r#"renamed to sanitize(xyz = "on|off")"#), 142681), /// Note: this feature was previously recorded in a separate /// `STABLE_REMOVED` list because it, uniquely, was once stable but was /// then removed. But there was no utility storing it separately, so now @@ -203,7 +207,7 @@ declare_features! ( (removed, object_safe_for_dispatch, "1.83.0", Some(43561), Some("renamed to `dyn_compatible_for_dispatch`"), 131511), /// Allows using `#[omit_gdb_pretty_printer_section]`. - (removed, omit_gdb_pretty_printer_section, "CURRENT_RUSTC_VERSION", None, None, 144738), + (removed, omit_gdb_pretty_printer_section, "1.91.0", None, None, 144738), /// Allows using `#[on_unimplemented(..)]` on traits. /// (Moved to `rustc_attrs`.) (removed, on_unimplemented, "1.40.0", None, None, 65794), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 93e5588146e..e63f29a9570 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -327,7 +327,7 @@ declare_features! ( (unstable, m68k_target_feature, "1.85.0", Some(134328)), (unstable, mips_target_feature, "1.27.0", Some(44839)), (unstable, movrs_target_feature, "1.88.0", Some(137976)), - (unstable, nvptx_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), + (unstable, nvptx_target_feature, "1.91.0", Some(44839)), (unstable, powerpc_target_feature, "1.27.0", Some(44839)), (unstable, prfchw_target_feature, "1.78.0", Some(44839)), (unstable, riscv_target_feature, "1.45.0", Some(44839)), @@ -471,17 +471,13 @@ declare_features! ( /// Allows deref patterns. (incomplete, deref_patterns, "1.79.0", Some(87121)), /// Allows deriving the From trait on single-field structs. - (unstable, derive_from, "CURRENT_RUSTC_VERSION", Some(144889)), - /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. - (unstable, doc_auto_cfg, "1.58.0", Some(43781)), + (unstable, derive_from, "1.91.0", Some(144889)), /// Allows `#[doc(cfg(...))]`. (unstable, doc_cfg, "1.21.0", Some(43781)), - /// Allows `#[doc(cfg_hide(...))]`. - (unstable, doc_cfg_hide, "1.57.0", Some(43781)), /// Allows `#[doc(masked)]`. (unstable, doc_masked, "1.21.0", Some(44027)), /// Allows features to allow target_feature to better interact with traits. - (incomplete, effective_target_features, "CURRENT_RUSTC_VERSION", Some(143352)), + (incomplete, effective_target_features, "1.91.0", Some(143352)), /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }` (incomplete, ergonomic_clones, "1.87.0", Some(132290)), /// Allows exhaustive pattern matching on types that contain uninhabited types. @@ -554,9 +550,9 @@ declare_features! ( /// Allows fused `loop`/`match` for direct intraprocedural jumps. (incomplete, loop_match, "1.90.0", Some(132306)), /// Allow `macro_rules!` attribute rules - (unstable, macro_attr, "CURRENT_RUSTC_VERSION", Some(83527)), + (unstable, macro_attr, "1.91.0", Some(143547)), /// Allow `macro_rules!` derive rules - (unstable, macro_derive, "CURRENT_RUSTC_VERSION", Some(143549)), + (unstable, macro_derive, "1.91.0", Some(143549)), /// Give access to additional metadata about declarative macro meta-variables. (unstable, macro_metavar_expr, "1.61.0", Some(83527)), /// Provides a way to concatenate identifiers using metavariable expressions. @@ -613,7 +609,7 @@ declare_features! ( (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows the use of raw-dylibs on ELF platforms (incomplete, raw_dylib_elf, "1.87.0", Some(135694)), - (unstable, reborrow, "CURRENT_RUSTC_VERSION", Some(145612)), + (unstable, reborrow, "1.91.0", Some(145612)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant @@ -627,13 +623,13 @@ declare_features! ( /// Allows `extern "rust-cold"`. (unstable, rust_cold_cc, "1.63.0", Some(97544)), /// Allows the use of the `sanitize` attribute. - (unstable, sanitize, "CURRENT_RUSTC_VERSION", Some(39699)), + (unstable, sanitize, "1.91.0", Some(39699)), /// Allows the use of SIMD types in functions declared in `extern` blocks. (unstable, simd_ffi, "1.0.0", Some(27731)), /// Allows specialization of implementations (RFC 1210). (incomplete, specialization, "1.7.0", Some(31844)), /// Allows using `#[rustc_align_static(...)]` on static items. - (unstable, static_align, "CURRENT_RUSTC_VERSION", Some(146177)), + (unstable, static_align, "1.91.0", Some(146177)), /// Allows attributes on expressions and non-item statements. (unstable, stmt_expr_attributes, "1.6.0", Some(15701)), /// Allows lints part of the strict provenance effort. @@ -645,7 +641,7 @@ declare_features! ( /// Allows subtrait items to shadow supertrait items. (unstable, supertrait_item_shadowing, "1.86.0", Some(89151)), /// Allows the use of target_feature when a function is marked inline(always). - (unstable, target_feature_inline_always, "CURRENT_RUSTC_VERSION", Some(145574)), + (unstable, target_feature_inline_always, "1.91.0", Some(145574)), /// Allows using `#[thread_local]` on `static` items. (unstable, thread_local, "1.0.0", Some(29594)), /// Allows defining `trait X = A + B;` alias items. diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 0784675b177..ddcbaeaad88 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -363,6 +363,20 @@ pub struct LinkEntry { pub import_name_type: Option<(PeImportNameType, Span)>, } +#[derive(HashStable_Generic, PrintAttribute)] +#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] +pub enum DebuggerVisualizerType { + Natvis, + GdbPrettyPrinter, +} + +#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] +pub struct DebugVisualizer { + pub span: Span, + pub visualizer_type: DebuggerVisualizerType, + pub path: Symbol, +} + /// Represents parsed *built-in* inert attributes. /// /// ## Overview @@ -485,7 +499,10 @@ pub enum AttributeKind { /// Represents `#[custom_mir]`. CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span), - ///Represents `#[rustc_deny_explicit_impl]`. + /// Represents `#[debugger_visualizer]`. + DebuggerVisualizer(ThinVec<DebugVisualizer>), + + /// Represents `#[rustc_deny_explicit_impl]`. DenyExplicitImpl(Span), /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute). @@ -551,6 +568,9 @@ pub enum AttributeKind { /// Represents `#[macro_escape]`. MacroEscape(Span), + /// Represents [`#[macro_export]`](https://doc.rust-lang.org/reference/macros-by-example.html#r-macro.decl.scope.path). + MacroExport { span: Span, local_inner_macros: bool }, + /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), @@ -648,6 +668,9 @@ pub enum AttributeKind { /// Represents `#[rustc_object_lifetime_default]`. RustcObjectLifetimeDefault, + /// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`. + RustcSimdMonomorphizeLaneLimit(Limit), + /// Represents `#[sanitize]` /// /// the on set and off set are distjoint since there's a third option: unset. diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 563e7a58c6d..1611b865c77 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -37,6 +37,7 @@ impl AttributeKind { Coverage(..) => No, CrateName { .. } => No, CustomMir(_, _, _) => Yes, + DebuggerVisualizer(..) => No, DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, DoNotImplementViaObject(..) => No, @@ -56,6 +57,7 @@ impl AttributeKind { Linkage(..) => No, LoopMatch(..) => No, MacroEscape(..) => No, + MacroExport { .. } => Yes, MacroTransparency(..) => Yes, MacroUse { .. } => No, Marker(..) => No, @@ -87,6 +89,7 @@ impl AttributeKind { RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, RustcObjectLifetimeDefault => No, + RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate Sanitize { .. } => No, ShouldPanic { .. } => No, SkipDuringMethodDispatch { .. } => No, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 493236718a8..bc1c47e95c3 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1298,10 +1298,7 @@ impl AttributeExt for Attribute { #[inline] fn path_matches(&self, name: &[Symbol]) -> bool { match &self { - Attribute::Unparsed(n) => { - n.path.segments.len() == name.len() - && n.path.segments.iter().zip(name).all(|(s, n)| s.name == *n) - } + Attribute::Unparsed(n) => n.path.segments.iter().map(|ident| &ident.name).eq(name), _ => false, } } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 2e099a97b65..311cf8f995c 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -440,6 +440,7 @@ language_item_table! { // Reborrowing related lang-items Reborrow, sym::reborrow, reborrow, Target::Trait, GenericRequirement::Exact(0); + CoerceShared, sym::coerce_shared, coerce_shared, Target::Trait, GenericRequirement::Exact(0); } /// The requirement imposed on the generics of a lang item diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index 0b24052b453..c9de6f6b5d5 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -31,9 +31,35 @@ pub struct AttributeLint<Id> { #[derive(Clone, Debug, HashStable_Generic)] pub enum AttributeLintKind { - UnusedDuplicate { this: Span, other: Span, warning: bool }, - IllFormedAttributeInput { suggestions: Vec<String> }, - EmptyAttribute { first_span: Span }, - InvalidTarget { name: AttrPath, target: Target, applied: Vec<String>, only: &'static str }, - InvalidStyle { name: AttrPath, is_used_as_inner: bool, target: Target, target_span: Span }, + /// Copy of `IllFormedAttributeInput` + /// specifically for the `invalid_macro_export_arguments` lint until that is removed, + /// see <https://github.com/rust-lang/rust/pull/143857#issuecomment-3079175663> + InvalidMacroExportArguments { + suggestions: Vec<String>, + }, + UnusedDuplicate { + this: Span, + other: Span, + warning: bool, + }, + IllFormedAttributeInput { + suggestions: Vec<String>, + }, + EmptyAttribute { + first_span: Span, + attr_path: AttrPath, + valid_without_list: bool, + }, + InvalidTarget { + name: AttrPath, + target: Target, + applied: Vec<String>, + only: &'static str, + }, + InvalidStyle { + name: AttrPath, + is_used_as_inner: bool, + target: Target, + target_span: Span, + }, } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 886ebddc75c..e1e6860e430 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -219,7 +219,7 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting // `async-std` (and `pub async fn` in general). - // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it! + // Since rustdoc doesn't care about the hidden type behind `impl Trait`, just don't look at it! // See https://github.com/rust-lang/rust/issues/75100 if tcx.sess.opts.actually_rustdoc { return; @@ -252,7 +252,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>( Ok(()) } -/// Check that the concrete type behind `impl Trait` actually implements `Trait`. +/// Check that the hidden type behind `impl Trait` actually implements `Trait`. /// /// This is mostly checked at the places that specify the opaque type, but we /// check those cases in the `param_env` of that function, which may have diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index aa2d27ab809..bc3448be582 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -64,83 +64,159 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi // it's usually worth updating that intrinsic's documentation // to note that it's safe to call, since // safe extern fns are otherwise unprecedented. - sym::abort + + // tidy-alphabetical-start + | sym::abort + | sym::add_with_overflow + | sym::aggregate_raw_ptr + | sym::align_of | sym::assert_inhabited - | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid + | sym::assert_zero_valid + | sym::autodiff + | sym::bitreverse + | sym::black_box | sym::box_new | sym::breakpoint - | sym::size_of - | sym::align_of - | sym::needs_drop + | sym::bswap | sym::caller_location - | sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow | sym::carrying_mul_add - | sym::wrapping_add - | sym::wrapping_sub - | sym::wrapping_mul - | sym::saturating_add - | sym::saturating_sub - | sym::rotate_left - | sym::rotate_right - | sym::ctpop + | sym::ceilf16 + | sym::ceilf32 + | sym::ceilf64 + | sym::ceilf128 + | sym::cold_path + | sym::const_eval_select + | sym::contract_check_ensures + | sym::contract_check_requires + | sym::contract_checks + | sym::copysignf16 + | sym::copysignf32 + | sym::copysignf64 + | sym::copysignf128 + | sym::cosf16 + | sym::cosf32 + | sym::cosf64 + | sym::cosf128 | sym::ctlz + | sym::ctpop | sym::cttz - | sym::bswap - | sym::bitreverse - | sym::three_way_compare | sym::discriminant_value - | sym::type_id - | sym::type_id_eq - | sym::select_unpredictable - | sym::cold_path - | sym::ptr_guaranteed_cmp - | sym::minnumf16 - | sym::minnumf32 - | sym::minnumf64 - | sym::minnumf128 - | sym::minimumf16 - | sym::minimumf32 - | sym::minimumf64 - | sym::minimumf128 - | sym::maxnumf16 - | sym::maxnumf32 - | sym::maxnumf64 - | sym::maxnumf128 + | sym::exp2f16 + | sym::exp2f32 + | sym::exp2f64 + | sym::exp2f128 + | sym::expf16 + | sym::expf32 + | sym::expf64 + | sym::expf128 + | sym::fabsf16 + | sym::fabsf32 + | sym::fabsf64 + | sym::fabsf128 + | sym::fadd_algebraic + | sym::fdiv_algebraic + | sym::floorf16 + | sym::floorf32 + | sym::floorf64 + | sym::floorf128 + | sym::fmaf16 + | sym::fmaf32 + | sym::fmaf64 + | sym::fmaf128 + | sym::fmul_algebraic + | sym::fmuladdf16 + | sym::fmuladdf32 + | sym::fmuladdf64 + | sym::fmuladdf128 + | sym::forget + | sym::frem_algebraic + | sym::fsub_algebraic + | sym::is_val_statically_known + | sym::log2f16 + | sym::log2f32 + | sym::log2f64 + | sym::log2f128 + | sym::log10f16 + | sym::log10f32 + | sym::log10f64 + | sym::log10f128 + | sym::logf16 + | sym::logf32 + | sym::logf64 + | sym::logf128 | sym::maximumf16 | sym::maximumf32 | sym::maximumf64 | sym::maximumf128 - | sym::rustc_peek - | sym::type_name - | sym::forget - | sym::black_box - | sym::variant_count - | sym::is_val_statically_known + | sym::maxnumf16 + | sym::maxnumf32 + | sym::maxnumf64 + | sym::maxnumf128 + | sym::minimumf16 + | sym::minimumf32 + | sym::minimumf64 + | sym::minimumf128 + | sym::minnumf16 + | sym::minnumf32 + | sym::minnumf64 + | sym::minnumf128 + | sym::mul_with_overflow + | sym::needs_drop + | sym::powf16 + | sym::powf32 + | sym::powf64 + | sym::powf128 + | sym::powif16 + | sym::powif32 + | sym::powif64 + | sym::powif128 + | sym::prefetch_read_data + | sym::prefetch_read_instruction + | sym::prefetch_write_data + | sym::prefetch_write_instruction + | sym::ptr_guaranteed_cmp | sym::ptr_mask - | sym::aggregate_raw_ptr | sym::ptr_metadata - | sym::ub_checks - | sym::contract_checks - | sym::contract_check_requires - | sym::contract_check_ensures - | sym::fadd_algebraic - | sym::fsub_algebraic - | sym::fmul_algebraic - | sym::fdiv_algebraic - | sym::frem_algebraic + | sym::rotate_left + | sym::rotate_right | sym::round_ties_even_f16 | sym::round_ties_even_f32 | sym::round_ties_even_f64 | sym::round_ties_even_f128 - | sym::autodiff - | sym::prefetch_read_data - | sym::prefetch_write_data - | sym::prefetch_read_instruction - | sym::prefetch_write_instruction - | sym::const_eval_select => hir::Safety::Safe, + | sym::roundf16 + | sym::roundf32 + | sym::roundf64 + | sym::roundf128 + | sym::rustc_peek + | sym::saturating_add + | sym::saturating_sub + | sym::select_unpredictable + | sym::sinf16 + | sym::sinf32 + | sym::sinf64 + | sym::sinf128 + | sym::size_of + | sym::sqrtf16 + | sym::sqrtf32 + | sym::sqrtf64 + | sym::sqrtf128 + | sym::sub_with_overflow + | sym::three_way_compare + | sym::truncf16 + | sym::truncf32 + | sym::truncf64 + | sym::truncf128 + | sym::type_id + | sym::type_id_eq + | sym::type_name + | sym::ub_checks + | sym::variant_count + | sym::wrapping_add + | sym::wrapping_mul + | sym::wrapping_sub + // tidy-alphabetical-end + => hir::Safety::Safe, _ => hir::Safety::Unsafe, }; diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 38ae7852ca9..b069a74bf5a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -195,11 +195,10 @@ impl<'tcx> InherentCollect<'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Alias(ty::Free, _) - | ty::Bound(..) - | ty::Placeholder(_) - | ty::Infer(_) => { + | ty::CoroutineWitness(..) => { + Err(self.tcx.dcx().delayed_bug("cannot define inherent `impl` for closure types")) + } + ty::Alias(ty::Free, _) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) => { bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty); } // We could bail out here, but that will silence other useful errors. diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 621431ae234..5a61248cab8 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -230,10 +230,12 @@ pub(crate) fn orphan_check_impl( ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(..) => { + | ty::CoroutineWitness(..) => { + return Err(tcx + .dcx() + .delayed_bug("cannot define inherent `impl` for closure types")); + } + ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => { let sp = tcx.def_span(impl_def_id); span_bug!(sp, "weird self type for autotrait impl") } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b72e743f95b..02baaec3713 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1140,7 +1140,7 @@ fn recover_infer_ret_ty<'tcx>( // recursive function definition to leak out into the fn sig. let mut recovered_ret_ty = None; if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) { - diag.span_suggestion( + diag.span_suggestion_verbose( infer_ret_ty.span, "replace with the correct return type", suggestable_ret_ty, @@ -1152,7 +1152,7 @@ fn recover_infer_ret_ty<'tcx>( tcx.param_env(def_id), ret_ty, ) { - diag.span_suggestion( + diag.span_suggestion_verbose( infer_ret_ty.span, "replace with an appropriate return type", sugg, diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index ba54fa8cc0d..129b26d8ff0 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -12,7 +12,7 @@ use tracing::{debug, instrument}; use super::ItemCtxt; use super::predicates_of::assert_only_contains_predicates_from; -use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter}; +use crate::hir_ty_lowering::{HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter}; /// For associated types we include both bounds written on the type /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`. @@ -37,7 +37,14 @@ fn associated_type_bounds<'tcx>( let icx = ItemCtxt::new(tcx, assoc_item_def_id); let mut bounds = Vec::new(); - icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); + icx.lowerer().lower_bounds( + item_ty, + hir_bounds, + &mut bounds, + ty::List::empty(), + filter, + OverlappingAsssocItemConstraints::Allowed, + ); match filter { PredicateFilter::All @@ -174,21 +181,25 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( for (param, var) in std::iter::zip(&generics.own_params, gat_vars) { let existing = match var.kind() { ty::GenericArgKind::Lifetime(re) => { - if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() { + if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = + re.kind() + { mapping.insert(bv.var, tcx.mk_param_from_def(param)) } else { return None; } } ty::GenericArgKind::Type(ty) => { - if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() { + if let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() { mapping.insert(bv.var, tcx.mk_param_from_def(param)) } else { return None; } } ty::GenericArgKind::Const(ct) => { - if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() { + if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = + ct.kind() + { mapping.insert(bv.var, tcx.mk_param_from_def(param)) } else { return None; @@ -253,7 +264,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> { return ty; } - if let ty::Bound(binder, old_bound) = *ty.kind() + if let ty::Bound(ty::BoundVarIndexKind::Bound(binder), old_bound) = *ty.kind() && self.binder == binder { let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) { @@ -279,7 +290,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> { } fn fold_region(&mut self, re: ty::Region<'tcx>) -> ty::Region<'tcx> { - if let ty::ReBound(binder, old_bound) = re.kind() + if let ty::ReBound(ty::BoundVarIndexKind::Bound(binder), old_bound) = re.kind() && self.binder == binder { let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) { @@ -307,7 +318,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> { return ct; } - if let ty::ConstKind::Bound(binder, old_bound) = ct.kind() + if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(binder), old_bound) = ct.kind() && self.binder == binder { let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) { @@ -347,7 +358,14 @@ fn opaque_type_bounds<'tcx>( ty::print::with_reduced_queries!({ let icx = ItemCtxt::new(tcx, opaque_def_id); let mut bounds = Vec::new(); - icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); + icx.lowerer().lower_bounds( + item_ty, + hir_bounds, + &mut bounds, + ty::List::empty(), + filter, + OverlappingAsssocItemConstraints::Allowed, + ); // Implicit bounds are added to opaque types unless a `?Trait` bound is found match filter { PredicateFilter::All diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index dd3590f9ac5..ffdf2a2f4c0 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -18,7 +18,9 @@ use super::item_bounds::explicit_item_bounds_with_filter; use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; use crate::delegation::inherit_predicates_for_delegation_item; -use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter, RegionInferReason}; +use crate::hir_ty_lowering::{ + HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, +}; /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `explicit_predicates_of`, plus @@ -187,6 +189,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen &mut bounds, ty::List::empty(), PredicateFilter::All, + OverlappingAsssocItemConstraints::Allowed, ); icx.lowerer().add_sizedness_bounds( &mut bounds, @@ -289,6 +292,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen &mut bounds, bound_vars, PredicateFilter::All, + OverlappingAsssocItemConstraints::Allowed, ); predicates.extend(bounds); } @@ -659,7 +663,14 @@ pub(super) fn implied_predicates_with_filter<'tcx>( let self_param_ty = tcx.types.self_param; let mut bounds = Vec::new(); - icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter); + icx.lowerer().lower_bounds( + self_param_ty, + superbounds, + &mut bounds, + ty::List::empty(), + filter, + OverlappingAsssocItemConstraints::Allowed, + ); match filter { PredicateFilter::All | PredicateFilter::SelfOnly @@ -984,6 +995,7 @@ impl<'tcx> ItemCtxt<'tcx> { &mut bounds, bound_vars, filter, + OverlappingAsssocItemConstraints::Allowed, ); } @@ -1063,6 +1075,7 @@ pub(super) fn const_conditions<'tcx>( &mut bounds, bound_vars, PredicateFilter::ConstIfConst, + OverlappingAsssocItemConstraints::Allowed, ); } _ => {} @@ -1083,6 +1096,7 @@ pub(super) fn const_conditions<'tcx>( &mut bounds, ty::List::empty(), PredicateFilter::ConstIfConst, + OverlappingAsssocItemConstraints::Allowed, ); } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index b6d898886ac..a02990fe4ab 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -177,7 +177,7 @@ impl<'tcx> TaitConstraintLocator<'tcx> { let tables = tcx.typeck(item_def_id); if let Some(guar) = tables.tainted_by_errors { self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar)); - } else if let Some(&hidden_type) = tables.concrete_opaque_types.get(&self.def_id) { + } else if let Some(&hidden_type) = tables.hidden_types.get(&self.def_id) { self.insert_found(hidden_type); } else { self.non_defining_use_in_defining_scope(item_def_id); @@ -185,8 +185,8 @@ impl<'tcx> TaitConstraintLocator<'tcx> { } DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(item_def_id) { Err(guar) => self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar)), - Ok(concrete_opaque_types) => { - if let Some(&hidden_type) = concrete_opaque_types.0.get(&self.def_id) { + Ok(hidden_types) => { + if let Some(&hidden_type) = hidden_types.0.get(&self.def_id) { debug!(?hidden_type, "found constraint"); self.insert_found(hidden_type); } else if let Err(guar) = tcx @@ -247,7 +247,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( let tables = tcx.typeck(owner_def_id); if let Some(guar) = tables.tainted_by_errors { Ty::new_error(tcx, guar) - } else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) { + } else if let Some(hidden_ty) = tables.hidden_types.get(&def_id) { hidden_ty.ty } else { assert!(!tcx.next_trait_solver_globally()); @@ -261,8 +261,8 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( } } DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(owner_def_id) { - Ok(concrete_opaque_types) => { - if let Some(hidden_ty) = concrete_opaque_types.0.get(&def_id) { + Ok(hidden_types) => { + if let Some(hidden_ty) = hidden_types.0.get(&def_id) { hidden_ty.ty } else { let hir_ty = tcx.type_of_opaque_hir_typeck(def_id).instantiate_identity(); diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 366b3943a05..f8d0ea3e7bf 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -4,7 +4,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeV use rustc_span::Span; use tracing::debug; -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub(crate) struct Parameter(pub u32); impl From<ty::ParamTy> for Parameter { @@ -167,15 +167,20 @@ pub(crate) fn setup_constraining_predicates<'tcx>( // which is `O(nt)` where `t` is the depth of type-parameter constraints, // remembering that `t` should be less than 7 in practice. // + // FIXME(hkBst): the big-O bound above would be accurate for the number + // of calls to `parameters_for`, which itself is some O(complexity of type). + // That would make this potentially cubic instead of merely quadratic... + // ...unless we cache those `parameters_for` calls. + // // Basically, I iterate over all projections and swap every // "ready" projection to the start of the list, such that // all of the projections before `i` are topologically sorted // and constrain all the parameters in `input_parameters`. // - // In the example, `input_parameters` starts by containing `U` - which - // is constrained by the trait-ref - and so on the first pass we + // In the first example, `input_parameters` starts by containing `U`, + // which is constrained by the self type `U`. Then, on the first pass we // observe that `<U as Iterator>::Item = T` is a "ready" projection that - // constrains `T` and swap it to front. As it is the sole projection, + // constrains `T` and swap it to the front. As it is the sole projection, // no more swaps can take place afterwards, with the result being // * <U as Iterator>::Item = T // * T: Debug @@ -193,33 +198,25 @@ pub(crate) fn setup_constraining_predicates<'tcx>( for j in i..predicates.len() { // Note that we don't have to care about binders here, // as the impl trait ref never contains any late-bound regions. - if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() { - // Special case: watch out for some kind of sneaky attempt - // to project out an associated type defined by this very - // trait. - let unbound_trait_ref = projection.projection_term.trait_ref(tcx); - if Some(unbound_trait_ref) == impl_trait_ref { - continue; - } - - // A projection depends on its input types and determines its output - // type. For example, if we have - // `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output` - // Then the projection only applies if `T` is known, but it still - // does not determine `U`. - let inputs = parameters_for(tcx, projection.projection_term, true); - let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p)); - if !relies_only_on_inputs { - continue; - } + if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() && + + // Special case: watch out for some kind of sneaky attempt to + // project out an associated type defined by this very trait. + !impl_trait_ref.is_some_and(|t| t == projection.projection_term.trait_ref(tcx)) && + + // A projection depends on its input types and determines its output + // type. For example, if we have + // `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output` + // then the projection only applies if `T` is known, but it still + // does not determine `U`. + parameters_for(tcx, projection.projection_term, true).iter().all(|p| input_parameters.contains(p)) + { input_parameters.extend(parameters_for(tcx, projection.term, false)); - } else { - continue; + + predicates.swap(i, j); + i += 1; + changed = true; } - // fancy control flow to bypass borrow checker - predicates.swap(i, j); - i += 1; - changed = true; } debug!( "setup_constraining_predicates: predicates={:?} \ diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 99dc8e6e522..7accab8df87 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -21,7 +21,8 @@ use tracing::{debug, instrument}; use super::errors::GenericsArgsErrExtend; use crate::errors; use crate::hir_ty_lowering::{ - AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason, + AssocItemQSelf, FeedConstTy, HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter, + RegionInferReason, }; #[derive(Debug, Default)] @@ -338,6 +339,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, bound_vars: &'tcx ty::List<ty::BoundVariableKind>, predicate_filter: PredicateFilter, + overlapping_assoc_constraints: OverlappingAsssocItemConstraints, ) where 'tcx: 'hir, { @@ -362,6 +364,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { param_ty, bounds, predicate_filter, + overlapping_assoc_constraints, ); } hir::GenericBound::Outlives(lifetime) => { @@ -402,7 +405,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_ref: ty::PolyTraitRef<'tcx>, constraint: &hir::AssocItemConstraint<'tcx>, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, - duplicates: &mut FxIndexMap<DefId, Span>, + duplicates: Option<&mut FxIndexMap<DefId, Span>>, path_span: Span, predicate_filter: PredicateFilter, ) -> Result<(), ErrorGuaranteed> { @@ -458,17 +461,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) .expect("failed to find associated item"); - duplicates - .entry(assoc_item.def_id) - .and_modify(|prev_span| { - self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified { - span: constraint.span, - prev_span: *prev_span, - item_name: constraint.ident, - def_path: tcx.def_path_str(assoc_item.container_id(tcx)), - }); - }) - .or_insert(constraint.span); + if let Some(duplicates) = duplicates { + duplicates + .entry(assoc_item.def_id) + .and_modify(|prev_span| { + self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified { + span: constraint.span, + prev_span: *prev_span, + item_name: constraint.ident, + def_path: tcx.def_path_str(assoc_item.container_id(tcx)), + }); + }) + .or_insert(constraint.span); + } let projection_term = if let ty::AssocTag::Fn = assoc_tag { let bound_vars = tcx.late_bound_vars(constraint.hir_id); @@ -600,6 +605,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds, projection_ty.bound_vars(), predicate_filter, + OverlappingAsssocItemConstraints::Allowed, ); } PredicateFilter::SelfOnly @@ -915,7 +921,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't ty::Param(param) => { self.params.insert(param.index); } - ty::Bound(db, bt) if *db >= self.depth => { + ty::Bound(ty::BoundVarIndexKind::Bound(db), bt) if *db >= self.depth => { self.vars.insert(match bt.kind { ty::BoundTyKind::Param(def_id) => def_id, ty::BoundTyKind::Anon => { @@ -938,7 +944,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't ty::ReEarlyParam(param) => { self.params.insert(param.index); } - ty::ReBound(db, br) if db >= self.depth => { + ty::ReBound(ty::BoundVarIndexKind::Bound(db), br) if db >= self.depth => { self.vars.insert(match br.kind { ty::BoundRegionKind::Named(def_id) => def_id, ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => { @@ -961,7 +967,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't ty::ConstKind::Param(param) => { self.params.insert(param.index); } - ty::ConstKind::Bound(db, _) if db >= self.depth => { + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(db), _) if db >= self.depth => { let guar = self.cx.dcx().delayed_bug("unexpected escaping late-bound const var"); return ControlFlow::Break(guar); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 7867c1c3b48..0a41659ec66 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -134,11 +134,12 @@ fn is_valid_cmse_inputs<'tcx>( // this type is only used for layout computation, which does not rely on regions let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig); + let fn_sig = tcx.erase_and_anonymize_regions(fn_sig); for (index, ty) in fn_sig.inputs().iter().enumerate() { let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))?; - let align = layout.layout.align().abi.bytes(); + let align = layout.layout.align().bytes(); let size = layout.layout.size().bytes(); accum += size; @@ -219,6 +220,7 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError } Unknown(..) | SizeOverflow(..) + | InvalidSimd { .. } | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index c248cd7fec2..c0b13773089 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -23,7 +23,9 @@ use tracing::{debug, instrument}; use super::HirTyLowerer; use crate::errors::SelfInTypeAlias; -use crate::hir_ty_lowering::{GenericArgCountMismatch, PredicateFilter, RegionInferReason}; +use crate::hir_ty_lowering::{ + GenericArgCountMismatch, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, +}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a trait object type from the HIR to our internal notion of a type. @@ -60,6 +62,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { dummy_self, &mut user_written_bounds, PredicateFilter::SelfOnly, + OverlappingAsssocItemConstraints::Forbidden, ); if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct { potential_assoc_types.extend(invalid_args); @@ -157,10 +160,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.dcx() .struct_span_err( span, - format!( - "conflicting associated type bounds for `{item}` when \ - expanding trait alias" - ), + format!("conflicting associated type bounds for `{item}`"), ) .with_span_label( old_proj_span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 9b198d04454..eb660804c2b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -332,6 +332,15 @@ pub(crate) enum GenericArgPosition { MethodCall, } +/// Whether to allow duplicate associated iten constraints in a trait ref, e.g. +/// `Trait<Assoc = Ty, Assoc = Ty>`. This is forbidden in `dyn Trait<...>` +/// but allowed everywhere else. +#[derive(Clone, Copy, Debug, PartialEq)] +pub(crate) enum OverlappingAsssocItemConstraints { + Allowed, + Forbidden, +} + /// A marker denoting that the generic arguments that were /// provided did not match the respective generic parameters. #[derive(Clone, Debug)] @@ -752,6 +761,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty: Ty<'tcx>, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, predicate_filter: PredicateFilter, + overlapping_assoc_item_constraints: OverlappingAsssocItemConstraints, ) -> GenericArgCountResult { let tcx = self.tcx(); @@ -908,7 +918,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - let mut dup_constraints = FxIndexMap::default(); + let mut dup_constraints = (overlapping_assoc_item_constraints + == OverlappingAsssocItemConstraints::Forbidden) + .then_some(FxIndexMap::default()); + for constraint in trait_segment.args().constraints { // Don't register any associated item constraints for negative bounds, // since we should have emitted an error for them earlier, and they @@ -927,7 +940,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { poly_trait_ref, constraint, bounds, - &mut dup_constraints, + dup_constraints.as_mut(), constraint.span, predicate_filter, ); @@ -2484,6 +2497,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &mut bounds, ty::List::empty(), PredicateFilter::All, + OverlappingAsssocItemConstraints::Allowed, ); self.add_sizedness_bounds( &mut bounds, 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 b38639ed8c6..13c744ab461 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 @@ -275,7 +275,7 @@ fn check_duplicate_params<'tcx>( span: Span, ) -> Result<(), ErrorGuaranteed> { let mut base_params = cgp::parameters_for(tcx, parent_args, true); - base_params.sort_by_key(|param| param.0); + base_params.sort_unstable(); if let (_, [duplicate, ..]) = base_params.partition_dedup() { let param = impl1_args[duplicate.0 as usize]; return Err(tcx diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7adbee7ff28..f9cdc923670 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1633,8 +1633,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, ) -> Ty<'tcx> { let rcvr_t = self.check_expr(rcvr); - // no need to check for bot/err -- callee does that - let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t); + let rcvr_t = self.try_structurally_resolve_type(rcvr.span, rcvr_t); match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args) { Ok(method) => { @@ -3552,35 +3551,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // Try to give some advice about indexing tuples. 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: + err.help( + "tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc.", + ); + // If index is an unsuffixed integer, show the fixed expression: if let ExprKind::Lit(lit) = idx.kind && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node - && i.get() - < types - .len() - .try_into() - .expect("expected tuple index to be < usize length") + && i.get() < types.len().try_into().expect("tuple length fits in u128") { err.span_suggestion( brackets_span, - "to access tuple elements, use", + format!("to access tuple element `{i}`, use"), format!(".{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( - "to access tuple elements, use tuple indexing \ - syntax (e.g., `tuple.0`)", - ); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 833ce433d56..35253e4c291 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -611,19 +611,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { typeck_results.rvalue_scopes = rvalue_scopes; } - /// Unify the inference variables corresponding to coroutine witnesses, and save all the - /// predicates that were stalled on those inference variables. - /// - /// This process allows to conservatively save all predicates that do depend on the coroutine - /// interior types, for later processing by `check_coroutine_obligations`. - /// - /// We must not attempt to select obligations after this method has run, or risk query cycle - /// ICE. + /// Drain all obligations that are stalled on coroutines defined in this body. #[instrument(level = "debug", skip(self))] - pub(crate) fn resolve_coroutine_interiors(&self) { - // Try selecting all obligations that are not blocked on inference variables. - // Once we start unifying coroutine witnesses, trying to select obligations on them will - // trigger query cycle ICEs, as doing so requires MIR. + pub(crate) fn drain_stalled_coroutine_obligations(&self) { + // Make as much inference progress as possible before + // draining the stalled coroutine obligations as this may + // change obligations from being stalled on infer vars to + // being stalled on a coroutine. self.select_obligations_where_possible(|_| {}); let ty::TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode() diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 7ca8580e098..c8943d4634e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2803,9 +2803,7 @@ impl<'a, 'b, 'tcx> ArgMatchingCtxt<'a, 'b, 'tcx> { if let Some((assoc, fn_sig)) = self.similar_assoc(call_name) && fn_sig.inputs()[1..] .iter() - .zip(input_types.iter()) - .all(|(expected, found)| self.may_coerce(*expected, *found)) - && fn_sig.inputs()[1..].len() == input_types.len() + .eq_by(input_types, |expected, found| self.may_coerce(*expected, found)) { let assoc_name = assoc.name(); err.span_suggestion_verbose( diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 43a23822fd1..9f5a85b6926 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -5,6 +5,7 @@ #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_intersperse)] +#![feature(iter_order_by)] #![feature(never_type)] // tidy-alphabetical-end @@ -242,18 +243,15 @@ fn typeck_with_inspect<'tcx>( debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations()); - // This must be the last thing before `report_ambiguity_errors`. - fcx.resolve_coroutine_interiors(); - - debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations()); - // We need to handle opaque types before emitting ambiguity errors as applying // defining uses may guide type inference. if fcx.next_trait_solver() { fcx.handle_opaque_type_uses_next(); } - fcx.select_obligations_where_possible(|_| {}); + // This must be the last thing before `report_ambiguity_errors` below except `select_obligations_where_possible`. + // So don't put anything after this. + fcx.drain_stalled_coroutine_obligations(); if fcx.infcx.tainted_by_errors().is_none() { fcx.report_ambiguity_errors(); } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index a23910a2006..b23e7ae8e77 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -172,7 +172,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // Commit the autoderefs by calling `autoderef` again, but this // time writing the results into the various typeck results. let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty); - let Some((ty, n)) = autoderef.nth(pick.autoderefs) else { + let Some((mut target, n)) = autoderef.nth(pick.autoderefs) else { return Ty::new_error_with_message( self.tcx, DUMMY_SP, @@ -182,8 +182,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { assert_eq!(n, pick.autoderefs); let mut adjustments = self.adjust_steps(&autoderef); - let mut target = self.structurally_resolve_type(autoderef.span(), ty); - match pick.autoref_or_ptr_adjustment { Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => { let region = self.next_region_var(RegionVariableOrigin::Autoref(self.span)); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 4185f7f6996..12f80a197b1 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -13,7 +13,7 @@ use rustc_hir::def::DefKind; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt}; -use rustc_infer::traits::ObligationCauseCode; +use rustc_infer::traits::{ObligationCauseCode, PredicateObligation, query}; use rustc_middle::middle::stability; use rustc_middle::ty::elaborate::supertrait_def_ids; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}; @@ -30,7 +30,8 @@ use rustc_span::edit_distance::{ use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::traits::query::CanonicalTyGoal; +use rustc_trait_selection::solve::Goal; +use rustc_trait_selection::traits::query::CanonicalMethodAutoderefStepsGoal; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::{ CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult, @@ -389,10 +390,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result<R, MethodError<'tcx>>, { let mut orig_values = OriginalQueryValues::default(); - let query_input = self.canonicalize_query( - ParamEnvAnd { param_env: self.param_env, value: self_ty }, - &mut orig_values, - ); + let predefined_opaques_in_body = if self.next_trait_solver() { + self.tcx.mk_predefined_opaques_in_body_from_iter( + self.inner.borrow_mut().opaque_types().iter_opaque_types().map(|(k, v)| (k, v.ty)), + ) + } else { + ty::List::empty() + }; + let value = query::MethodAutoderefSteps { predefined_opaques_in_body, self_ty }; + let query_input = self + .canonicalize_query(ParamEnvAnd { param_env: self.param_env, value }, &mut orig_values); let steps = match mode { Mode::MethodCall => self.tcx.method_autoderef_steps(query_input), @@ -403,13 +410,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // special handling for this "trivial case" is a good idea. let infcx = &self.infcx; - let (ParamEnvAnd { param_env: _, value: self_ty }, var_values) = + let (ParamEnvAnd { param_env: _, value }, var_values) = infcx.instantiate_canonical(span, &query_input.canonical); + let query::MethodAutoderefSteps { predefined_opaques_in_body: _, self_ty } = value; debug!(?self_ty, ?query_input, "probe_op: Mode::Path"); MethodAutoderefStepsResult { steps: infcx.tcx.arena.alloc_from_iter([CandidateStep { self_ty: self .make_query_response_ignoring_pending_obligations(var_values, self_ty), + self_ty_is_opaque: false, autoderefs: 0, from_unsafe_deref: false, unsize: false, @@ -479,6 +488,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Infer(ty::TyVar(_)) => { let raw_ptr_call = bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types(); + // FIXME: Ideally we'd use the span of the self-expr here, + // not of the method path. let mut err = self.err_ctxt().emit_inference_failure_err( self.body_id, span, @@ -553,12 +564,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn method_autoderef_steps<'tcx>( tcx: TyCtxt<'tcx>, - goal: CanonicalTyGoal<'tcx>, + goal: CanonicalMethodAutoderefStepsGoal<'tcx>, ) -> MethodAutoderefStepsResult<'tcx> { debug!("method_autoderef_steps({:?})", goal); let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal); - let ParamEnvAnd { param_env, value: self_ty } = goal; + let ParamEnvAnd { + param_env, + value: query::MethodAutoderefSteps { predefined_opaques_in_body, self_ty }, + } = goal; + for (key, ty) in predefined_opaques_in_body { + let prev = + infcx.register_hidden_type_in_storage(key, ty::OpaqueHiddenType { span: DUMMY_SP, ty }); + // It may be possible that two entries in the opaque type storage end up + // with the same key after resolving contained inference variables. + // + // We could put them in the duplicate list but don't have to. The opaques we + // encounter here are already tracked in the caller, so there's no need to + // also store them here. We'd take them out when computing the query response + // and then discard them, as they're already present in the input. + // + // Ideally we'd drop duplicate opaque type definitions when computing + // the canonical input. This is more annoying to implement and may cause a + // perf regression, so we do it inside of the query for now. + if let Some(prev) = prev { + debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`"); + } + } + + // We accept not-yet-defined opaque types in the autoderef + // chain to support recursive calls. We do error if the final + // infer var is not an opaque. + let self_ty_is_opaque = |ty: Ty<'_>| { + if let &ty::Infer(ty::TyVar(vid)) = ty.kind() { + infcx.has_opaques_with_sub_unified_hidden_type(vid) + } else { + false + } + }; // If arbitrary self types is not enabled, we follow the chain of // `Deref<Target=T>`. If arbitrary self types is enabled, we instead @@ -593,6 +636,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( let step = CandidateStep { self_ty: infcx .make_query_response_ignoring_pending_obligations(inference_vars, ty), + self_ty_is_opaque: self_ty_is_opaque(ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, unsize: false, @@ -613,6 +657,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( let step = CandidateStep { self_ty: infcx .make_query_response_ignoring_pending_obligations(inference_vars, ty), + self_ty_is_opaque: self_ty_is_opaque(ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, unsize: false, @@ -629,7 +674,11 @@ pub(crate) fn method_autoderef_steps<'tcx>( }; let final_ty = autoderef_via_deref.final_ty(); let opt_bad_ty = match final_ty.kind() { - ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy { + ty::Infer(ty::TyVar(_)) if !self_ty_is_opaque(final_ty) => Some(MethodAutoderefBadTy { + reached_raw_pointer, + ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty), + }), + ty::Error(_) => Some(MethodAutoderefBadTy { reached_raw_pointer, ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty), }), @@ -640,6 +689,7 @@ pub(crate) fn method_autoderef_steps<'tcx>( inference_vars, Ty::new_slice(infcx.tcx, *elem_ty), ), + self_ty_is_opaque: false, autoderefs, // this could be from an unsafe deref if we had // a *mut/const [T; N] @@ -655,7 +705,8 @@ pub(crate) fn method_autoderef_steps<'tcx>( }; debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty); - + // Need to empty the opaque types storage before it gets dropped. + let _ = infcx.take_opaque_types(); MethodAutoderefStepsResult { steps: tcx.arena.alloc_from_iter(steps), opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)), @@ -1203,7 +1254,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { !step.self_ty.value.references_error() && !step.from_unsafe_deref }) .find_map(|step| { - let InferOk { value: self_ty, obligations: _ } = self + let InferOk { value: self_ty, obligations: instantiate_self_ty_obligations } = self .fcx .probe_instantiate_query_response( self.span, @@ -1214,7 +1265,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty) }); - let by_value_pick = self.pick_by_value_method(step, self_ty, pick_diag_hints); + let by_value_pick = self.pick_by_value_method( + step, + self_ty, + &instantiate_self_ty_obligations, + pick_diag_hints, + ); // Check for shadowing of a by-reference method by a by-value method (see comments on check_for_shadowing) if let Some(by_value_pick) = by_value_pick { @@ -1225,6 +1281,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { by_value_pick, step, self_ty, + &instantiate_self_ty_obligations, mutbl, track_unstable_candidates, ) { @@ -1239,6 +1296,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let autoref_pick = self.pick_autorefd_method( step, self_ty, + &instantiate_self_ty_obligations, hir::Mutability::Not, pick_diag_hints, None, @@ -1252,6 +1310,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { autoref_pick, step, self_ty, + &instantiate_self_ty_obligations, hir::Mutability::Mut, track_unstable_candidates, ) { @@ -1288,12 +1347,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.pick_autorefd_method( step, self_ty, + &instantiate_self_ty_obligations, hir::Mutability::Mut, pick_diag_hints, None, ) - .or_else(|| self.pick_const_ptr_method(step, self_ty, pick_diag_hints)) - .or_else(|| self.pick_reborrow_pin_method(step, self_ty, pick_diag_hints)) + .or_else(|| { + self.pick_const_ptr_method( + step, + self_ty, + &instantiate_self_ty_obligations, + pick_diag_hints, + ) + }) + .or_else(|| { + self.pick_reborrow_pin_method( + step, + self_ty, + &instantiate_self_ty_obligations, + pick_diag_hints, + ) + }) }) } @@ -1317,6 +1391,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { possible_shadower: &Pick<'tcx>, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], mutbl: hir::Mutability, track_unstable_candidates: bool, ) -> Result<(), MethodError<'tcx>> { @@ -1381,6 +1456,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let potentially_shadowed_pick = self.pick_autorefd_method( step, self_ty, + instantiate_self_ty_obligations, mutbl, &mut pick_diag_hints, Some(&pick_constraints), @@ -1407,13 +1483,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], pick_diag_hints: &mut PickDiagHints<'_, 'tcx>, ) -> Option<PickResult<'tcx>> { if step.unsize { return None; } - self.pick_method(self_ty, pick_diag_hints, None).map(|r| { + self.pick_method(self_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(|r| { r.map(|mut pick| { pick.autoderefs = step.autoderefs; @@ -1450,6 +1527,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], mutbl: hir::Mutability, pick_diag_hints: &mut PickDiagHints<'_, 'tcx>, pick_constraints: Option<&PickConstraintsForShadowed>, @@ -1466,7 +1544,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let region = tcx.lifetimes.re_erased; let autoref_ty = Ty::new_ref(tcx, region, self_ty, mutbl); - self.pick_method(autoref_ty, pick_diag_hints, pick_constraints).map(|r| { + self.pick_method( + autoref_ty, + instantiate_self_ty_obligations, + pick_diag_hints, + pick_constraints, + ) + .map(|r| { r.map(|mut pick| { pick.autoderefs = step.autoderefs; pick.autoref_or_ptr_adjustment = @@ -1482,6 +1566,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], pick_diag_hints: &mut PickDiagHints<'_, 'tcx>, ) -> Option<PickResult<'tcx>> { if !self.tcx.features().pin_ergonomics() { @@ -1503,14 +1588,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let region = self.tcx.lifetimes.re_erased; let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not); - self.pick_method(autopin_ty, pick_diag_hints, None).map(|r| { - r.map(|mut pick| { - pick.autoderefs = step.autoderefs; - pick.autoref_or_ptr_adjustment = - Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not)); - pick - }) - }) + self.pick_method(autopin_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map( + |r| { + r.map(|mut pick| { + pick.autoderefs = step.autoderefs; + pick.autoref_or_ptr_adjustment = + Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not)); + pick + }) + }, + ) } /// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a @@ -1520,6 +1607,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, step: &CandidateStep<'tcx>, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], pick_diag_hints: &mut PickDiagHints<'_, 'tcx>, ) -> Option<PickResult<'tcx>> { // Don't convert an unsized reference to ptr @@ -1532,18 +1620,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }; let const_ptr_ty = Ty::new_imm_ptr(self.tcx, ty); - self.pick_method(const_ptr_ty, pick_diag_hints, None).map(|r| { - r.map(|mut pick| { - pick.autoderefs = step.autoderefs; - pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr); - pick - }) - }) + self.pick_method(const_ptr_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map( + |r| { + r.map(|mut pick| { + pick.autoderefs = step.autoderefs; + pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr); + pick + }) + }, + ) } fn pick_method( &self, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], pick_diag_hints: &mut PickDiagHints<'_, 'tcx>, pick_constraints: Option<&PickConstraintsForShadowed>, ) -> Option<PickResult<'tcx>> { @@ -1553,8 +1644,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { [("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)] { debug!("searching {} candidates", kind); - let res = - self.consider_candidates(self_ty, candidates, pick_diag_hints, pick_constraints); + let res = self.consider_candidates( + self_ty, + instantiate_self_ty_obligations, + candidates, + pick_diag_hints, + pick_constraints, + ); if let Some(pick) = res { return Some(pick); } @@ -1563,6 +1659,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if self.private_candidate.get().is_none() { if let Some(Ok(pick)) = self.consider_candidates( self_ty, + instantiate_self_ty_obligations, &self.private_candidates, &mut PickDiagHints { unstable_candidates: None, @@ -1579,6 +1676,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn consider_candidates( &self, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], candidates: &[Candidate<'tcx>], pick_diag_hints: &mut PickDiagHints<'_, 'tcx>, pick_constraints: Option<&PickConstraintsForShadowed>, @@ -1595,6 +1693,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { probe, self.consider_probe( self_ty, + instantiate_self_ty_obligations, probe, &mut pick_diag_hints.unsatisfied_predicates, ), @@ -1779,10 +1878,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - #[instrument(level = "trace", skip(self, possibly_unsatisfied_predicates), ret)] + #[instrument(level = "debug", skip(self, possibly_unsatisfied_predicates), ret)] fn consider_probe( &self, self_ty: Ty<'tcx>, + instantiate_self_ty_obligations: &[PredicateObligation<'tcx>], probe: &Candidate<'tcx>, possibly_unsatisfied_predicates: &mut Vec<( ty::Predicate<'tcx>, @@ -1790,8 +1890,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { Option<ObligationCause<'tcx>>, )>, ) -> ProbeResult { - debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe); - self.probe(|snapshot| { let outer_universe = self.universe(); @@ -1799,6 +1897,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let cause = &self.misc(self.span); let ocx = ObligationCtxt::new_with_diagnostics(self); + // Subtle: we're not *really* instantiating the current self type while + // probing, but instead fully recompute the autoderef steps once we've got + // a final `Pick`. We can't nicely handle these obligations outside of a probe. + // + // We simply handle them for each candidate here for now. That's kinda scuffed + // and ideally we just put them into the `FnCtxt` right away. We need to consider + // them to deal with defining uses in `method_autoderef_steps`. + if self.next_trait_solver() { + ocx.register_obligations(instantiate_self_ty_obligations.iter().cloned()); + let errors = ocx.select_where_possible(); + if !errors.is_empty() { + unreachable!("unexpected autoderef error {errors:?}"); + } + } + let mut trait_predicate = None; let (mut xform_self_ty, mut xform_ret_ty); @@ -2041,6 +2154,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + if self.infcx.next_trait_solver() { + if self.should_reject_candidate_due_to_opaque_treated_as_rigid(trait_predicate) { + result = ProbeResult::NoMatch; + } + } + // Previously, method probe used `evaluate_predicate` to determine if a predicate // was impossible to satisfy. This did a leak check, so we must also do a leak // check here to prevent backwards-incompatible ambiguity being introduced. See @@ -2054,6 +2173,80 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }) } + /// Trait candidates for not-yet-defined opaque types are a somewhat hacky. + /// + /// We want to only accept trait methods if they were hold even if the + /// opaque types were rigid. To handle this, we both check that for trait + /// candidates the goal were to hold even when treating opaques as rigid, + /// see [OpaqueTypesJank](rustc_trait_selection::solve::OpaqueTypesJank). + /// + /// We also check that all opaque types encountered as self types in the + /// autoderef chain don't get constrained when applying the candidate. + /// Importantly, this also handles calling methods taking `&self` on + /// `impl Trait` to reject the "by-self" candidate. + /// + /// This needs to happen at the end of `consider_probe` as we need to take + /// all the constraints from that into account. + #[instrument(level = "debug", skip(self), ret)] + fn should_reject_candidate_due_to_opaque_treated_as_rigid( + &self, + trait_predicate: Option<ty::Predicate<'tcx>>, + ) -> bool { + // This function is what hacky and doesn't perfectly do what we want it to. + // It's not soundness critical and we should be able to freely improve this + // in the future. + // + // Some concrete edge cases include the fact that `goal_may_hold_opaque_types_jank` + // also fails if there are any constraints opaques which are never used as a self + // type. We also allow where-bounds which are currently ambiguous but end up + // constraining an opaque later on. + + // Check whether the trait candidate would not be applicable if the + // opaque type were rigid. + if let Some(predicate) = trait_predicate { + let goal = Goal { param_env: self.param_env, predicate }; + if !self.infcx.goal_may_hold_opaque_types_jank(goal) { + return true; + } + } + + // Check whether any opaque types in the autoderef chain have been + // constrained. + for step in self.steps { + if step.self_ty_is_opaque { + debug!(?step.autoderefs, ?step.self_ty, "self_type_is_opaque"); + let constrained_opaque = self.probe(|_| { + // If we fail to instantiate the self type of this + // step, this part of the deref-chain is no longer + // reachable. In this case we don't care about opaque + // types there. + let Ok(ok) = self.fcx.probe_instantiate_query_response( + self.span, + self.orig_steps_var_values, + &step.self_ty, + ) else { + debug!("failed to instantiate self_ty"); + return false; + }; + let ocx = ObligationCtxt::new(self); + let self_ty = ocx.register_infer_ok_obligations(ok); + if !ocx.select_where_possible().is_empty() { + debug!("failed to prove instantiate self_ty obligations"); + return false; + } + + !self.resolve_vars_if_possible(self_ty).is_ty_var() + }); + if constrained_opaque { + debug!("opaque type has been constrained"); + return true; + } + } + } + + false + } + /// Sometimes we get in a situation where we have multiple probes that are all impls of the /// same trait, but we don't know which impl to use. In this case, since in all cases the /// external interface of the method can be determined from the trait, it's ok not to decide. diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 024b9ee08c2..44602e62899 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1914,9 +1914,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(ref args) = call_args && fn_sig.inputs()[1..] .iter() - .zip(args.into_iter()) - .all(|(expected, found)| self.may_coerce(*expected, *found)) - && fn_sig.inputs()[1..].len() == args.len() + .eq_by(args, |expected, found| self.may_coerce(*expected, *found)) { err.span_suggestion_verbose( item_name.span, diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index 5cefa506b5a..4c1fe69405e 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -15,7 +15,7 @@ use crate::FnCtxt; impl<'tcx> FnCtxt<'_, 'tcx> { /// This takes all the opaque type uses during HIR typeck. It first computes - /// the concrete hidden type by iterating over all defining uses. + /// the hidden type by iterating over all defining uses. /// /// A use during HIR typeck is defining if all non-lifetime arguments are /// unique generic parameters and the hidden type does not reference any @@ -35,8 +35,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } debug!(?opaque_types); - self.compute_concrete_opaque_types(&opaque_types); - self.apply_computed_concrete_opaque_types(&opaque_types); + self.compute_definition_site_hidden_types(&opaque_types); + self.apply_definition_site_hidden_types(&opaque_types); } } @@ -71,7 +71,7 @@ impl<'tcx> UsageKind<'tcx> { } impl<'tcx> FnCtxt<'_, 'tcx> { - fn compute_concrete_opaque_types( + fn compute_definition_site_hidden_types( &mut self, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) { @@ -142,7 +142,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { self.typeck_results .borrow_mut() - .concrete_opaque_types + .hidden_types .insert(def_id, OpaqueHiddenType::new_error(tcx, guar)); self.set_tainted_by_errors(guar); } @@ -161,7 +161,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { ) { match err { NonDefiningUseReason::Tainted(guar) => { - self.typeck_results.borrow_mut().concrete_opaque_types.insert( + self.typeck_results.borrow_mut().hidden_types.insert( opaque_type_key.def_id, OpaqueHiddenType::new_error(self.tcx, guar), ); @@ -197,20 +197,19 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let prev = self .typeck_results .borrow_mut() - .concrete_opaque_types + .hidden_types .insert(opaque_type_key.def_id, hidden_type); assert!(prev.is_none()); UsageKind::HasDefiningUse } - fn apply_computed_concrete_opaque_types( + fn apply_definition_site_hidden_types( &mut self, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], ) { let tcx = self.tcx; for &(key, hidden_type) in opaque_types { - let expected = - *self.typeck_results.borrow_mut().concrete_opaque_types.get(&key.def_id).unwrap(); + let expected = *self.typeck_results.borrow_mut().hidden_types.get(&key.def_id).unwrap(); let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args); self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index f735c0a4160..46accb76a18 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -47,7 +47,7 @@ You can read more about trait objects in the Trait Objects section of the Refere 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)) + text.chars().all(|c: char| c.is_ascii_digit()) } /// Information about the expected type at the top level of type checking a pattern. @@ -262,8 +262,9 @@ enum InheritedRefMatchRule { /// pattern matches a given type: /// - If the underlying type is not a reference, a reference pattern may eat the inherited reference; /// - If the underlying type is a reference, a reference pattern matches if it can eat either one - /// of the underlying and inherited references. E.g. a `&mut` pattern is allowed if either the - /// underlying type is `&mut` or the inherited reference is `&mut`. + /// of the underlying and inherited references. E.g. a `&mut` pattern is allowed if either the + /// underlying type is `&mut` or the inherited reference is `&mut`. + /// /// If `false`, a reference pattern is only matched against the underlying type. /// This is `false` for stable Rust and `true` for both the `ref_pat_eat_one_layer_2024` and /// `ref_pat_eat_one_layer_2024_structural` feature gates. @@ -1069,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { if !self.tcx.features().mut_ref() { feature_err( - &self.tcx.sess, + self.tcx.sess, sym::mut_ref, pat.span.until(ident.span), "binding cannot be both mutable and by-reference", @@ -1487,31 +1488,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_def_id: Option<hir::def_id::DefId>, ident: Ident, ) -> bool { - match opt_def_id { - Some(def_id) => match self.tcx.hir_get_if_local(def_id) { - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Const(_, _, _, body_id), - .. - })) => match self.tcx.hir_node(body_id.hir_id) { - hir::Node::Expr(expr) => { - if hir::is_range_literal(expr) { - let span = self.tcx.hir_span(body_id.hir_id); - if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) { - e.span_suggestion_verbose( - ident.span, - "you may want to move the range into the match block", - snip, - Applicability::MachineApplicable, - ); - return true; - } - } - } - _ => (), - }, - _ => (), - }, - _ => (), + if let Some(def_id) = opt_def_id + && let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Const(_, _, _, body_id), + .. + })) = self.tcx.hir_get_if_local(def_id) + && let hir::Node::Expr(expr) = self.tcx.hir_node(body_id.hir_id) + && hir::is_range_literal(expr) + { + let span = self.tcx.hir_span(body_id.hir_id); + if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) { + e.span_suggestion_verbose( + ident.span, + "you may want to move the range into the match block", + snip, + Applicability::MachineApplicable, + ); + return true; + } } false } @@ -1529,7 +1523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(span) = self.tcx.hir_res_span(pat_res) { e.span_label(span, format!("{} defined here", res.descr())); - if let [hir::PathSegment { ident, .. }] = &*segments { + if let [hir::PathSegment { ident, .. }] = segments { e.span_label( pat_span, format!( @@ -1557,17 +1551,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => (None, None), }; - let is_range = match type_def_id.and_then(|id| self.tcx.as_lang_item(id)) { + let is_range = matches!( + type_def_id.and_then(|id| self.tcx.as_lang_item(id)), Some( LangItem::Range - | LangItem::RangeFrom - | LangItem::RangeTo - | LangItem::RangeFull - | LangItem::RangeInclusiveStruct - | LangItem::RangeToInclusive, - ) => true, - _ => false, - }; + | LangItem::RangeFrom + | LangItem::RangeTo + | LangItem::RangeFull + | LangItem::RangeInclusiveStruct + | LangItem::RangeToInclusive, + ) + ); if is_range { if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { let msg = "constants only support matching by type, \ diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 6192420898f..697029e55f7 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -550,13 +550,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn visit_opaque_types_next(&mut self) { let mut fcx_typeck_results = self.fcx.typeck_results.borrow_mut(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); - for hidden_ty in fcx_typeck_results.concrete_opaque_types.values() { + for hidden_ty in fcx_typeck_results.hidden_types.values() { assert!(!hidden_ty.has_infer()); } - assert_eq!(self.typeck_results.concrete_opaque_types.len(), 0); - self.typeck_results.concrete_opaque_types = - mem::take(&mut fcx_typeck_results.concrete_opaque_types); + assert_eq!(self.typeck_results.hidden_types.len(), 0); + self.typeck_results.hidden_types = mem::take(&mut fcx_typeck_results.hidden_types); } #[instrument(skip(self), level = "debug")] @@ -588,7 +587,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { hidden_type.span, DefiningScopeKind::HirTypeck, ) { - self.typeck_results.concrete_opaque_types.insert( + self.typeck_results.hidden_types.insert( opaque_type_key.def_id, ty::OpaqueHiddenType::new_error(tcx, err.report(self.fcx)), ); @@ -600,16 +599,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { DefiningScopeKind::HirTypeck, ); - if let Some(prev) = self - .typeck_results - .concrete_opaque_types - .insert(opaque_type_key.def_id, hidden_type) + if let Some(prev) = + self.typeck_results.hidden_types.insert(opaque_type_key.def_id, hidden_type) { - let entry = &mut self - .typeck_results - .concrete_opaque_types - .get_mut(&opaque_type_key.def_id) - .unwrap(); + let entry = + &mut self.typeck_results.hidden_types.get_mut(&opaque_type_key.def_id).unwrap(); if prev.ty != hidden_type.ty { if let Some(guar) = self.typeck_results.tainted_by_errors { entry.ty = Ty::new_error(tcx, guar); @@ -628,7 +622,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let recursive_opaques: Vec<_> = self .typeck_results - .concrete_opaque_types + .hidden_types .iter() .filter(|&(&def_id, hidden_ty)| { hidden_ty @@ -636,7 +630,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { .visit_with(&mut HasRecursiveOpaque { def_id, seen: Default::default(), - opaques: &self.typeck_results.concrete_opaque_types, + opaques: &self.typeck_results.hidden_types, tcx, }) .is_break() @@ -651,7 +645,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { .with_code(E0720) .emit(); self.typeck_results - .concrete_opaque_types + .hidden_types .insert(def_id, OpaqueHiddenType { span, ty: Ty::new_error(tcx, guar) }); } } @@ -1003,8 +997,10 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - debug_assert!(!r.is_bound(), "Should not be resolving bound region."); - self.fcx.tcx.lifetimes.re_erased + match r.kind() { + ty::ReBound(..) => r, + _ => self.fcx.tcx.lifetimes.re_erased, + } } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { diff --git a/compiler/rustc_index/src/idx.rs b/compiler/rustc_index/src/idx.rs index 9cd7134659c..2fb2008f9a3 100644 --- a/compiler/rustc_index/src/idx.rs +++ b/compiler/rustc_index/src/idx.rs @@ -130,12 +130,6 @@ impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeFrom<I> { impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeInclusive<I> { type Output = core::range::RangeInclusive<usize>; #[inline] - #[cfg(bootstrap)] - fn into_slice_idx(self) -> Self::Output { - core::range::RangeInclusive { start: self.start.index(), end: self.end.index() } - } - #[inline] - #[cfg(not(bootstrap))] fn into_slice_idx(self) -> Self::Output { core::range::RangeInclusive { start: self.start.index(), last: self.last.index() } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 3c5e4a91c98..e445def4faa 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -303,8 +303,6 @@ struct Canonicalizer<'cx, 'tcx> { sub_root_lookup_table: SsoHashMap<ty::TyVid, usize>, canonicalize_mode: &'cx dyn CanonicalizeMode, needs_canonical_flags: TypeFlags, - - binder_index: ty::DebruijnIndex, } impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { @@ -312,24 +310,12 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { self.tcx } - fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> - where - T: TypeFoldable<TyCtxt<'tcx>>, - { - self.binder_index.shift_in(1); - let t = t.super_fold_with(self); - self.binder_index.shift_out(1); - t - } - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r.kind() { - ty::ReBound(index, ..) => { - if index >= self.binder_index { - bug!("escaping late-bound region during canonicalization"); - } else { - r - } + ty::ReBound(ty::BoundVarIndexKind::Bound(_), ..) => r, + + ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => { + bug!("canonicalized bound var found during canonicalization"); } ty::ReStatic @@ -403,12 +389,10 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t) } - ty::Bound(debruijn, _) => { - if debruijn >= self.binder_index { - bug!("escaping bound type during canonicalization") - } else { - t - } + ty::Bound(ty::BoundVarIndexKind::Bound(_), _) => t, + + ty::Bound(ty::BoundVarIndexKind::Canonical, _) => { + bug!("canonicalized bound var found during canonicalization"); } ty::Closure(..) @@ -479,12 +463,11 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { ty::ConstKind::Infer(InferConst::Fresh(_)) => { bug!("encountered a fresh const during canonicalization") } - ty::ConstKind::Bound(debruijn, _) => { - if debruijn >= self.binder_index { - bug!("escaping bound const during canonicalization") - } else { - return ct; - } + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(_), _) => { + return ct; + } + ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, _) => { + bug!("canonicalized bound var found during canonicalization"); } ty::ConstKind::Placeholder(placeholder) => { return self @@ -569,7 +552,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { query_state, indices: FxHashMap::default(), sub_root_lookup_table: Default::default(), - binder_index: ty::INNERMOST, }; if canonicalizer.query_state.var_values.spilled() { canonicalizer.indices = canonicalizer @@ -751,8 +733,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { let var = self.canonical_var(var_kind, r.into()); - let br = ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }; - ty::Region::new_bound(self.cx(), self.binder_index, br) + ty::Region::new_canonical_bound(self.cx(), var) } /// Given a type variable `ty_var` of the given kind, first check @@ -766,8 +747,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { ) -> Ty<'tcx> { debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var))); let var = self.canonical_var(var_kind, ty_var.into()); - let bt = ty::BoundTy { var, kind: ty::BoundTyKind::Anon }; - Ty::new_bound(self.tcx, self.binder_index, bt) + Ty::new_canonical_bound(self.tcx, var) } /// Given a type variable `const_var` of the given kind, first check @@ -783,7 +763,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { !self.infcx.is_some_and(|infcx| ct_var != infcx.shallow_resolve_const(ct_var)) ); let var = self.canonical_var(var_kind, ct_var.into()); - let bc = ty::BoundConst { var }; - ty::Const::new_bound(self.tcx, self.binder_index, bc) + ty::Const::new_canonical_bound(self.tcx, var) } } diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index cc052fbd85c..c215a9db2a0 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::{ self, DelayedMap, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, }; -use rustc_type_ir::TypeVisitable; +use rustc_type_ir::{TypeFlags, TypeVisitable}; use crate::infer::canonical::{Canonical, CanonicalVarValues}; @@ -66,7 +66,6 @@ where value.fold_with(&mut CanonicalInstantiator { tcx, - current_index: ty::INNERMOST, var_values: var_values.var_values, cache: Default::default(), }) @@ -79,12 +78,9 @@ struct CanonicalInstantiator<'tcx> { // The values that the bound vars are are being instantiated with. var_values: ty::GenericArgsRef<'tcx>, - /// As with `BoundVarReplacer`, represents the index of a binder *just outside* - /// the ones we have visited. - current_index: ty::DebruijnIndex, - - // Instantiation is a pure function of `DebruijnIndex` and `Ty`. - cache: DelayedMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>, + // Because we use `ty::BoundVarIndexKind::Canonical`, we can cache + // based only on the entire ty, not worrying about a `DebruijnIndex` + cache: DelayedMap<Ty<'tcx>, Ty<'tcx>>, } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> { @@ -92,29 +88,19 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>( - &mut self, - t: ty::Binder<'tcx, T>, - ) -> ty::Binder<'tcx, T> { - self.current_index.shift_in(1); - let t = t.super_fold_with(self); - self.current_index.shift_out(1); - t - } - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match *t.kind() { - ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => { + ty::Bound(ty::BoundVarIndexKind::Canonical, bound_ty) => { self.var_values[bound_ty.var.as_usize()].expect_ty() } _ => { - if !t.has_vars_bound_at_or_above(self.current_index) { + if !t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { t - } else if let Some(&t) = self.cache.get(&(self.current_index, t)) { + } else if let Some(&t) = self.cache.get(&t) { t } else { let res = t.super_fold_with(self); - assert!(self.cache.insert((self.current_index, t), res)); + assert!(self.cache.insert(t, res)); res } } @@ -123,7 +109,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r.kind() { - ty::ReBound(debruijn, br) if debruijn == self.current_index => { + ty::ReBound(ty::BoundVarIndexKind::Canonical, br) => { self.var_values[br.var.as_usize()].expect_region() } _ => r, @@ -132,7 +118,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { - ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { + ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bound_const) => { self.var_values[bound_const.var.as_usize()].expect_const() } _ => ct.super_fold_with(self), @@ -140,22 +126,14 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> { } fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } + if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p } } fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> { - if !c.has_vars_bound_at_or_above(self.current_index) { + if !c.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { return c; } - // Since instantiation is a function of `DebruijnIndex`, we don't want - // to have to cache more copies of clauses when we're inside of binders. - // Since we currently expect to only have clauses in the outermost - // debruijn index, we just fold if we're inside of a binder. - if self.current_index > ty::INNERMOST { - return c.super_fold_with(self); - } - // Our cache key is `(clauses, var_values)`, but we also don't care about // var values that aren't named in the clauses, since they can change without // affecting the output. Since `ParamEnv`s are cached first, we compute the @@ -185,45 +163,29 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> { fn highest_var_in_clauses<'tcx>(c: ty::Clauses<'tcx>) -> usize { struct HighestVarInClauses { max_var: usize, - current_index: ty::DebruijnIndex, } impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HighestVarInClauses { - fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( - &mut self, - t: &ty::Binder<'tcx, T>, - ) -> Self::Result { - self.current_index.shift_in(1); - let t = t.super_visit_with(self); - self.current_index.shift_out(1); - t - } fn visit_ty(&mut self, t: Ty<'tcx>) { - if let ty::Bound(debruijn, bound_ty) = *t.kind() - && debruijn == self.current_index - { + if let ty::Bound(ty::BoundVarIndexKind::Canonical, bound_ty) = *t.kind() { self.max_var = self.max_var.max(bound_ty.var.as_usize()); - } else if t.has_vars_bound_at_or_above(self.current_index) { + } else if t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { t.super_visit_with(self); } } fn visit_region(&mut self, r: ty::Region<'tcx>) { - if let ty::ReBound(debruijn, bound_region) = r.kind() - && debruijn == self.current_index - { + if let ty::ReBound(ty::BoundVarIndexKind::Canonical, bound_region) = r.kind() { self.max_var = self.max_var.max(bound_region.var.as_usize()); } } fn visit_const(&mut self, ct: ty::Const<'tcx>) { - if let ty::ConstKind::Bound(debruijn, bound_const) = ct.kind() - && debruijn == self.current_index - { + if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bound_const) = ct.kind() { self.max_var = self.max_var.max(bound_const.var.as_usize()); - } else if ct.has_vars_bound_at_or_above(self.current_index) { + } else if ct.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { ct.super_visit_with(self); } } } - let mut visitor = HighestVarInClauses { max_var: 0, current_index: ty::INNERMOST }; + let mut visitor = HighestVarInClauses { max_var: 0 }; c.visit_with(&mut visitor); visitor.max_var } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 5d1b4be9e57..37a19605206 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -85,11 +85,29 @@ impl<'tcx> InferCtxt<'tcx> { where T: Debug + TypeFoldable<TyCtxt<'tcx>>, { + // While we ignore region constraints and pending obligations, + // we do return constrained opaque types to avoid unconstrained + // inference variables in the response. This is important as we want + // to check that opaques in deref steps stay unconstrained. + // + // This doesn't handle the more general case for non-opaques as + // ambiguous `Projection` obligations have same the issue. + let opaque_types = if self.next_trait_solver() { + self.inner + .borrow_mut() + .opaque_type_storage + .iter_opaque_types() + .map(|(k, v)| (k, v.ty)) + .collect() + } else { + vec![] + }; + self.canonicalize_response(QueryResponse { var_values: inference_vars, region_constraints: QueryRegionConstraints::default(), certainty: Certainty::Proven, // Ambiguities are OK! - opaque_types: vec![], + opaque_types, value: answer, }) } @@ -422,28 +440,28 @@ impl<'tcx> InferCtxt<'tcx> { // and only use it for placeholders. We need to handle the // `sub_root` of type inference variables which would make this // more involved. They are also a lot rarer than region variables. - if let ty::Bound(debruijn, b) = *result_value.kind() + if let ty::Bound(index_kind, b) = *result_value.kind() && !matches!( query_response.variables[b.var.as_usize()], CanonicalVarKind::Ty { .. } ) { - // We only allow a `ty::INNERMOST` index in generic parameters. - assert_eq!(debruijn, ty::INNERMOST); + // We only allow a `Canonical` index in generic parameters. + assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical)); opt_values[b.var] = Some(*original_value); } } GenericArgKind::Lifetime(result_value) => { - if let ty::ReBound(debruijn, b) = result_value.kind() { - // We only allow a `ty::INNERMOST` index in generic parameters. - assert_eq!(debruijn, ty::INNERMOST); + if let ty::ReBound(index_kind, b) = result_value.kind() { + // We only allow a `Canonical` index in generic parameters. + assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical)); opt_values[b.var] = Some(*original_value); } } GenericArgKind::Const(result_value) => { - if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() { - // We only allow a `ty::INNERMOST` index in generic parameters. - assert_eq!(debruijn, ty::INNERMOST); + if let ty::ConstKind::Bound(index_kind, b) = result_value.kind() { + // We only allow a `Canonical` index in generic parameters. + assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical)); opt_values[b.var] = Some(*original_value); } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c9fc124d3bf..f3ebfde06ab 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -131,23 +131,6 @@ pub struct InferCtxtInner<'tcx> { /// `$0: 'static`. This will get checked later by regionck. (We /// can't generally check these things right away because we have /// to wait until types are resolved.) - /// - /// These are stored in a map keyed to the id of the innermost - /// enclosing fn body / static initializer expression. This is - /// because the location where the obligation was incurred can be - /// relevant with respect to which sublifetime assumptions are in - /// place. The reason that we store under the fn-id, and not - /// something more fine-grained, is so that it is easier for - /// regionck to be sure that it has found *all* the region - /// obligations (otherwise, it's easy to fail to walk to a - /// particular node-id). - /// - /// Before running `resolve_regions_and_report_errors`, the creator - /// of the inference context is expected to invoke - /// [`InferCtxt::process_registered_region_obligations`] - /// for each body-id in this map, which will process the - /// obligations within. This is expected to be done 'late enough' - /// that all type inference variables have been bound and so forth. region_obligations: Vec<TypeOutlivesConstraint<'tcx>>, /// The outlives bounds that we assume must hold about placeholders that diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index b989d419057..a640dcb1b4e 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -170,6 +170,10 @@ impl<'tcx> InferCtxt<'tcx> { std::mem::take(&mut self.inner.borrow_mut().region_obligations) } + pub fn clone_registered_region_obligations(&self) -> Vec<TypeOutlivesConstraint<'tcx>> { + self.inner.borrow().region_obligations.clone() + } + pub fn register_region_assumption(&self, assumption: ty::ArgOutlivesPredicate<'tcx>) { let mut inner = self.inner.borrow_mut(); inner.undo_log.push(UndoLog::PushRegionAssumption); 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 f06eb58a371..6592360cf0a 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -44,8 +44,8 @@ pub fn extract_verify_if_eq<'tcx>( let verify_if_eq = verify_if_eq_b.skip_binder(); m.relate(verify_if_eq.ty, test_ty).ok()?; - if let ty::RegionKind::ReBound(depth, br) = verify_if_eq.bound.kind() { - assert!(depth == ty::INNERMOST); + if let ty::RegionKind::ReBound(index_kind, br) = verify_if_eq.bound.kind() { + assert!(matches!(index_kind, ty::BoundVarIndexKind::Bound(ty::INNERMOST))); match m.map.get(&br) { Some(&r) => Some(r), None => { @@ -156,7 +156,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx> pattern: ty::Region<'tcx>, value: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - if let ty::RegionKind::ReBound(depth, br) = pattern.kind() + if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(depth), br) = pattern.kind() && depth == self.pattern_depth { self.bind(br, value) diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl index 6f6666f8c76..1f5c5e74d97 100644 --- a/compiler/rustc_interface/messages.ftl +++ b/compiler/rustc_interface/messages.ftl @@ -47,7 +47,7 @@ interface_out_dir_error = failed to find or create the directory specified by `--out-dir` interface_proc_macro_crate_panic_abort = - building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic + building proc macro crate with `panic=abort` or `panic=immediate-abort` may crash the compiler should the proc-macro panic interface_temps_dir_error = failed to find or create the directory specified by `--temps-dir` diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 6cefe887530..c1bba0b0197 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -42,7 +42,6 @@ use rustc_span::{ DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym, }; -use rustc_target::spec::PanicStrategy; use rustc_trait_selection::{solve, traits}; use tracing::{info, instrument}; @@ -282,7 +281,7 @@ fn configure_and_expand( feature_err(sess, sym::export_stable, DUMMY_SP, "`sdylib` crate type is unstable").emit(); } - if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort { + if is_proc_macro_crate && !sess.panic_strategy().unwinds() { sess.dcx().emit_warn(errors::ProcMacroCratePanicAbort); } @@ -1123,18 +1122,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { sess.time("layout_testing", || layout_test::test_layout(tcx)); sess.time("abi_testing", || abi_test::test_abi(tcx)); - - // If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item - // (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs - // in MIR optimizations that may only be reachable through codegen, or other codepaths - // that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts. - if tcx.sess.opts.unstable_opts.validate_mir { - sess.time("ensuring_final_MIR_is_computable", || { - tcx.par_hir_body_owners(|def_id| { - tcx.instance_mir(ty::InstanceKind::Item(def_id.into())); - }); - }); - } } /// Runs the type-checking, region checking and other miscellaneous analysis @@ -1200,6 +1187,20 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { // we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally. let _ = tcx.all_diagnostic_items(()); }); + + // If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item + // (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs + // in MIR optimizations that may only be reachable through codegen, or other codepaths + // that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts. + // Nevertheless, wait after type checking is finished, as optimizing code that does not + // type-check is very prone to ICEs. + if tcx.sess.opts.unstable_opts.validate_mir { + sess.time("ensuring_final_MIR_is_computable", || { + tcx.par_hir_body_owners(|def_id| { + tcx.instance_mir(ty::InstanceKind::Item(def_id.into())); + }); + }); + } } /// Runs the codegen backend, after which the AST and analysis can diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 7730bddc0f1..7e5186db4ea 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -765,14 +765,15 @@ fn test_unstable_options_tracking_hash() { tracked!(allow_features, Some(vec![String::from("lang_items")])); tracked!(always_encode_mir, true); tracked!(assume_incomplete_release, true); - tracked!(autodiff, vec![AutoDiff::Enable]); + tracked!(autodiff, vec![AutoDiff::Enable, AutoDiff::NoTT]); tracked!(binary_dep_depinfo, true); tracked!(box_noalias, false); tracked!( branch_protection, Some(BranchProtection { bti: true, - pac_ret: Some(PacRet { leaf: true, pc: true, key: PAuthKey::B }) + pac_ret: Some(PacRet { leaf: true, pc: true, key: PAuthKey::B }), + gcs: true, }) ); tracked!(codegen_backend, Some("abc".to_string())); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 26e09c95e76..be2fd0787b9 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -1,3 +1,4 @@ +use std::any::Any; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -6,13 +7,20 @@ use std::{env, thread}; use rustc_ast as ast; use rustc_attr_parsing::{ShouldEmit, validate_attr}; +use rustc_codegen_ssa::back::archive::ArArchiveBuilderBuilder; +use rustc_codegen_ssa::back::link::link_binary; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_codegen_ssa::{CodegenResults, CrateInfo}; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::sync; use rustc_errors::LintBuffer; -use rustc_metadata::{DylibError, load_symbol_from_dylib}; -use rustc_middle::ty::CurrentGcx; -use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple}; +use rustc_metadata::{DylibError, EncodedMetadata, load_symbol_from_dylib}; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; +use rustc_middle::ty::{CurrentGcx, TyCtxt}; +use rustc_session::config::{ + Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple, +}; use rustc_session::output::{CRATE_TYPES, categorize_crate_type}; use rustc_session::{EarlyDiagCtxt, Session, filesearch, lint}; use rustc_span::edit_distance::find_best_match_for_name; @@ -316,12 +324,13 @@ pub fn get_codegen_backend( let backend = backend_name .or(target.default_codegen_backend.as_deref()) .or(option_env!("CFG_DEFAULT_CODEGEN_BACKEND")) - .unwrap_or("llvm"); + .unwrap_or("dummy"); match backend { filename if filename.contains('.') => { load_backend_from_dylib(early_dcx, filename.as_ref()) } + "dummy" => || Box::new(DummyCodegenBackend), #[cfg(feature = "llvm")] "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new, backend_name => get_codegen_sysroot(early_dcx, sysroot, backend_name), @@ -334,6 +343,63 @@ pub fn get_codegen_backend( unsafe { load() } } +struct DummyCodegenBackend; + +impl CodegenBackend for DummyCodegenBackend { + fn locale_resource(&self) -> &'static str { + "" + } + + fn name(&self) -> &'static str { + "dummy" + } + + fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> { + Box::new(CodegenResults { + modules: vec![], + allocator_module: None, + crate_info: CrateInfo::new(tcx, String::new()), + }) + } + + fn join_codegen( + &self, + ongoing_codegen: Box<dyn Any>, + _sess: &Session, + _outputs: &OutputFilenames, + ) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) { + (*ongoing_codegen.downcast().unwrap(), FxIndexMap::default()) + } + + fn link( + &self, + sess: &Session, + codegen_results: CodegenResults, + metadata: EncodedMetadata, + outputs: &OutputFilenames, + ) { + // JUSTIFICATION: TyCtxt no longer available here + #[allow(rustc::bad_opt_access)] + if sess.opts.crate_types.iter().any(|&crate_type| crate_type != CrateType::Rlib) { + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] + sess.dcx().fatal(format!( + "crate type {} not supported by the dummy codegen backend", + sess.opts.crate_types[0], + )); + } + + link_binary( + sess, + &ArArchiveBuilderBuilder, + codegen_results, + metadata, + outputs, + self.name(), + ); + } +} + // This is used for rustdoc, but it uses similar machinery to codegen backend // loading, so we leave the code here. It is potentially useful for other tools // that want to invoke the rustc binary while linking to rustc as well. @@ -386,8 +452,8 @@ fn get_codegen_sysroot( .collect::<Vec<_>>() .join("\n* "); let err = format!( - "failed to find a `codegen-backends` folder \ - in the sysroot candidates:\n* {candidates}" + "failed to find a `codegen-backends` folder in the sysroot candidates:\n\ + * {candidates}" ); early_dcx.early_fatal(err); }); @@ -396,10 +462,8 @@ fn get_codegen_sysroot( let d = sysroot.read_dir().unwrap_or_else(|e| { let err = format!( - "failed to load default codegen backend, couldn't \ - read `{}`: {}", + "failed to load default codegen backend, couldn't read `{}`: {e}", sysroot.display(), - e ); early_dcx.early_fatal(err); }); @@ -544,6 +608,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu stem, None, sess.io.temps_dir.clone(), + sess.opts.unstable_opts.split_dwarf_out_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) @@ -573,6 +638,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu out_filestem, ofile, sess.io.temps_dir.clone(), + sess.opts.unstable_opts.split_dwarf_out_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index c29ab569f47..f6790f7ed1e 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -599,14 +599,16 @@ impl Cursor<'_> { if potential_closing.is_none() { // a less fortunate recovery if all else fails which finds any dashes preceded by whitespace // on a standalone line. Might be wrong. + let mut base_index = 0; while let Some(closing) = rest.find("---") { let preceding_chars_start = rest[..closing].rfind("\n").map_or(0, |i| i + 1); if rest[preceding_chars_start..closing].chars().all(is_horizontal_whitespace) { // candidate found - potential_closing = Some(closing); + potential_closing = Some(closing + base_index); break; } else { rest = &rest[closing + 3..]; + base_index += closing + 3; } } } diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index dca22b986ff..b10be22dc38 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -1,11 +1,12 @@ use rustc_errors::MultiSpan; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; -use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind}; +use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind, find_attr}; use rustc_middle::ty::TyCtxt; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::def_id::{DefId, LOCAL_CRATE}; -use rustc_span::{ExpnKind, Span, kw, sym}; +use rustc_span::{ExpnKind, Span, kw}; use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag}; use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent}; @@ -241,7 +242,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { ) } ItemKind::Macro(_, _macro, _kinds) - if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) => + if find_attr!( + cx.tcx.get_all_attrs(item.owner_id.def_id), + AttributeKind::MacroExport { .. } + ) => { cx.emit_span_lint( NON_LOCAL_DEFINITIONS, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b79075ac09b..939f3d088b1 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2309,10 +2309,10 @@ declare_lint! { /// ### Example /// /// ```rust - /// #![cfg_attr(not(bootstrap), feature(sanitize))] + /// #![feature(sanitize)] /// /// #[inline(always)] - /// #[cfg_attr(not(bootstrap), sanitize(address = "off"))] + /// #[sanitize(address = "off")] /// fn x() {} /// /// fn main() { @@ -4191,8 +4191,13 @@ declare_lint! { /// You can't have multiple arguments in a `#[macro_export(..)]`, or mention arguments other than `local_inner_macros`. /// pub INVALID_MACRO_EXPORT_ARGUMENTS, - Warn, + Deny, "\"invalid_parameter\" isn't a valid argument for `#[macro_export]`", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseError, + reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>", + report_in_deps: true, + }; } declare_lint! { @@ -4832,16 +4837,13 @@ declare_lint! { /// /// ### Example /// - #[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")] - #[cfg_attr(bootstrap, doc = "```rust")] + /// ```rust,compile_fail /// #![doc = in_root!()] /// /// macro_rules! in_root { () => { "" } } /// /// fn main() {} - #[cfg_attr(not(bootstrap), doc = "```")] - #[cfg_attr(bootstrap, doc = "```")] - // ^ Needed to avoid tidy warning about odd number of backticks + /// ``` /// /// {{produces}} /// diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index 0dfd1b13df5..ad93c745381 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -10,8 +10,7 @@ libc = "0.2.73" [build-dependencies] # tidy-alphabetical-start -# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version -# per crate", so if you change this, you need to also change it in `rustc_codegen_ssa` and `rustc_windows_rc`. +# `cc` updates often break things, so we pin it here. cc = "=1.2.16" # tidy-alphabetical-end diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 7518b40799b..2e9fd6754f1 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -359,10 +359,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( return wrap(TM); } -extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) { - delete unwrap(TM); -} - // Unfortunately, the LLVM C API doesn't provide a way to create the // TargetLibraryInfo pass, so we use this method to do so. extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M, @@ -573,25 +569,43 @@ extern "C" LLVMRustResult LLVMRustOptimize( } std::optional<PGOOptions> PGOOpt; +#if LLVM_VERSION_LT(22, 0) auto FS = vfs::getRealFileSystem(); +#endif if (PGOGenPath) { assert(!PGOUsePath && !PGOSampleUsePath); PGOOpt = PGOOptions( +#if LLVM_VERSION_GE(22, 0) + PGOGenPath, "", "", "", PGOOptions::IRInstr, PGOOptions::NoCSAction, +#else PGOGenPath, "", "", "", FS, PGOOptions::IRInstr, PGOOptions::NoCSAction, +#endif PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling); } else if (PGOUsePath) { assert(!PGOSampleUsePath); PGOOpt = PGOOptions( +#if LLVM_VERSION_GE(22, 0) + PGOUsePath, "", "", "", PGOOptions::IRUse, PGOOptions::NoCSAction, +#else PGOUsePath, "", "", "", FS, PGOOptions::IRUse, PGOOptions::NoCSAction, +#endif PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling); } else if (PGOSampleUsePath) { PGOOpt = +#if LLVM_VERSION_GE(22, 0) + PGOOptions(PGOSampleUsePath, "", "", "", PGOOptions::SampleUse, +#else PGOOptions(PGOSampleUsePath, "", "", "", FS, PGOOptions::SampleUse, +#endif PGOOptions::NoCSAction, PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling); } else if (DebugInfoForProfiling) { PGOOpt = PGOOptions( +#if LLVM_VERSION_GE(22, 0) + "", "", "", "", PGOOptions::NoAction, PGOOptions::NoCSAction, +#else "", "", "", "", FS, PGOOptions::NoAction, PGOOptions::NoCSAction, +#endif PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling); } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 64151962321..2b83ea24ac6 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -553,6 +553,7 @@ enum class LLVMRustMemoryEffects { None, ReadOnly, InaccessibleMemOnly, + ReadOnlyNotPure, }; extern "C" LLVMAttributeRef @@ -568,6 +569,10 @@ LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C, case LLVMRustMemoryEffects::InaccessibleMemOnly: return wrap(Attribute::getWithMemoryEffects( *unwrap(C), MemoryEffects::inaccessibleMemOnly())); + case LLVMRustMemoryEffects::ReadOnlyNotPure: + return wrap(Attribute::getWithMemoryEffects( + *unwrap(C), + MemoryEffects::readOnly() | MemoryEffects::inaccessibleMemOnly())); default: report_fatal_error("bad MemoryEffects."); } @@ -985,14 +990,6 @@ extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind, unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD)); } -extern "C" LLVMDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) { - return wrap(new DIBuilder(*unwrap(M))); -} - -extern "C" void LLVMRustDIBuilderDispose(LLVMDIBuilderRef Builder) { - delete unwrap(Builder); -} - extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit( LLVMDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef, const char *Producer, size_t ProducerLen, bool isOptimized, @@ -1124,51 +1121,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( return wrap(VarExpr); } -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( - LLVMDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMDIFlags Flags, unsigned ArgNo, - uint32_t AlignInBits) { - if (Tag == 0x100) { // DW_TAG_auto_variable - return wrap(unwrap(Builder)->createAutoVariable( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), AlwaysPreserve, - fromRust(Flags), AlignInBits)); - } else { - return wrap(unwrap(Builder)->createParameterVariable( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ArgNo, - unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), AlwaysPreserve, - fromRust(Flags))); - } -} - -extern "C" LLVMMetadataRef -LLVMRustDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, int64_t Lo, - int64_t Count) { - return wrap(unwrap(Builder)->getOrCreateSubrange(Lo, Count)); -} - -extern "C" LLVMMetadataRef -LLVMRustDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder, - LLVMMetadataRef *Ptr, unsigned Count) { - Metadata **DataValue = unwrap(Ptr); - return wrap(unwrap(Builder) - ->getOrCreateArray(ArrayRef<Metadata *>(DataValue, Count)) - .get()); -} - -extern "C" void -LLVMRustDIBuilderInsertDeclareAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V, - LLVMMetadataRef VarInfo, uint64_t *AddrOps, - unsigned AddrOpsCount, LLVMMetadataRef DL, - LLVMBasicBlockRef InsertAtEnd) { - unwrap(Builder)->insertDeclare( - unwrap(V), unwrap<DILocalVariable>(VarInfo), - unwrap(Builder)->createExpression( - llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)), - DebugLoc(cast<MDNode>(unwrap(DL))), unwrap(InsertAtEnd)); -} - extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name, size_t NameLen, const uint64_t Value[2], @@ -1680,6 +1632,14 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler( RemarkStreamer(std::move(RemarkStreamer)), LlvmRemarkStreamer(std::move(LlvmRemarkStreamer)) {} +#if LLVM_VERSION_GE(22, 0) + ~RustDiagnosticHandler() { + if (RemarkStreamer) { + RemarkStreamer->releaseSerializer(); + } + } +#endif + virtual bool handleDiagnostics(const DiagnosticInfo &DI) override { // If this diagnostic is one of the optimization remark kinds, we can // check if it's enabled before emitting it. This can avoid many @@ -1774,9 +1734,14 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler( // Do not delete the file after we gather remarks RemarkFile->keep(); +#if LLVM_VERSION_GE(22, 0) + auto RemarkSerializer = remarks::createRemarkSerializer( + llvm::remarks::Format::YAML, RemarkFile->os()); +#else auto RemarkSerializer = remarks::createRemarkSerializer( llvm::remarks::Format::YAML, remarks::SerializerMode::Separate, RemarkFile->os()); +#endif if (Error E = RemarkSerializer.takeError()) { std::string Error = std::string("Cannot create remark serializer: ") + toString(std::move(E)); @@ -1847,3 +1812,67 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) { MD.NoHWAddress = true; GV.setSanitizerMetadata(MD); } + +#ifdef ENZYME +extern "C" { +extern llvm::cl::opt<unsigned> EnzymeMaxTypeDepth; +} + +extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() { return EnzymeMaxTypeDepth; } +#else +extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() { + return 6; // Default fallback depth +} +#endif + +// Statically assert that the fixed metadata kind IDs declared in +// `metadata_kind.rs` match the ones actually used by LLVM. +#define FIXED_MD_KIND(VARIANT, VALUE) \ + static_assert(::llvm::LLVMContext::VARIANT == VALUE); +// Must be kept in sync with the corresponding list in `metadata_kind.rs`. +FIXED_MD_KIND(MD_dbg, 0) +FIXED_MD_KIND(MD_tbaa, 1) +FIXED_MD_KIND(MD_prof, 2) +FIXED_MD_KIND(MD_fpmath, 3) +FIXED_MD_KIND(MD_range, 4) +FIXED_MD_KIND(MD_tbaa_struct, 5) +FIXED_MD_KIND(MD_invariant_load, 6) +FIXED_MD_KIND(MD_alias_scope, 7) +FIXED_MD_KIND(MD_noalias, 8) +FIXED_MD_KIND(MD_nontemporal, 9) +FIXED_MD_KIND(MD_mem_parallel_loop_access, 10) +FIXED_MD_KIND(MD_nonnull, 11) +FIXED_MD_KIND(MD_dereferenceable, 12) +FIXED_MD_KIND(MD_dereferenceable_or_null, 13) +FIXED_MD_KIND(MD_make_implicit, 14) +FIXED_MD_KIND(MD_unpredictable, 15) +FIXED_MD_KIND(MD_invariant_group, 16) +FIXED_MD_KIND(MD_align, 17) +FIXED_MD_KIND(MD_loop, 18) +FIXED_MD_KIND(MD_type, 19) +FIXED_MD_KIND(MD_section_prefix, 20) +FIXED_MD_KIND(MD_absolute_symbol, 21) +FIXED_MD_KIND(MD_associated, 22) +FIXED_MD_KIND(MD_callees, 23) +FIXED_MD_KIND(MD_irr_loop, 24) +FIXED_MD_KIND(MD_access_group, 25) +FIXED_MD_KIND(MD_callback, 26) +FIXED_MD_KIND(MD_preserve_access_index, 27) +FIXED_MD_KIND(MD_vcall_visibility, 28) +FIXED_MD_KIND(MD_noundef, 29) +FIXED_MD_KIND(MD_annotation, 30) +FIXED_MD_KIND(MD_nosanitize, 31) +FIXED_MD_KIND(MD_func_sanitize, 32) +FIXED_MD_KIND(MD_exclude, 33) +FIXED_MD_KIND(MD_memprof, 34) +FIXED_MD_KIND(MD_callsite, 35) +FIXED_MD_KIND(MD_kcfi_type, 36) +FIXED_MD_KIND(MD_pcsections, 37) +FIXED_MD_KIND(MD_DIAssignID, 38) +FIXED_MD_KIND(MD_coro_outside_frame, 39) +FIXED_MD_KIND(MD_mmra, 40) +FIXED_MD_KIND(MD_noalias_addrspace, 41) +// If some fixed metadata kinds are not present and consistent in all supported +// LLVM versions, it's fine to omit them from this list; in that case Rust-side +// code cannot declare them as fixed IDs and must look them up by name instead. +#undef FIXED_MD_KIND diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 5821ffa3a30..5d32950875a 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -5,7 +5,7 @@ use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ AttrStyle, Attribute, Block, Error, Expr, Ident, Pat, ReturnType, Token, Type, braced, - parenthesized, parse_macro_input, parse_quote, token, + parenthesized, parse_macro_input, token, }; mod kw { diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index e104be2c466..e624bfc5b8b 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -98,6 +98,13 @@ metadata_full_metadata_not_found = metadata_global_alloc_required = no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait +metadata_incompatible_with_immediate_abort = + the crate `{$crate_name}` was compiled with a panic strategy which is incompatible with `immediate-abort` + +metadata_incompatible_with_immediate_abort_core = + the crate `core` was compiled with a panic strategy which is incompatible with `immediate-abort` + .help = consider building the standard library from source with `cargo build -Zbuild-std` + metadata_incompatible_panic_in_drop_strategy = the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 9e23da88f5e..7650acbd292 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1027,6 +1027,10 @@ impl CStore { let name = match desired_strategy { PanicStrategy::Unwind => sym::panic_unwind, PanicStrategy::Abort => sym::panic_abort, + PanicStrategy::ImmediateAbort => { + // Immediate-aborting panics don't use a runtime. + return; + } }; info!("panic runtime not found -- loading {}", name); diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index fb9c2e23b71..8054a48d37a 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -61,11 +61,13 @@ use rustc_session::config::CrateType; use rustc_session::cstore::CrateDepKind; use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic}; use rustc_span::sym; +use rustc_target::spec::PanicStrategy; use tracing::info; use crate::creader::CStore; use crate::errors::{ - BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired, + BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, + IncompatibleWithImmediateAbort, IncompatibleWithImmediateAbortCore, LibRequired, NonStaticCrateDep, RequiredPanicStrategy, RlibRequired, RustcDriverHelp, RustcLibRequired, TwoPanicRuntimes, }; @@ -402,15 +404,43 @@ fn activate_injected_dep( /// there's only going to be one panic runtime in the output. fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) { let sess = &tcx.sess; + let list: Vec<_> = list + .iter_enumerated() + .filter_map( + |(cnum, linkage)| if *linkage == Linkage::NotLinked { None } else { Some(cnum) }, + ) + .collect(); if list.is_empty() { return; } - let mut panic_runtime = None; - for (cnum, linkage) in list.iter_enumerated() { - if let Linkage::NotLinked = *linkage { - continue; + let desired_strategy = sess.panic_strategy(); + + // If we are panic=immediate-abort, make sure everything in the dependency tree has also been + // compiled with immediate-abort. + if list + .iter() + .any(|cnum| tcx.required_panic_strategy(*cnum) == Some(PanicStrategy::ImmediateAbort)) + { + let mut invalid_crates = Vec::new(); + for cnum in list.iter().copied() { + if tcx.required_panic_strategy(cnum) != Some(PanicStrategy::ImmediateAbort) { + invalid_crates.push(cnum); + // If core is incompatible, it's very likely that we'd emit an error for every + // sysroot crate, so instead of doing that emit a single fatal error that suggests + // using build-std. + if tcx.crate_name(cnum) == sym::core { + sess.dcx().emit_fatal(IncompatibleWithImmediateAbortCore); + } + } } + for cnum in invalid_crates { + sess.dcx() + .emit_err(IncompatibleWithImmediateAbort { crate_name: tcx.crate_name(cnum) }); + } + } + let mut panic_runtime = None; + for cnum in list.iter().copied() { if tcx.is_panic_runtime(cnum) { if let Some((prev, _)) = panic_runtime { let prev_name = tcx.crate_name(prev); @@ -430,8 +460,6 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) { // only one, but we perform validation here that all the panic strategy // compilation modes for the whole DAG are valid. if let Some((runtime_cnum, found_strategy)) = panic_runtime { - let desired_strategy = sess.panic_strategy(); - // First up, validate that our selected panic runtime is indeed exactly // our same strategy. if found_strategy != desired_strategy { @@ -445,10 +473,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) { // strategy. If the dep isn't linked, we ignore it, and if our strategy // is abort then it's compatible with everything. Otherwise all crates' // panic strategy must match our own. - for (cnum, linkage) in list.iter_enumerated() { - if let Linkage::NotLinked = *linkage { - continue; - } + for cnum in list.iter().copied() { if cnum == runtime_cnum || tcx.is_compiler_builtins(cnum) { continue; } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index e5a4fd48353..abfd078f746 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -76,6 +76,16 @@ pub struct RequiredPanicStrategy { } #[derive(Diagnostic)] +#[diag(metadata_incompatible_with_immediate_abort)] +pub struct IncompatibleWithImmediateAbort { + pub crate_name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(metadata_incompatible_with_immediate_abort_core)] +pub struct IncompatibleWithImmediateAbortCore; + +#[derive(Diagnostic)] #[diag(metadata_incompatible_panic_in_drop_strategy)] pub struct IncompatiblePanicInDropStrategy { pub crate_name: Symbol, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 0c8d1f32e99..b895feb9062 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1555,7 +1555,7 @@ impl<'a> CrateMetadataRef<'a> { } #[inline] - fn def_path_hash_to_def_index(self, hash: DefPathHash) -> DefIndex { + fn def_path_hash_to_def_index(self, hash: DefPathHash) -> Option<DefIndex> { self.def_path_hash_map.def_path_hash_to_def_index(&hash) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 11fef3be5d0..df3add316ec 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -691,8 +691,8 @@ fn provide_cstore_hooks(providers: &mut Providers) { .get(&stable_crate_id) .unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}")); assert_ne!(cnum, LOCAL_CRATE); - let def_index = cstore.get_crate_data(cnum).def_path_hash_to_def_index(hash); - DefId { krate: cnum, index: def_index } + let def_index = cstore.get_crate_data(cnum).def_path_hash_to_def_index(hash)?; + Some(DefId { krate: cnum, index: def_index }) }; providers.hooks.expn_hash_to_expn_id = |tcx, cnum, index_guess, hash| { 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 f3917b55782..a17b3e1047d 100644 --- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs +++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs @@ -12,11 +12,12 @@ pub(crate) enum DefPathHashMapRef<'tcx> { impl DefPathHashMapRef<'_> { #[inline] - pub(crate) fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex { + pub(crate) fn def_path_hash_to_def_index( + &self, + def_path_hash: &DefPathHash, + ) -> Option<DefIndex> { match *self { - DefPathHashMapRef::OwnedFromMetadata(ref map) => { - map.get(&def_path_hash.local_hash()).unwrap() - } + DefPathHashMapRef::OwnedFromMetadata(ref map) => map.get(&def_path_hash.local_hash()), DefPathHashMapRef::BorrowedFromTcx(_) => { panic!("DefPathHashMap::BorrowedFromTcx variant only exists for serialization") } diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 279ab9a9d8f..82f3df8da3b 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -98,6 +98,12 @@ middle_layout_references_error = middle_layout_size_overflow = values of the type `{$ty}` are too big for the target architecture +middle_layout_simd_too_many = + the SIMD type `{$ty}` has more elements than the limit {$max_lanes} + +middle_layout_simd_zero_length = + the SIMD type `{$ty}` has zero elements + middle_layout_too_generic = the type `{$ty}` does not have a fixed layout middle_layout_unknown = diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 52fbe19c9f2..feaad5bb96e 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -27,7 +27,7 @@ macro_rules! arena_types { rustc_middle::mir::Body<'tcx> >, [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>, - [decode] borrowck_result: rustc_middle::mir::ConcreteOpaqueTypes<'tcx>, + [decode] borrowck_result: rustc_middle::mir::DefinitionSiteHiddenTypes<'tcx>, [] resolver: rustc_data_structures::steal::Steal<( rustc_middle::ty::ResolverAstLowering, std::sync::Arc<rustc_ast::Crate>, @@ -109,7 +109,6 @@ macro_rules! arena_types { rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>> >, [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<rustc_middle::ty::TyCtxt<'tcx>>, - [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<rustc_middle::ty::TyCtxt<'tcx>>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, [] stripped_cfg_items: rustc_hir::attrs::StrippedCfgItem, [] mod_child: rustc_middle::metadata::ModChild, diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index e3e1393b5f9..3ff9eea8cc4 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -37,7 +37,6 @@ pub(crate) struct OpaqueHiddenTypeMismatch<'tcx> { pub sub: TypeMismatchReason, } -// FIXME(autodiff): I should get used somewhere #[derive(Diagnostic)] #[diag(middle_unsupported_union)] pub struct UnsupportedUnion { @@ -143,6 +142,12 @@ pub enum LayoutError<'tcx> { #[diag(middle_layout_size_overflow)] Overflow { ty: Ty<'tcx> }, + #[diag(middle_layout_simd_too_many)] + SimdTooManyLanes { ty: Ty<'tcx>, max_lanes: u64 }, + + #[diag(middle_layout_simd_zero_length)] + SimdZeroLength { ty: Ty<'tcx> }, + #[diag(middle_layout_normalization_failure)] NormalizationFailure { ty: Ty<'tcx>, failure_ty: String }, diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 9d2f0a45237..dc6a3334a4c 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -77,7 +77,7 @@ declare_hooks! { /// session, if it still exists. This is used during incremental compilation to /// turn a deserialized `DefPathHash` into its current `DefId`. /// Will fetch a DefId from a DefPathHash for a foreign crate. - hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> DefId; + hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> Option<DefId>; /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we /// can just link to the upstream crate and therefore don't need a mono item. diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 5023b2740ef..754a258eef9 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,7 +29,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::direct_use_of_rustc_type_ir)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(round_char_boundary))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs index 5a811321f58..a7f0095dcdf 100644 --- a/compiler/rustc_middle/src/middle/debugger_visualizer.rs +++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs @@ -1,15 +1,9 @@ use std::path::PathBuf; use std::sync::Arc; +use rustc_hir::attrs::DebuggerVisualizerType; use rustc_macros::{Decodable, Encodable, HashStable}; -#[derive(HashStable)] -#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] -pub enum DebuggerVisualizerType { - Natvis, - GdbPrettyPrinter, -} - /// A single debugger visualizer file. #[derive(HashStable)] #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)] diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 93264f02cc2..a0e4c288c4a 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -98,5 +98,6 @@ pub fn required(tcx: TyCtxt<'_>, lang_item: LangItem) -> bool { lang_item != LangItem::EhPersonality && lang_item != LangItem::EhCatchTypeinfo } PanicStrategy::Unwind => true, + PanicStrategy::ImmediateAbort => false, } } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 7c72a8ec243..951aac503fe 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -499,10 +499,7 @@ pub enum ValidationErrorKind<'tcx> { MutableRefInConst, NullFnPtr, NeverVal, - NullablePtrOutOfRange { - range: WrappingRange, - max_value: u128, - }, + NonnullPtrMaybeNull, PtrOutOfRange { range: WrappingRange, max_value: u128, @@ -544,6 +541,8 @@ pub enum ValidationErrorKind<'tcx> { }, NullPtr { ptr_kind: PointerKind, + /// Records whether this pointer is definitely null or just may be null. + maybe: bool, }, DanglingPtrNoProvenance { ptr_kind: PointerKind, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 96148fd5b92..350d75c2ee7 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1274,7 +1274,6 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> for &elem in projection.iter().rev() { match elem { ProjectionElem::OpaqueCast(_) - | ProjectionElem::Subtype(_) | ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { write!(fmt, "(")?; @@ -1300,9 +1299,6 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> ProjectionElem::OpaqueCast(ty) => { write!(fmt, " as {ty})")?; } - ProjectionElem::Subtype(ty) => { - write!(fmt, " as subtype {ty})")?; - } ProjectionElem::Downcast(Some(name), _index) => { write!(fmt, " as {name})")?; } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index a509c40c89c..2e6c9f207e2 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -84,11 +84,10 @@ impl Debug for CoroutineLayout<'_> { } } -/// All the opaque types that are restricted to concrete types -/// by this function. Unlike the value in `TypeckResults`, this has -/// unerased regions. +/// All the opaque types that have had their hidden type fully computed. +/// Unlike the value in `TypeckResults`, this has unerased regions. #[derive(Default, Debug, TyEncodable, TyDecodable, HashStable)] -pub struct ConcreteOpaqueTypes<'tcx>(pub FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>); +pub struct DefinitionSiteHiddenTypes<'tcx>(pub FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>); /// The result of the `mir_const_qualif` query. /// diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 28294b47e90..e009fe05b53 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -222,7 +222,6 @@ impl<'tcx> PlaceTy<'tcx> { fty, )), ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)), - ProjectionElem::Subtype(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)), // FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general. ProjectionElem::UnwrapUnsafeBinder(ty) => { @@ -244,7 +243,6 @@ impl<V, T> ProjectionElem<V, T> { Self::Field(_, _) | Self::Index(_) | Self::OpaqueCast(_) - | Self::Subtype(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } | Self::Downcast(_, _) @@ -259,7 +257,6 @@ impl<V, T> ProjectionElem<V, T> { Self::Deref | Self::Index(_) => false, Self::Field(_, _) | Self::OpaqueCast(_) - | Self::Subtype(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } | Self::Downcast(_, _) @@ -286,7 +283,6 @@ impl<V, T> ProjectionElem<V, T> { | Self::Field(_, _) => true, Self::ConstantIndex { from_end: true, .. } | Self::Index(_) - | Self::Subtype(_) | Self::OpaqueCast(_) | Self::Subslice { .. } => false, @@ -319,7 +315,6 @@ impl<V, T> ProjectionElem<V, T> { ProjectionElem::Subslice { from, to, from_end } } ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(t(ty)), - ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(t(ty)), ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(t(ty)), ProjectionElem::Index(val) => ProjectionElem::Index(v(val)?), }) @@ -706,7 +701,8 @@ impl<'tcx> Rvalue<'tcx> { | CastKind::PtrToPtr | CastKind::PointerCoercion(_, _) | CastKind::PointerWithExposedProvenance - | CastKind::Transmute, + | CastKind::Transmute + | CastKind::Subtype, _, _, ) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index e6c8512564e..a823c365394 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1275,18 +1275,6 @@ pub enum ProjectionElem<V, T> { /// A transmute from an unsafe binder to the type that it wraps. This is a projection /// of a place, so it doesn't necessarily constitute a move out of the binder. UnwrapUnsafeBinder(T), - - /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where - /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping - /// explicit during optimizations and codegen. - /// - /// This projection doesn't impact the runtime behavior of the program except for potentially changing - /// some type metadata of the interpreter or codegen backend. - /// - /// This goal is achieved with mir_transform pass `Subtyper`, which runs right after - /// borrowchecker, as we only care about subtyping that can affect trait selection and - /// `TypeId`. - Subtype(T), } /// Alias for projections as they appear in places, where the base is a place @@ -1513,6 +1501,18 @@ pub enum CastKind { /// MIR is well-formed if the input and output types have different sizes, /// but running a transmute between differently-sized types is UB. Transmute, + + /// A `Subtype` cast is applied to any `StatementKind::Assign` where + /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping + /// explicit during optimizations and codegen. + /// + /// This cast doesn't impact the runtime behavior of the program except for potentially changing + /// some type metadata of the interpreter or codegen backend. + /// + /// This goal is achieved with mir_transform pass `Subtyper`, which runs right after + /// borrowchecker, as we only care about subtyping that can affect trait selection and + /// `TypeId`. + Subtype, } /// Represents how a [`CastKind::PointerCoercion`] was constructed. diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 81df239dee4..f3923477800 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1166,11 +1166,6 @@ macro_rules! visit_place_fns { self.visit_ty(&mut new_ty, TyContext::Location(location)); if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None } } - PlaceElem::Subtype(ty) => { - let mut new_ty = ty; - self.visit_ty(&mut new_ty, TyContext::Location(location)); - if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None } - } PlaceElem::UnwrapUnsafeBinder(ty) => { let mut new_ty = ty; self.visit_ty(&mut new_ty, TyContext::Location(location)); @@ -1244,7 +1239,6 @@ macro_rules! visit_place_fns { ) { match elem { ProjectionElem::OpaqueCast(ty) - | ProjectionElem::Subtype(ty) | ProjectionElem::Field(_, ty) | ProjectionElem::UnwrapUnsafeBinder(ty) => { self.visit_ty(ty, TyContext::Location(location)); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0e645a3aae4..895c8c0295a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -124,7 +124,7 @@ use crate::query::plumbing::{ }; use crate::traits::query::{ CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal, - CanonicalPredicateGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, + CanonicalMethodAutoderefStepsGoal, CanonicalPredicateGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, DropckConstraint, DropckOutlivesResult, MethodAutoderefStepsResult, NoSolution, NormalizationResult, OutlivesBound, @@ -1244,7 +1244,7 @@ rustc_queries! { /// Borrow-checks the given typeck root, e.g. functions, const/static items, /// and its children, e.g. closures, inline consts. - query mir_borrowck(key: LocalDefId) -> Result<&'tcx mir::ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> { + query mir_borrowck(key: LocalDefId) -> Result<&'tcx mir::DefinitionSiteHiddenTypes<'tcx>, ErrorGuaranteed> { desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) } } @@ -2559,9 +2559,9 @@ rustc_queries! { } query method_autoderef_steps( - goal: CanonicalTyGoal<'tcx> + goal: CanonicalMethodAutoderefStepsGoal<'tcx> ) -> MethodAutoderefStepsResult<'tcx> { - desc { "computing autoderef types for `{}`", goal.canonical.value.value } + desc { "computing autoderef types for `{}`", goal.canonical.value.value.self_ty } } /// Used by `-Znext-solver` to compute proof trees. diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 3f6faa1a572..c5cd7c54e4e 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -10,6 +10,7 @@ use rustc_span::Span; use crate::error::DropCheckOverflow; use crate::infer::canonical::{Canonical, CanonicalQueryInput, QueryResponse}; +use crate::traits::solve; pub use crate::traits::solve::NoSolution; use crate::ty::{self, GenericArg, Ty, TyCtxt}; @@ -67,7 +68,16 @@ pub mod type_op { pub type CanonicalAliasGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>; -pub type CanonicalTyGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; +pub type CanonicalMethodAutoderefStepsGoal<'tcx> = + CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, MethodAutoderefSteps<'tcx>>>; +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] +pub struct MethodAutoderefSteps<'tcx> { + /// The list of opaque types currently in the storage. + /// + /// Only used by the new solver for now. + pub predefined_opaques_in_body: solve::PredefinedOpaques<'tcx>, + pub self_ty: Ty<'tcx>, +} pub type CanonicalPredicateGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; @@ -144,6 +154,7 @@ impl<'tcx> FromIterator<DropckConstraint<'tcx>> for DropckConstraint<'tcx> { #[derive(Debug, HashStable)] pub struct CandidateStep<'tcx> { pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, + pub self_ty_is_opaque: bool, pub autoderefs: usize, /// `true` if the type results from a dereference of a raw pointer. /// when assembling candidates, we include these steps, but not when diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index ef5223de0e8..3343f270333 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -4,7 +4,7 @@ use rustc_type_ir as ir; pub use rustc_type_ir::solve::*; use crate::ty::{ - self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, + self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, try_visit, }; @@ -15,16 +15,7 @@ pub type CandidateSource<'tcx> = ir::solve::CandidateSource<TyCtxt<'tcx>>; pub type CanonicalInput<'tcx, P = ty::Predicate<'tcx>> = ir::solve::CanonicalInput<TyCtxt<'tcx>, P>; pub type CanonicalResponse<'tcx> = ir::solve::CanonicalResponse<TyCtxt<'tcx>>; -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] -pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<TyCtxt<'tcx>>>); - -impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { - type Target = PredefinedOpaquesData<TyCtxt<'tcx>>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} +pub type PredefinedOpaques<'tcx> = &'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>; #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] pub struct ExternalConstraints<'tcx>( @@ -93,35 +84,3 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> { self.normalization_nested_goals.visit_with(visitor) } } - -// FIXME: Having to clone `region_constraints` for folding feels bad and -// probably isn't great wrt performance. -// -// Not sure how to fix this, maybe we should also intern `opaque_types` and -// `region_constraints` here or something. -impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> { - fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( - self, - folder: &mut F, - ) -> Result<Self, F::Error> { - Ok(FallibleTypeFolder::cx(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData { - opaque_types: self - .opaque_types - .iter() - .map(|opaque| opaque.try_fold_with(folder)) - .collect::<Result<_, F::Error>>()?, - })) - } - - fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self { - TypeFolder::cx(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData { - opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), - }) - } -} - -impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> { - fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { - self.opaque_types.visit_with(visitor) - } -} diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 614b6471f18..95adb561c70 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -95,7 +95,15 @@ impl<'tcx> Const<'tcx> { debruijn: ty::DebruijnIndex, bound_const: ty::BoundConst, ) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Bound(debruijn, bound_const)) + Const::new(tcx, ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const)) + } + + #[inline] + pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Const<'tcx> { + Const::new( + tcx, + ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, ty::BoundConst { var }), + ) } #[inline] @@ -180,6 +188,10 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> { Const::new_bound(tcx, debruijn, ty::BoundConst { var }) } + fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: rustc_type_ir::BoundVar) -> Self { + Const::new_canonical_bound(tcx, var) + } + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Self { Const::new_placeholder(tcx, placeholder) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7d3e2c9965d..1b89a49cf98 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -75,7 +75,7 @@ use crate::thir::Thir; use crate::traits; use crate::traits::solve::{ self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, - PredefinedOpaquesData, QueryResult, inspect, + QueryResult, inspect, }; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ @@ -116,7 +116,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn mk_predefined_opaques_in_body( self, - data: PredefinedOpaquesData<Self>, + data: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)], ) -> Self::PredefinedOpaques { self.mk_predefined_opaques_in_body(data) } @@ -941,7 +941,7 @@ pub struct CtxtInterners<'tcx> { layout: InternedSet<'tcx, LayoutData<FieldIdx, VariantIdx>>, adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>, - predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<TyCtxt<'tcx>>>, + predefined_opaques_in_body: InternedSet<'tcx, List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>>, fields: InternedSet<'tcx, List<FieldIdx>>, local_def_ids: InternedSet<'tcx, List<LocalDefId>>, captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, @@ -1110,6 +1110,15 @@ const NUM_PREINTERNED_FRESH_TYS: u32 = 20; const NUM_PREINTERNED_FRESH_INT_TYS: u32 = 3; const NUM_PREINTERNED_FRESH_FLOAT_TYS: u32 = 3; const NUM_PREINTERNED_ANON_BOUND_TYS_I: u32 = 3; + +// From general profiling of the *max vars during canonicalization* of a value: +// - about 90% of the time, there are no canonical vars +// - about 9% of the time, there is only one canonical var +// - there are rarely more than 3-5 canonical vars (with exceptions in particularly pathological cases) +// This may not match the number of bound vars found in `for`s. +// Given that this is all heap interned, it seems likely that interning fewer +// vars here won't make an appreciable difference. Though, if we were to inline the data (in an array), +// we may want to consider reducing the number for canonicalized vars down to 4 or so. const NUM_PREINTERNED_ANON_BOUND_TYS_V: u32 = 20; // This number may seem high, but it is reached in all but the smallest crates. @@ -1160,9 +1169,14 @@ pub struct CommonTypes<'tcx> { pub fresh_float_tys: Vec<Ty<'tcx>>, /// Pre-interned values of the form: - /// `Bound(DebruijnIndex(i), BoundTy { var: v, kind: BoundTyKind::Anon})` + /// `Bound(BoundVarIndexKind::Bound(DebruijnIndex(i)), BoundTy { var: v, kind: BoundTyKind::Anon})` /// for small values of `i` and `v`. pub anon_bound_tys: Vec<Vec<Ty<'tcx>>>, + + // Pre-interned values of the form: + // `Bound(BoundVarIndexKind::Canonical, BoundTy { var: v, kind: BoundTyKind::Anon })` + // for small values of `v`. + pub anon_canonical_bound_tys: Vec<Ty<'tcx>>, } pub struct CommonLifetimes<'tcx> { @@ -1176,9 +1190,14 @@ pub struct CommonLifetimes<'tcx> { pub re_vars: Vec<Region<'tcx>>, /// Pre-interned values of the form: - /// `ReBound(DebruijnIndex(i), BoundRegion { var: v, kind: BoundRegionKind::Anon })` + /// `ReBound(BoundVarIndexKind::Bound(DebruijnIndex(i)), BoundRegion { var: v, kind: BoundRegionKind::Anon })` /// for small values of `i` and `v`. pub anon_re_bounds: Vec<Vec<Region<'tcx>>>, + + // Pre-interned values of the form: + // `ReBound(BoundVarIndexKind::Canonical, BoundRegion { var: v, kind: BoundRegionKind::Anon })` + // for small values of `v`. + pub anon_re_canonical_bounds: Vec<Region<'tcx>>, } pub struct CommonConsts<'tcx> { @@ -1211,7 +1230,7 @@ impl<'tcx> CommonTypes<'tcx> { (0..NUM_PREINTERNED_ANON_BOUND_TYS_V) .map(|v| { mk(ty::Bound( - ty::DebruijnIndex::from(i), + ty::BoundVarIndexKind::Bound(ty::DebruijnIndex::from(i)), ty::BoundTy { var: ty::BoundVar::from(v), kind: ty::BoundTyKind::Anon }, )) }) @@ -1219,6 +1238,15 @@ impl<'tcx> CommonTypes<'tcx> { }) .collect(); + let anon_canonical_bound_tys = (0..NUM_PREINTERNED_ANON_BOUND_TYS_V) + .map(|v| { + mk(ty::Bound( + ty::BoundVarIndexKind::Canonical, + ty::BoundTy { var: ty::BoundVar::from(v), kind: ty::BoundTyKind::Anon }, + )) + }) + .collect(); + CommonTypes { unit: mk(Tuple(List::empty())), bool: mk(Bool), @@ -1250,6 +1278,7 @@ impl<'tcx> CommonTypes<'tcx> { fresh_int_tys, fresh_float_tys, anon_bound_tys, + anon_canonical_bound_tys, } } } @@ -1270,7 +1299,7 @@ impl<'tcx> CommonLifetimes<'tcx> { (0..NUM_PREINTERNED_ANON_RE_BOUNDS_V) .map(|v| { mk(ty::ReBound( - ty::DebruijnIndex::from(i), + ty::BoundVarIndexKind::Bound(ty::DebruijnIndex::from(i)), ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BoundRegionKind::Anon, @@ -1281,11 +1310,21 @@ impl<'tcx> CommonLifetimes<'tcx> { }) .collect(); + let anon_re_canonical_bounds = (0..NUM_PREINTERNED_ANON_RE_BOUNDS_V) + .map(|v| { + mk(ty::ReBound( + ty::BoundVarIndexKind::Canonical, + ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BoundRegionKind::Anon }, + )) + }) + .collect(); + CommonLifetimes { re_static: mk(ty::ReStatic), re_erased: mk(ty::ReErased), re_vars, anon_re_bounds, + anon_re_canonical_bounds, } } } @@ -2012,7 +2051,7 @@ impl<'tcx> TyCtxt<'tcx> { if stable_crate_id == self.stable_crate_id(LOCAL_CRATE) { Some(self.untracked.definitions.read().local_def_path_hash_to_def_id(hash)?.to_def_id()) } else { - Some(self.def_path_hash_to_def_id_extern(hash, stable_crate_id)) + self.def_path_hash_to_def_id_extern(hash, stable_crate_id) } } @@ -2748,8 +2787,6 @@ direct_interners! { adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, external_constraints: pub mk_external_constraints(ExternalConstraintsData<TyCtxt<'tcx>>): ExternalConstraints -> ExternalConstraints<'tcx>, - predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<TyCtxt<'tcx>>): - PredefinedOpaques -> PredefinedOpaques<'tcx>, } macro_rules! slice_interners { @@ -2786,6 +2823,7 @@ slice_interners!( offset_of: pub mk_offset_of((VariantIdx, FieldIdx)), patterns: pub mk_patterns(Pattern<'tcx>), outlives: pub mk_outlives(ty::ArgOutlivesPredicate<'tcx>), + predefined_opaques_in_body: pub mk_predefined_opaques_in_body((ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)), ); impl<'tcx> TyCtxt<'tcx> { @@ -3129,6 +3167,14 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_poly_existential_predicates(xs)) } + pub fn mk_predefined_opaques_in_body_from_iter<I, T>(self, iter: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>), PredefinedOpaques<'tcx>>, + { + T::collect_and_apply(iter, |xs| self.mk_predefined_opaques_in_body(xs)) + } + pub fn mk_clauses_from_iter<I, T>(self, iter: I) -> T::Output where I: Iterator<Item = T>, diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 7d56ec1635f..ee29afcff63 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -125,7 +125,9 @@ where fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match *t.kind() { - ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => { + ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty) + if debruijn == self.current_index => + { let ty = self.delegate.replace_ty(bound_ty); debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST)); ty::shift_vars(self.tcx, ty, self.current_index.as_u32()) @@ -146,9 +148,11 @@ where fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r.kind() { - ty::ReBound(debruijn, br) if debruijn == self.current_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) + if debruijn == self.current_index => + { let region = self.delegate.replace_region(br); - if let ty::ReBound(debruijn1, br) = region.kind() { + if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn1), br) = region.kind() { // If the callback returns a bound region, // that region should always use the INNERMOST // debruijn index. Then we adjust it to the @@ -165,7 +169,9 @@ where fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { - ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const) + if debruijn == self.current_index => + { let ct = self.delegate.replace_const(bound_const); debug_assert!(!ct.has_vars_bound_above(ty::INNERMOST)); ty::shift_vars(self.tcx, ct, self.current_index.as_u32()) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c477e65f5d6..507a25a4325 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -16,7 +16,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension}; use rustc_session::config::OptLevel; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use rustc_target::callconv::FnAbi; -use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, PanicStrategy, Target, X86Abi}; +use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi}; use tracing::debug; use {rustc_abi as abi, rustc_hir as hir}; @@ -219,6 +219,15 @@ impl fmt::Display for ValidityRequirement { } #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)] +pub enum SimdLayoutError { + /// The vector has 0 lanes. + ZeroLength, + /// The vector has more lanes than supported or permitted by + /// #\[rustc_simd_monomorphize_lane_limit\]. + TooManyLanes(u64), +} + +#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)] pub enum LayoutError<'tcx> { /// A type doesn't have a sensible layout. /// @@ -230,6 +239,8 @@ pub enum LayoutError<'tcx> { Unknown(Ty<'tcx>), /// The size of a type exceeds [`TargetDataLayout::obj_size_bound`]. SizeOverflow(Ty<'tcx>), + /// A SIMD vector has invalid layout, such as zero-length or too many lanes. + InvalidSimd { ty: Ty<'tcx>, kind: SimdLayoutError }, /// The layout can vary due to a generic parameter. /// /// Unlike `Unknown`, this variant is a "soft" error and indicates that the layout @@ -257,6 +268,10 @@ impl<'tcx> LayoutError<'tcx> { match self { Unknown(_) => middle_layout_unknown, SizeOverflow(_) => middle_layout_size_overflow, + InvalidSimd { kind: SimdLayoutError::TooManyLanes(_), .. } => { + middle_layout_simd_too_many + } + InvalidSimd { kind: SimdLayoutError::ZeroLength, .. } => middle_layout_simd_zero_length, TooGeneric(_) => middle_layout_too_generic, NormalizationFailure(_, _) => middle_layout_normalization_failure, Cycle(_) => middle_layout_cycle, @@ -271,6 +286,10 @@ impl<'tcx> LayoutError<'tcx> { match self { Unknown(ty) => E::Unknown { ty }, SizeOverflow(ty) => E::Overflow { ty }, + InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => { + E::SimdTooManyLanes { ty, max_lanes } + } + InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => E::SimdZeroLength { ty }, TooGeneric(ty) => E::TooGeneric { ty }, NormalizationFailure(ty, e) => { E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() } @@ -293,6 +312,12 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { LayoutError::SizeOverflow(ty) => { write!(f, "values of the type `{ty}` are too big for the target architecture") } + LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => { + write!(f, "the SIMD type `{ty}` has more elements than the limit {max_lanes}") + } + LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => { + write!(f, "the SIMD type `{ty}` has zero elements") + } LayoutError::NormalizationFailure(t, e) => write!( f, "unable to determine layout for `{}` because `{}` cannot be normalized", @@ -374,6 +399,7 @@ impl<'tcx> SizeSkeleton<'tcx> { e @ LayoutError::Cycle(_) | e @ LayoutError::Unknown(_) | e @ LayoutError::SizeOverflow(_) + | e @ LayoutError::InvalidSimd { .. } | e @ LayoutError::NormalizationFailure(..) | e @ LayoutError::ReferencesError(_), ) => return Err(e), @@ -1198,7 +1224,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi) // // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"` // function defined in Rust is also required to abort. - if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) { + if !tcx.sess.panic_strategy().unwinds() && !tcx.is_foreign_item(did) { return false; } @@ -1206,7 +1232,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi) // // This is not part of `codegen_fn_attrs` as it can differ between crates // and therefore cannot be computed in core. - if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort + if !tcx.sess.opts.unstable_opts.panic_in_drop.unwinds() && tcx.is_lang_item(did, LangItem::DropInPlace) { return false; @@ -1245,7 +1271,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi) | RiscvInterruptS | RustInvalid | Unadjusted => false, - Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind, + Rust | RustCall | RustCold => tcx.sess.panic_strategy().unwinds(), } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0ffef393a33..ce4de6b95e0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -25,6 +25,7 @@ pub use generic_args::{GenericArgKind, TermKind, *}; pub use generics::*; pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; +use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree}; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; @@ -62,7 +63,7 @@ pub use rustc_type_ir::solve::SizedTraitKind; pub use rustc_type_ir::*; #[allow(hidden_glob_reexports, unused_imports)] use rustc_type_ir::{InferCtxtLike, Interner}; -use tracing::{debug, instrument}; +use tracing::{debug, instrument, trace}; pub use vtable::*; use {rustc_ast as ast, rustc_hir as hir}; @@ -2216,3 +2217,225 @@ pub struct DestructuredConst<'tcx> { pub variant: Option<VariantIdx>, pub fields: &'tcx [ty::Const<'tcx>], } + +/// Generate TypeTree information for autodiff. +/// This function creates TypeTree metadata that describes the memory layout +/// of function parameters and return types for Enzyme autodiff. +pub fn fnc_typetrees<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>) -> FncTree { + // Check if TypeTrees are disabled via NoTT flag + if tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::NoTT) { + return FncTree { args: vec![], ret: TypeTree::new() }; + } + + // Check if this is actually a function type + if !fn_ty.is_fn() { + return FncTree { args: vec![], ret: TypeTree::new() }; + } + + // Get the function signature + let fn_sig = fn_ty.fn_sig(tcx); + let sig = tcx.instantiate_bound_regions_with_erased(fn_sig); + + // Create TypeTrees for each input parameter + let mut args = vec![]; + for ty in sig.inputs().iter() { + let type_tree = typetree_from_ty(tcx, *ty); + args.push(type_tree); + } + + // Create TypeTree for return type + let ret = typetree_from_ty(tcx, sig.output()); + + FncTree { args, ret } +} + +/// Generate TypeTree for a specific type. +/// This function analyzes a Rust type and creates appropriate TypeTree metadata. +pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { + let mut visited = Vec::new(); + typetree_from_ty_inner(tcx, ty, 0, &mut visited) +} + +/// Maximum recursion depth for TypeTree generation to prevent stack overflow +/// from pathological deeply nested types. Combined with cycle detection. +const MAX_TYPETREE_DEPTH: usize = 6; + +/// Internal recursive function for TypeTree generation with cycle detection and depth limiting. +fn typetree_from_ty_inner<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + depth: usize, + visited: &mut Vec<Ty<'tcx>>, +) -> TypeTree { + if depth >= MAX_TYPETREE_DEPTH { + trace!("typetree depth limit {} reached for type: {}", MAX_TYPETREE_DEPTH, ty); + return TypeTree::new(); + } + + if visited.contains(&ty) { + return TypeTree::new(); + } + + visited.push(ty); + let result = typetree_from_ty_impl(tcx, ty, depth, visited); + visited.pop(); + result +} + +/// Implementation of TypeTree generation logic. +fn typetree_from_ty_impl<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + depth: usize, + visited: &mut Vec<Ty<'tcx>>, +) -> TypeTree { + typetree_from_ty_impl_inner(tcx, ty, depth, visited, false) +} + +/// Internal implementation with context about whether this is for a reference target. +fn typetree_from_ty_impl_inner<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + depth: usize, + visited: &mut Vec<Ty<'tcx>>, + is_reference_target: bool, +) -> TypeTree { + if ty.is_scalar() { + let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() { + (Kind::Integer, ty.primitive_size(tcx).bytes_usize()) + } else if ty.is_floating_point() { + match ty { + x if x == tcx.types.f16 => (Kind::Half, 2), + x if x == tcx.types.f32 => (Kind::Float, 4), + x if x == tcx.types.f64 => (Kind::Double, 8), + x if x == tcx.types.f128 => (Kind::F128, 16), + _ => (Kind::Integer, 0), + } + } else { + (Kind::Integer, 0) + }; + + // Use offset 0 for scalars that are direct targets of references (like &f64) + // Use offset -1 for scalars used directly (like function return types) + let offset = if is_reference_target && !ty.is_array() { 0 } else { -1 }; + return TypeTree(vec![Type { offset, size, kind, child: TypeTree::new() }]); + } + + if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() { + let inner_ty = if let Some(inner) = ty.builtin_deref(true) { + inner + } else { + return TypeTree::new(); + }; + + let child = typetree_from_ty_impl_inner(tcx, inner_ty, depth + 1, visited, true); + return TypeTree(vec![Type { + offset: -1, + size: tcx.data_layout.pointer_size().bytes_usize(), + kind: Kind::Pointer, + child, + }]); + } + + if ty.is_array() { + if let ty::Array(element_ty, len_const) = ty.kind() { + let len = len_const.try_to_target_usize(tcx).unwrap_or(0); + if len == 0 { + return TypeTree::new(); + } + let element_tree = + typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); + let mut types = Vec::new(); + for elem_type in &element_tree.0 { + types.push(Type { + offset: -1, + size: elem_type.size, + kind: elem_type.kind, + child: elem_type.child.clone(), + }); + } + + return TypeTree(types); + } + } + + if ty.is_slice() { + if let ty::Slice(element_ty) = ty.kind() { + let element_tree = + typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); + return element_tree; + } + } + + if let ty::Tuple(tuple_types) = ty.kind() { + if tuple_types.is_empty() { + return TypeTree::new(); + } + + let mut types = Vec::new(); + let mut current_offset = 0; + + for tuple_ty in tuple_types.iter() { + let element_tree = + typetree_from_ty_impl_inner(tcx, tuple_ty, depth + 1, visited, false); + + let element_layout = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tuple_ty)) + .ok() + .map(|layout| layout.size.bytes_usize()) + .unwrap_or(0); + + for elem_type in &element_tree.0 { + types.push(Type { + offset: if elem_type.offset == -1 { + current_offset as isize + } else { + current_offset as isize + elem_type.offset + }, + size: elem_type.size, + kind: elem_type.kind, + child: elem_type.child.clone(), + }); + } + + current_offset += element_layout; + } + + return TypeTree(types); + } + + if let ty::Adt(adt_def, args) = ty.kind() { + if adt_def.is_struct() { + let struct_layout = + tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)); + if let Ok(layout) = struct_layout { + let mut types = Vec::new(); + + for (field_idx, field_def) in adt_def.all_fields().enumerate() { + let field_ty = field_def.ty(tcx, args); + let field_tree = + typetree_from_ty_impl_inner(tcx, field_ty, depth + 1, visited, false); + + let field_offset = layout.fields.offset(field_idx).bytes_usize(); + + for elem_type in &field_tree.0 { + types.push(Type { + offset: if elem_type.offset == -1 { + field_offset as isize + } else { + field_offset as isize + elem_type.offset + }, + size: elem_type.size, + kind: elem_type.kind, + child: elem_type.child.clone(), + }); + } + } + + return TypeTree(types); + } + } + } + + TypeTree::new() +} diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1b7ef8de845..4d1fcaeda5e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2664,7 +2664,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { let name = &mut self.name; let region = match r.kind() { - ty::ReBound(db, br) if db >= self.current_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(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 { @@ -2687,7 +2687,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> { } _ => return r, }; - if let ty::ReBound(debruijn1, br) = region.kind() { + if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn1), br) = region.kind() { assert_eq!(debruijn1, ty::INNERMOST); ty::Region::new_bound(self.tcx, self.current_index, br) } else { @@ -3177,8 +3177,7 @@ define_print! { write!(p, "` can be evaluated")?; } ty::ClauseKind::UnstableFeature(symbol) => { - write!(p, "unstable feature: ")?; - write!(p, "`{symbol}`")?; + write!(p, "feature({symbol}) is enabled")?; } } } diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 3a7852dea06..f0687f2bc72 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -31,7 +31,7 @@ impl<'tcx> rustc_type_ir::Flags for Region<'tcx> { fn outer_exclusive_binder(&self) -> ty::DebruijnIndex { match self.kind() { - ty::ReBound(debruijn, _) => debruijn.shifted_in(1), + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) => debruijn.shifted_in(1), _ => ty::INNERMOST, } } @@ -59,7 +59,20 @@ impl<'tcx> Region<'tcx> { { re } else { - tcx.intern_region(ty::ReBound(debruijn, bound_region)) + tcx.intern_region(ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), bound_region)) + } + } + + #[inline] + pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Region<'tcx> { + // Use a pre-interned one when possible. + if let Some(re) = tcx.lifetimes.anon_re_canonical_bounds.get(var.as_usize()).copied() { + re + } else { + tcx.intern_region(ty::ReBound( + ty::BoundVarIndexKind::Canonical, + ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }, + )) } } @@ -122,7 +135,12 @@ impl<'tcx> Region<'tcx> { pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> { match kind { ty::ReEarlyParam(region) => Region::new_early_param(tcx, region), - ty::ReBound(debruijn, region) => Region::new_bound(tcx, debruijn, region), + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), region) => { + Region::new_bound(tcx, debruijn, region) + } + ty::ReBound(ty::BoundVarIndexKind::Canonical, region) => { + Region::new_canonical_bound(tcx, region.var) + } ty::ReLateParam(ty::LateParamRegion { scope, kind }) => { Region::new_late_param(tcx, scope, kind) } @@ -148,6 +166,10 @@ impl<'tcx> rustc_type_ir::inherent::Region<TyCtxt<'tcx>> for Region<'tcx> { Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }) } + fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: rustc_type_ir::BoundVar) -> Self { + Region::new_canonical_bound(tcx, var) + } + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Self { Region::new_placeholder(tcx, placeholder) } @@ -223,7 +245,7 @@ impl<'tcx> Region<'tcx> { #[inline] pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool { match self.kind() { - ty::ReBound(debruijn, _) => debruijn >= index, + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) => debruijn >= index, _ => false, } } @@ -254,7 +276,11 @@ impl<'tcx> Region<'tcx> { ty::ReStatic => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } - ty::ReBound(..) => { + ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => { + flags = flags | TypeFlags::HAS_RE_BOUND; + flags = flags | TypeFlags::HAS_CANONICAL_BOUND; + } + ty::ReBound(ty::BoundVarIndexKind::Bound(..), _) => { flags = flags | TypeFlags::HAS_RE_BOUND; } ty::ReErased => { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 11d109b463d..8dc4dfd677b 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -796,6 +796,7 @@ macro_rules! list_fold { list_fold! { &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> : mk_poly_existential_predicates, + &'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>: mk_predefined_opaques_in_body, &'tcx ty::List<PlaceElem<'tcx>> : mk_place_elems, &'tcx ty::List<ty::Pattern<'tcx>> : mk_patterns, &'tcx ty::List<ty::ArgOutlivesPredicate<'tcx>> : mk_outlives, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index de35e5e847c..a3fdd4e35b6 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -487,7 +487,23 @@ impl<'tcx> Ty<'tcx> { { ty } else { - Ty::new(tcx, Bound(index, bound_ty)) + Ty::new(tcx, Bound(ty::BoundVarIndexKind::Bound(index), bound_ty)) + } + } + + #[inline] + pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: BoundVar) -> Ty<'tcx> { + // Use a pre-interned one when possible. + if let Some(ty) = tcx.types.anon_canonical_bound_tys.get(var.as_usize()).copied() { + ty + } else { + Ty::new( + tcx, + Bound( + ty::BoundVarIndexKind::Canonical, + ty::BoundTy { var, kind: ty::BoundTyKind::Anon }, + ), + ) } } @@ -952,6 +968,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> { Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon }) } + fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Self { + Ty::new_canonical_bound(tcx, var) + } + fn new_alias( interner: TyCtxt<'tcx>, kind: ty::AliasTyKind, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 8dd80aab946..b276b993ec9 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -167,7 +167,7 @@ pub struct TypeckResults<'tcx> { /// We also store the type here, so that the compiler can use it as a hint /// for figuring out hidden types, even if they are only set in dead code /// (which doesn't show up in MIR). - pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>, + pub hidden_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. @@ -250,7 +250,7 @@ impl<'tcx> TypeckResults<'tcx> { coercion_casts: Default::default(), used_trait_imports: Default::default(), tainted_by_errors: None, - concrete_opaque_types: Default::default(), + hidden_types: Default::default(), closure_min_captures: Default::default(), closure_fake_reads: Default::default(), rvalue_scopes: Default::default(), @@ -798,8 +798,8 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { match arg.kind() { GenericArgKind::Type(ty) => match ty.kind() { ty::Bound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in generic parameters. - assert_eq!(*debruijn, ty::INNERMOST); + // We only allow a `ty::BoundVarIndexKind::Canonical` index in generic parameters. + assert_eq!(*debruijn, ty::BoundVarIndexKind::Canonical); cvar == b.var } _ => false, @@ -807,8 +807,8 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { GenericArgKind::Lifetime(r) => match r.kind() { ty::ReBound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in generic parameters. - assert_eq!(debruijn, ty::INNERMOST); + // We only allow a `ty::BoundVarIndexKind::Canonical` index in generic parameters. + assert_eq!(debruijn, ty::BoundVarIndexKind::Canonical); cvar == b.var } _ => false, @@ -816,8 +816,8 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { GenericArgKind::Const(ct) => match ct.kind() { ty::ConstKind::Bound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in generic parameters. - assert_eq!(debruijn, ty::INNERMOST); + // We only allow a `ty::BoundVarIndexKind::Canonical` index in generic parameters. + assert_eq!(debruijn, ty::BoundVarIndexKind::Canonical); cvar == b.var } _ => false, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 4f039381e50..a4422abc688 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1368,7 +1368,6 @@ impl<'tcx> Ty<'tcx> { /// 2229 drop reorder migration analysis. #[inline] pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { - assert!(!self.has_non_region_infer()); // Avoid querying in simple cases. match needs_drop_components(tcx, self) { Err(AlwaysRequiresDrop) => true, @@ -1381,6 +1380,16 @@ impl<'tcx> Ty<'tcx> { _ => self, }; + // FIXME + // We should be canonicalizing, or else moving this to a method of inference + // context, or *something* like that, + // but for now just avoid passing inference variables + // to queries that can't cope with them. + // Instead, conservatively return "true" (may change drop order). + if query_ty.has_infer() { + return true; + } + // This doesn't depend on regions, so try to minimize distinct // query keys used. let erased = tcx.normalize_erasing_regions(typing_env, query_ty); diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index f0c47f257cc..e84ac56b31d 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -78,7 +78,9 @@ impl<'tcx> TyCtxt<'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result { match r.kind() { - ty::ReBound(debruijn, _) if debruijn < self.outer_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) + if debruijn < self.outer_index => + { ControlFlow::Continue(()) } _ => { @@ -205,7 +207,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector { } fn visit_region(&mut self, r: ty::Region<'tcx>) { - if let ty::ReBound(debruijn, br) = r.kind() { + if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) = r.kind() { if debruijn == self.current_index { self.regions.insert(br.kind); } diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index e2f09fdcb4b..a3e9054fdcb 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -104,7 +104,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( .expect("failed to build vtable representation"); assert!(layout.is_sized(), "can't create a vtable for an unsized type"); let size = layout.size.bytes(); - let align = layout.align.abi.bytes(); + let align = layout.align.bytes(); let ptr_size = tcx.data_layout.pointer_size(); let ptr_align = tcx.data_layout.pointer_align().abi; diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 5a6bd2f413c..5e7a57d51a9 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -103,7 +103,7 @@ fn convert_to_hir_projections_and_truncate_for_capture( } ProjectionElem::UnwrapUnsafeBinder(_) => HirProjectionKind::UnwrapUnsafeBinder, // These do not affect anything, they just make sure we know the right type. - ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue, + ProjectionElem::OpaqueCast(_) => continue, ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { @@ -802,7 +802,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ProjectionElem::Field(..) | ProjectionElem::Downcast(..) | ProjectionElem::OpaqueCast(..) - | ProjectionElem::Subtype(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::UnwrapUnsafeBinder(_) => (), diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index a4ef6e92739..3a5839f2d40 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -8,6 +8,7 @@ use rustc_middle::middle::region; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::*; use rustc_middle::thir::*; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::{CastTy, mir_cast_kind}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, Ty, UpvarArgs}; @@ -656,6 +657,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(rvalue) } + /// Recursively inspect a THIR expression and probe through unsizing + /// operations that can be const-folded today. + fn check_constness(&self, mut kind: &'a ExprKind<'tcx>) -> bool { + loop { + debug!(?kind, "check_constness"); + match kind { + &ExprKind::ValueTypeAscription { source: eid, user_ty: _, user_ty_span: _ } + | &ExprKind::Use { source: eid } + | &ExprKind::PointerCoercion { + cast: PointerCoercion::Unsize, + source: eid, + is_from_as_cast: _, + } + | &ExprKind::Scope { region_scope: _, lint_level: _, value: eid } => { + kind = &self.thir[eid].kind + } + _ => return matches!(Category::of(&kind), Some(Category::Constant)), + } + } + } + fn build_zero_repeat( &mut self, mut block: BasicBlock, @@ -666,7 +688,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let this = self; let value_expr = &this.thir[value]; let elem_ty = value_expr.ty; - if let Some(Category::Constant) = Category::of(&value_expr.kind) { + if this.check_constness(&value_expr.kind) { // Repeating a const does nothing } else { // For a non-const, we may need to generate an appropriate `Drop` diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index cdb2c5561ce..7ca94e655fb 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -395,12 +395,10 @@ enum NeedsTemporary { Maybe, } -/////////////////////////////////////////////////////////////////////////// /// The `BlockAnd` "monad" packages up the new basic block along with a /// produced value (sometimes just unit, of course). The `unpack!` /// macro (and methods below) makes working with `BlockAnd` much more /// convenient. - #[must_use = "if you don't use one of these results, you're leaving a dangling edge"] struct BlockAnd<T>(BasicBlock, T); @@ -438,9 +436,7 @@ macro_rules! unpack { }}; } -/////////////////////////////////////////////////////////////////////////// -/// the main entry point for building MIR for a function - +/// The main entry point for building MIR for a function. fn construct_fn<'tcx>( tcx: TyCtxt<'tcx>, fn_def: LocalDefId, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index b5e165c7517..195d45c2c4c 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -554,6 +554,21 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_expr(self, &self.thir[arg]); return; } + + // Secondly, we allow raw borrows of union field accesses. Peel + // any of those off, and recurse normally on the LHS, which should + // reject any unsafe operations within. + let mut peeled = arg; + while let ExprKind::Scope { value: arg, .. } = self.thir[peeled].kind + && let ExprKind::Field { lhs, name: _, variant_index: _ } = self.thir[arg].kind + && let ty::Adt(def, _) = &self.thir[lhs].ty.kind() + && def.is_union() + { + peeled = lhs; + } + visit::walk_expr(self, &self.thir[peeled]); + // And return so we don't recurse directly onto the union field access(es). + return; } ExprKind::Deref { arg } => { if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) = 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 ae67bb5075e..3929a97eed8 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1275,13 +1275,13 @@ fn report_non_exhaustive_match<'p, 'tcx>( if ty.is_ptr_sized_integral() { if ty.inner() == cx.tcx.types.usize { err.note(format!( - "`{ty}` does not have a fixed maximum value, so half-open ranges are \ - necessary to match exhaustively", + "`{ty}::MAX` is not treated as exhaustive, \ + so half-open ranges are necessary to match exhaustively", )); } else if ty.inner() == cx.tcx.types.isize { err.note(format!( - "`{ty}` does not have fixed minimum and maximum values, so half-open \ - ranges are necessary to match exhaustively", + "`{ty}::MIN` and `{ty}::MAX` are not treated as exhaustive, \ + so half-open ranges are necessary to match exhaustively", )); } } else if ty.inner() == cx.tcx.types.str_ { diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 72d4cd72c2b..434f106302f 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -227,11 +227,8 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { ProjectionElem::UnwrapUnsafeBinder(_) => {} // `OpaqueCast`:Only transmutes the type, so no moves there. // `Downcast` :Only changes information about a `Place` without moving. - // `Subtype` :Only transmutes the type, so moves. // So it's safe to skip these. - ProjectionElem::OpaqueCast(_) - | ProjectionElem::Subtype(_) - | ProjectionElem::Downcast(_, _) => (), + ProjectionElem::OpaqueCast(_) | ProjectionElem::Downcast(_, _) => (), } let elem_ty = PlaceTy::from_ty(place_ty).projection_ty(tcx, elem).ty; if !(self.filter)(elem_ty) { diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index 5bd6fdcf485..35a21a2a834 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -3,6 +3,7 @@ use rustc_ast::InlineAsmOptions; use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::ty::{self, TyCtxt, layout}; +use rustc_span::sym; use rustc_target::spec::PanicStrategy; /// A pass that runs which is targeted at ensuring that codegen guarantees about @@ -33,6 +34,19 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls { return; } + // Represent whether this compilation target fundamentally doesn't + // support unwinding at all at an ABI level. If this the target has no + // support for unwinding then cleanup actions, for example, are all + // unnecessary and can be considered unreachable. + // + // Currently this is only true for wasm targets on panic=abort when the + // `exception-handling` target feature is disabled. In such a + // configuration it's illegal to emit exception-related instructions so + // it's not possible to unwind. + let target_supports_unwinding = !(tcx.sess.target.is_like_wasm + && tcx.sess.panic_strategy() == PanicStrategy::Abort + && !tcx.asm_target_features(def_id).contains(&sym::exception_handling)); + // Here we test for this function itself whether its ABI allows // unwinding or not. let body_ty = tcx.type_of(def_id).skip_binder(); @@ -54,12 +68,18 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls { let Some(terminator) = &mut block.terminator else { continue }; let span = terminator.source_info.span; - // If we see an `UnwindResume` terminator inside a function that cannot unwind, we need - // to replace it with `UnwindTerminate`. - if let TerminatorKind::UnwindResume = &terminator.kind - && !body_can_unwind - { - terminator.kind = TerminatorKind::UnwindTerminate(UnwindTerminateReason::Abi); + // If we see an `UnwindResume` terminator inside a function then: + // + // * If the target doesn't support unwinding at all, then this is an + // unreachable block. + // * If the body cannot unwind, we need to replace it with + // `UnwindTerminate`. + if let TerminatorKind::UnwindResume = &terminator.kind { + if !target_supports_unwinding { + terminator.kind = TerminatorKind::Unreachable; + } else if !body_can_unwind { + terminator.kind = TerminatorKind::UnwindTerminate(UnwindTerminateReason::Abi); + } } if block.is_cleanup { @@ -93,8 +113,9 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls { _ => continue, }; - if !call_can_unwind { - // If this function call can't unwind, then there's no need for it + if !call_can_unwind || !target_supports_unwinding { + // If this function call can't unwind, or if the target doesn't + // support unwinding at all, then there's no need for it // to have a landing pad. This means that we can remove any cleanup // registered for it (and turn it into `UnwindAction::Unreachable`). let cleanup = block.terminator_mut().unwind_mut().unwrap(); diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs index be4f84d64d0..a6a60fddf90 100644 --- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs +++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs @@ -40,8 +40,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> { .new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span); let new_place = Place::from(temp); self.patcher.add_assign(location, new_place, rvalue.clone()); - let subtyped = new_place.project_deeper(&[ProjectionElem::Subtype(place_ty)], self.tcx); - *rvalue = Rvalue::Use(Operand::Move(subtyped)); + *rvalue = Rvalue::Cast(CastKind::Subtype, Operand::Move(new_place), place_ty); } } } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index c1cd2788348..c5cd06f170c 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -86,7 +86,6 @@ use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::source_map::dummy_spanned; use rustc_span::symbol::sym; use rustc_span::{DUMMY_SP, Span}; -use rustc_target::spec::PanicStrategy; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::TyCtxtInferExt as _; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; @@ -1149,7 +1148,7 @@ fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, typing_env: ty::Typing fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { // Nothing can unwind when landing pads are off. - if tcx.sess.panic_strategy() == PanicStrategy::Abort { + if !tcx.sess.panic_strategy().unwinds() { return false; } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 5c984984d3c..e970f7ff81a 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -440,7 +440,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { FlatSet::Top => FlatSet::Top, } } - Rvalue::Cast(CastKind::Transmute, operand, _) => { + Rvalue::Cast(CastKind::Transmute | CastKind::Subtype, operand, _) => { match self.eval_operand(operand, state) { FlatSet::Elem(op) => self.wrap_immediate(*op), FlatSet::Bottom => FlatSet::Bottom, @@ -476,7 +476,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { }; let val = match null_op { NullOp::SizeOf if layout.is_sized() => layout.size.bytes(), - NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(), + NullOp::AlignOf if layout.is_sized() => layout.align.bytes(), NullOp::OffsetOf(fields) => self .ecx .tcx diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index abbff1c48dd..7c66783548e 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -101,12 +101,15 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { } fn required_panic_strategy(tcx: TyCtxt<'_>, _: LocalCrate) -> Option<PanicStrategy> { + let local_strategy = tcx.sess.panic_strategy(); + if tcx.is_panic_runtime(LOCAL_CRATE) { - return Some(tcx.sess.panic_strategy()); + return Some(local_strategy); } - if tcx.sess.panic_strategy() == PanicStrategy::Abort { - return Some(PanicStrategy::Abort); + match local_strategy { + PanicStrategy::Abort | PanicStrategy::ImmediateAbort => return Some(local_strategy), + _ => {} } for def_id in tcx.hir_body_owners() { diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index ebec3d12500..99691d9e045 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -618,7 +618,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } let val = match null_op { NullOp::SizeOf => arg_layout.size.bytes(), - NullOp::AlignOf => arg_layout.align.abi.bytes(), + NullOp::AlignOf => arg_layout.align.bytes(), NullOp::OffsetOf(fields) => self .ecx .tcx @@ -656,7 +656,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let res = self.ecx.float_to_float_or_int(&value, ty).discard_err()?; res.into() } - CastKind::Transmute => { + CastKind::Transmute | CastKind::Subtype => { let value = self.evaluated[value].as_ref()?; // `offset` for immediates generally only supports projections that match the // type of the immediate. However, as a HACK, we exploit that it can also do @@ -788,7 +788,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ProjectionElem::Subslice { from, to, from_end } } ProjectionElem::OpaqueCast(_) => ProjectionElem::OpaqueCast(()), - ProjectionElem::Subtype(_) => ProjectionElem::Subtype(()), ProjectionElem::UnwrapUnsafeBinder(_) => ProjectionElem::UnwrapUnsafeBinder(()), }; diff --git a/compiler/rustc_mir_transform/src/impossible_predicates.rs b/compiler/rustc_mir_transform/src/impossible_predicates.rs index b03518de00a..883ee32bdec 100644 --- a/compiler/rustc_mir_transform/src/impossible_predicates.rs +++ b/compiler/rustc_mir_transform/src/impossible_predicates.rs @@ -28,6 +28,7 @@ use rustc_middle::mir::{Body, START_BLOCK, TerminatorKind}; use rustc_middle::ty::{TyCtxt, TypeFlags, TypeVisitableExt}; +use rustc_span::def_id::DefId; use rustc_trait_selection::traits; use tracing::trace; @@ -35,23 +36,29 @@ use crate::pass_manager::MirPass; pub(crate) struct ImpossiblePredicates; +fn has_impossible_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + let predicates = tcx.predicates_of(def_id).instantiate_identity(tcx); + tracing::trace!(?predicates); + let predicates = predicates.predicates.into_iter().filter(|p| { + !p.has_type_flags( + // Only consider global clauses to simplify. + TypeFlags::HAS_FREE_LOCAL_NAMES + // Clauses that refer to unevaluated constants as they cause cycles. + | TypeFlags::HAS_CT_PROJECTION, + ) + }); + let predicates: Vec<_> = traits::elaborate(tcx, predicates).collect(); + tracing::trace!(?predicates); + predicates.references_error() || traits::impossible_predicates(tcx, predicates) +} + impl<'tcx> MirPass<'tcx> for ImpossiblePredicates { #[tracing::instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { tracing::trace!(def_id = ?body.source.def_id()); - let predicates = tcx.predicates_of(body.source.def_id()).instantiate_identity(tcx); - tracing::trace!(?predicates); - let predicates = predicates.predicates.into_iter().filter(|p| { - !p.has_type_flags( - // Only consider global clauses to simplify. - TypeFlags::HAS_FREE_LOCAL_NAMES - // Clauses that refer to unevaluated constants as they cause cycles. - | TypeFlags::HAS_CT_PROJECTION, - ) - }); - let predicates: Vec<_> = traits::elaborate(tcx, predicates).collect(); - tracing::trace!(?predicates); - if predicates.references_error() || traits::impossible_predicates(tcx, predicates) { + let impossible = body.tainted_by_errors.is_some() + || has_impossible_predicates(tcx, body.source.def_id()); + if impossible { trace!("found unsatisfiable predicates"); // Clear the body to only contain a single `unreachable` statement. let bbs = body.basic_blocks.as_mut(); diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index f9e642e28eb..68298767e7f 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -84,7 +84,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { body, arena, map: Map::new(tcx, body, Some(MAX_PLACES)), - loop_headers: loop_headers(body), + maybe_loop_headers: maybe_loop_headers(body), opportunities: Vec::new(), }; @@ -100,7 +100,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { // Verify that we do not thread through a loop header. for to in opportunities.iter() { - assert!(to.chain.iter().all(|&block| !finder.loop_headers.contains(block))); + assert!(to.chain.iter().all(|&block| !finder.maybe_loop_headers.contains(block))); } OpportunitySet::new(body, opportunities).apply(body); } @@ -124,7 +124,7 @@ struct TOFinder<'a, 'tcx> { ecx: InterpCx<'tcx, DummyMachine>, body: &'a Body<'tcx>, map: Map<'tcx>, - loop_headers: DenseBitSet<BasicBlock>, + maybe_loop_headers: DenseBitSet<BasicBlock>, /// We use an arena to avoid cloning the slices when cloning `state`. arena: &'a DroplessArena, opportunities: Vec<ThreadingOpportunity>, @@ -190,7 +190,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { #[instrument(level = "trace", skip(self))] fn start_from_switch(&mut self, bb: BasicBlock) { let bbdata = &self.body[bb]; - if bbdata.is_cleanup || self.loop_headers.contains(bb) { + if bbdata.is_cleanup || self.maybe_loop_headers.contains(bb) { return; } let Some((discr, targets)) = bbdata.terminator().kind.as_switch() else { return }; @@ -235,7 +235,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { depth: usize, ) { // Do not thread through loop headers. - if self.loop_headers.contains(bb) { + if self.maybe_loop_headers.contains(bb) { return; } @@ -833,20 +833,28 @@ enum Update { Decr, } -/// Compute the set of loop headers in the given body. We define a loop header as a block which has -/// at least a predecessor which it dominates. This definition is only correct for reducible CFGs. -/// But if the CFG is already irreducible, there is no point in trying much harder. -/// is already irreducible. -fn loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> { - let mut loop_headers = DenseBitSet::new_empty(body.basic_blocks.len()); - let dominators = body.basic_blocks.dominators(); - // Only visit reachable blocks. - for (bb, bbdata) in traversal::preorder(body) { +/// Compute the set of loop headers in the given body. A loop header is usually defined as a block +/// which dominates one of its predecessors. This definition is only correct for reducible CFGs. +/// However, computing dominators is expensive, so we approximate according to the post-order +/// traversal order. A loop header for us is a block which is visited after its predecessor in +/// post-order. This is ok as we mostly need a heuristic. +fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> { + let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len()); + let mut visited = DenseBitSet::new_empty(body.basic_blocks.len()); + for (bb, bbdata) in traversal::postorder(body) { + // Post-order means we visit successors before the block for acyclic CFGs. + // If the successor is not visited yet, consider it a loop header. for succ in bbdata.terminator().successors() { - if dominators.dominates(succ, bb) { - loop_headers.insert(succ); + if !visited.contains(succ) { + maybe_loop_headers.insert(succ); } } + + // Only mark `bb` as visited after we checked the successors, in case we have a self-loop. + // bb1: goto -> bb1; + let _new = visited.insert(bb); + debug_assert!(_new); } - loop_headers + + maybe_loop_headers } diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index aaacc5866a2..93abc0f8860 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -609,7 +609,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let op_layout = self.ecx.layout_of(ty).ok()?; let val = match null_op { NullOp::SizeOf => op_layout.size.bytes(), - NullOp::AlignOf => op_layout.align.abi.bytes(), + NullOp::AlignOf => op_layout.align.bytes(), NullOp::OffsetOf(fields) => self .tcx .offset_of_subfield(self.typing_env, op_layout, fields.iter()) @@ -637,7 +637,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?; res.into() } - CastKind::Transmute => { + CastKind::Transmute | CastKind::Subtype => { let value = self.eval_operand(value)?; let to = self.ecx.layout_of(to).ok()?; // `offset` for immediates only supports scalar/scalar-pair ABIs, diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index c781d1a5324..cc8ea76011b 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -1,4 +1,5 @@ -use rustc_index::{Idx, IndexVec}; +use rustc_data_structures::fx::FxHashMap; +use rustc_index::Idx; use rustc_middle::mir::*; use rustc_middle::ty::Ty; use rustc_span::Span; @@ -9,7 +10,9 @@ use tracing::debug; /// and replacement of terminators, and then apply the queued changes all at /// once with `apply`. This is useful for MIR transformation passes. pub(crate) struct MirPatch<'tcx> { - term_patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>, + term_patch_map: FxHashMap<BasicBlock, TerminatorKind<'tcx>>, + /// Set of statements that should be replaced by `Nop`. + nop_statements: Vec<Location>, new_blocks: Vec<BasicBlockData<'tcx>>, new_statements: Vec<(Location, StatementKind<'tcx>)>, new_locals: Vec<LocalDecl<'tcx>>, @@ -22,17 +25,22 @@ pub(crate) struct MirPatch<'tcx> { terminate_block: Option<(BasicBlock, UnwindTerminateReason)>, body_span: Span, next_local: usize, + /// The number of blocks at the start of the transformation. New blocks + /// get appended at the end. + next_block: usize, } impl<'tcx> MirPatch<'tcx> { /// Creates a new, empty patch. pub(crate) fn new(body: &Body<'tcx>) -> Self { let mut result = MirPatch { - term_patch_map: IndexVec::from_elem(None, &body.basic_blocks), + term_patch_map: Default::default(), + nop_statements: vec![], new_blocks: vec![], new_statements: vec![], new_locals: vec![], next_local: body.local_decls.len(), + next_block: body.basic_blocks.len(), resume_block: None, unreachable_cleanup_block: None, unreachable_no_cleanup_block: None, @@ -141,7 +149,7 @@ impl<'tcx> MirPatch<'tcx> { /// Has a replacement of this block's terminator been queued in this patch? pub(crate) fn is_term_patched(&self, bb: BasicBlock) -> bool { - self.term_patch_map[bb].is_some() + self.term_patch_map.contains_key(&bb) } /// Universal getter for block data, either it is in 'old' blocks or in patched ones @@ -194,18 +202,26 @@ impl<'tcx> MirPatch<'tcx> { /// Queues the addition of a new basic block. pub(crate) fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { - let block = self.term_patch_map.next_index(); + let block = BasicBlock::from_usize(self.next_block + self.new_blocks.len()); debug!("MirPatch: new_block: {:?}: {:?}", block, data); self.new_blocks.push(data); - self.term_patch_map.push(None); block } /// Queues the replacement of a block's terminator. pub(crate) fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) { - assert!(self.term_patch_map[block].is_none()); + assert!(!self.term_patch_map.contains_key(&block)); debug!("MirPatch: patch_terminator({:?}, {:?})", block, new); - self.term_patch_map[block] = Some(new); + self.term_patch_map.insert(block, new); + } + + /// Mark given statement to be replaced by a `Nop`. + /// + /// This method only works on statements from the initial body, and cannot be used to remove + /// statements from `add_statement` or `add_assign`. + #[tracing::instrument(level = "debug", skip(self))] + pub(crate) fn nop_statement(&mut self, loc: Location) { + self.nop_statements.push(loc); } /// Queues the insertion of a statement at a given location. The statement @@ -244,6 +260,7 @@ impl<'tcx> MirPatch<'tcx> { self.new_blocks.len(), body.basic_blocks.len() ); + debug_assert_eq!(self.next_block, body.basic_blocks.len()); let bbs = if self.term_patch_map.is_empty() && self.new_blocks.is_empty() { body.basic_blocks.as_mut_preserves_cfg() } else { @@ -251,11 +268,9 @@ impl<'tcx> MirPatch<'tcx> { }; bbs.extend(self.new_blocks); body.local_decls.extend(self.new_locals); - for (src, patch) in self.term_patch_map.into_iter_enumerated() { - if let Some(patch) = patch { - debug!("MirPatch: patching block {:?}", src); - bbs[src].terminator_mut().kind = patch; - } + + for loc in self.nop_statements { + bbs[loc.block].statements[loc.statement_index].make_nop(); } let mut new_statements = self.new_statements; @@ -273,12 +288,23 @@ impl<'tcx> MirPatch<'tcx> { } debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta); loc.statement_index += delta; - let source_info = Self::source_info_for_index(&body[loc.block], loc); - body[loc.block] + let source_info = Self::source_info_for_index(&bbs[loc.block], loc); + bbs[loc.block] .statements .insert(loc.statement_index, Statement::new(source_info, stmt)); delta += 1; } + + // The order in which we patch terminators does not change the result. + #[allow(rustc::potential_query_instability)] + for (src, patch) in self.term_patch_map { + debug!("MirPatch: patching block {:?}", src); + let bb = &mut bbs[src]; + if let TerminatorKind::Unreachable = patch { + bb.statements.clear(); + } + bb.terminator_mut().kind = patch; + } } fn source_info_for_index(data: &BasicBlockData<'_>, loc: Location) -> SourceInfo { diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index a0b0c8c990f..48ddf5a1bca 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -292,7 +292,6 @@ impl<'tcx> Validator<'_, 'tcx> { match elem { // Recurse directly. ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subtype(_) | ProjectionElem::Subslice { .. } | ProjectionElem::UnwrapUnsafeBinder(_) => {} 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 5b6d7ffb511..b53c1f6d202 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -1,7 +1,6 @@ use rustc_index::bit_set::DenseBitSet; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -use rustc_target::spec::PanicStrategy; use tracing::debug; use crate::patch::MirPatch; @@ -13,7 +12,7 @@ pub(super) struct RemoveNoopLandingPads; impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.panic_strategy() != PanicStrategy::Abort + sess.panic_strategy().unwinds() } fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index 886f4d6e509..ed94a058ec6 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -2,6 +2,8 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use tracing::trace; +use crate::patch::MirPatch; + pub(super) enum SimplifyConstCondition { AfterConstProp, Final, @@ -19,8 +21,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running SimplifyConstCondition on {:?}", body.source); let typing_env = body.typing_env(tcx); - 'blocks: for block in body.basic_blocks_mut() { - for stmt in block.statements.iter_mut() { + let mut patch = MirPatch::new(body); + + 'blocks: for (bb, block) in body.basic_blocks.iter_enumerated() { + for (statement_index, stmt) in block.statements.iter().enumerate() { // Simplify `assume` of a known value: either a NOP or unreachable. if let StatementKind::Intrinsic(box ref intrinsic) = stmt.kind && let NonDivergingIntrinsic::Assume(discr) = intrinsic @@ -28,17 +32,16 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { && let Some(constant) = c.const_.try_eval_bool(tcx, typing_env) { if constant { - stmt.make_nop(); + patch.nop_statement(Location { block: bb, statement_index }); } else { - block.statements.clear(); - block.terminator_mut().kind = TerminatorKind::Unreachable; + patch.patch_terminator(bb, TerminatorKind::Unreachable); continue 'blocks; } } } - let terminator = block.terminator_mut(); - terminator.kind = match terminator.kind { + let terminator = block.terminator(); + let terminator = match terminator.kind { TerminatorKind::SwitchInt { discr: Operand::Constant(ref c), ref targets, .. } => { @@ -58,7 +61,9 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { }, _ => continue, }; + patch.patch_terminator(bb, terminator); } + patch.apply(body); } fn is_required(&self) -> bool { diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index c8a9a88dc3f..cbabb982df8 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -814,22 +814,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } } - ProjectionElem::Subtype(ty) => { - if !util::sub_types( - self.tcx, - self.typing_env, - ty, - place_ref.ty(&self.body.local_decls, self.tcx).ty, - ) { - self.fail( - location, - format!( - "Failed subtyping {ty} and {}", - place_ref.ty(&self.body.local_decls, self.tcx).ty - ), - ) - } - } ProjectionElem::UnwrapUnsafeBinder(unwrapped_ty) => { let binder_ty = place_ref.ty(&self.body.local_decls, self.tcx); let ty::UnsafeBinder(binder_ty) = *binder_ty.ty.kind() else { @@ -1331,6 +1315,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } + CastKind::Subtype => { + if !util::sub_types(self.tcx, self.typing_env, op_ty, *target_type) { + self.fail( + location, + format!("Failed subtyping {op_ty} and {target_type}"), + ) + } + } } } Rvalue::NullaryOp(NullOp::OffsetOf(indices), container) => { diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index b25671d676b..9162284422d 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -74,12 +74,10 @@ pub(super) struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner /// we set the `sub_root` of the second variable to the position of the first. /// Otherwise the `sub_root` of each type variable is just its own position. sub_root_lookup_table: HashMap<ty::TyVid, usize>, - binder_index: ty::DebruijnIndex, - /// We only use the debruijn index during lookup. We don't need to - /// track the `variables` as each generic arg only results in a single - /// bound variable regardless of how many times it is encountered. - cache: HashMap<(ty::DebruijnIndex, I::Ty), I::Ty>, + /// We can simply cache based on the ty itself, because we use + /// `ty::BoundVarIndexKind::Canonical`. + cache: HashMap<I::Ty, I::Ty>, } impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { @@ -97,7 +95,6 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), - binder_index: ty::INNERMOST, cache: Default::default(), }; @@ -141,12 +138,10 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), - binder_index: ty::INNERMOST, cache: Default::default(), }; let param_env = param_env.fold_with(&mut env_canonicalizer); - debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST); debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty()); CanonicalParamEnvCacheEntry { param_env, @@ -175,12 +170,10 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), - binder_index: ty::INNERMOST, cache: Default::default(), }; let param_env = param_env.fold_with(&mut env_canonicalizer); - debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST); debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty()); (param_env, env_canonicalizer.variable_lookup_table, env_canonicalizer.var_kinds) } @@ -212,7 +205,6 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { variable_lookup_table, sub_root_lookup_table: Default::default(), var_kinds, - binder_index: ty::INNERMOST, // We do not reuse the cache as it may contain entries whose canonicalized // value contains `'static`. While we could alternatively handle this by @@ -409,7 +401,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { let var = self.get_or_insert_bound_var(t, kind); - Ty::new_anon_bound(self.cx(), self.binder_index, var) + Ty::new_canonical_bound(self.cx(), var) } } @@ -418,16 +410,6 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz self.delegate.cx() } - fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> - where - T: TypeFoldable<I>, - { - self.binder_index.shift_in(1); - let t = t.super_fold_with(self); - self.binder_index.shift_out(1); - t - } - fn fold_region(&mut self, r: I::Region) -> I::Region { let kind = match r.kind() { ty::ReBound(..) => return r, @@ -491,15 +473,15 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz let var = self.get_or_insert_bound_var(r, kind); - Region::new_anon_bound(self.cx(), self.binder_index, var) + Region::new_canonical_bound(self.cx(), var) } fn fold_ty(&mut self, t: I::Ty) -> I::Ty { - if let Some(&ty) = self.cache.get(&(self.binder_index, t)) { + if let Some(&ty) = self.cache.get(&t) { ty } else { let res = self.inner_fold_ty(t); - let old = self.cache.insert((self.binder_index, t), res); + let old = self.cache.insert(t, res); assert_eq!(old, None); res } @@ -552,7 +534,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz let var = self.get_or_insert_bound_var(c, kind); - Const::new_anon_bound(self.cx(), self.binder_index, var) + Const::new_canonical_bound(self.cx(), var) } fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index e3520e238ed..b4cea8701d8 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -25,7 +25,7 @@ use crate::delegate::SolverDelegate; use crate::resolve::eager_resolve_vars; use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, ExternalConstraintsData, Goal, - NestedNormalizationGoals, PredefinedOpaquesData, QueryInput, Response, inspect, + NestedNormalizationGoals, QueryInput, Response, inspect, }; pub mod canonicalizer; @@ -53,7 +53,7 @@ impl<I: Interner, T> ResponseT<I> for inspect::State<I, T> { pub(super) fn canonicalize_goal<D, I>( delegate: &D, goal: Goal<I, I::Predicate>, - opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>, + opaque_types: &[(ty::OpaqueTypeKey<I>, I::Ty)], ) -> (Vec<I::GenericArg>, CanonicalInput<I, I::Predicate>) where D: SolverDelegate<Interner = I>, @@ -65,9 +65,7 @@ where &mut orig_values, QueryInput { goal, - predefined_opaques_in_body: delegate - .cx() - .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), + predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types), }, ); let query_input = ty::CanonicalQueryInput { canonical, typing_mode: delegate.typing_mode() }; @@ -167,25 +165,25 @@ where // and only use it for placeholders. We need to handle the // `sub_root` of type inference variables which would make this // more involved. They are also a lot rarer than region variables. - if let ty::Bound(debruijn, b) = t.kind() + if let ty::Bound(index_kind, b) = t.kind() && !matches!( response.variables.get(b.var().as_usize()).unwrap(), CanonicalVarKind::Ty { .. } ) { - assert_eq!(debruijn, ty::INNERMOST); + assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical)); opt_values[b.var()] = Some(*original_value); } } ty::GenericArgKind::Lifetime(r) => { - if let ty::ReBound(debruijn, br) = r.kind() { - assert_eq!(debruijn, ty::INNERMOST); + if let ty::ReBound(index_kind, br) = r.kind() { + assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical)); opt_values[br.var()] = Some(*original_value); } } ty::GenericArgKind::Const(c) => { - if let ty::ConstKind::Bound(debruijn, bv) = c.kind() { - assert_eq!(debruijn, ty::INNERMOST); + if let ty::ConstKind::Bound(index_kind, bv) = c.kind() { + assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical)); opt_values[bv.var()] = Some(*original_value); } } diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs index c88fb8defae..c8016759f23 100644 --- a/compiler/rustc_next_trait_solver/src/placeholder.rs +++ b/compiler/rustc_next_trait_solver/src/placeholder.rs @@ -90,7 +90,7 @@ where fn fold_region(&mut self, r: I::Region) -> I::Region { match r.kind() { - ty::ReBound(debruijn, _) + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) if debruijn.as_usize() >= self.current_index.as_usize() + self.universe_indices.len() => { @@ -99,7 +99,9 @@ where self.universe_indices ); } - ty::ReBound(debruijn, br) if debruijn >= self.current_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) + if debruijn >= self.current_index => + { let universe = self.universe_for(debruijn); let p = PlaceholderLike::new(universe, br); self.mapped_regions.insert(p, br); @@ -111,7 +113,7 @@ where fn fold_ty(&mut self, t: I::Ty) -> I::Ty { match t.kind() { - ty::Bound(debruijn, _) + ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _) if debruijn.as_usize() + 1 > self.current_index.as_usize() + self.universe_indices.len() => { @@ -120,7 +122,9 @@ where self.universe_indices ); } - ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { + ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty) + if debruijn >= self.current_index => + { let universe = self.universe_for(debruijn); let p = PlaceholderLike::new(universe, bound_ty); self.mapped_types.insert(p, bound_ty); @@ -133,7 +137,7 @@ where fn fold_const(&mut self, ct: I::Const) -> I::Const { match ct.kind() { - ty::ConstKind::Bound(debruijn, _) + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), _) if debruijn.as_usize() + 1 > self.current_index.as_usize() + self.universe_indices.len() => { @@ -142,7 +146,9 @@ where self.universe_indices ); } - ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => { + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const) + if debruijn >= self.current_index => + { let universe = self.universe_for(debruijn); let p = PlaceholderLike::new(universe, bound_const); self.mapped_consts.insert(p, bound_const); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index a2e6ef6f0fe..d58c264841c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -473,7 +473,10 @@ where // fails to reach a fixpoint but ends up getting an error after // running for some additional step. // - // cc trait-system-refactor-initiative#105 + // FIXME(@lcnr): While I believe an error here to be possible, we + // currently don't have any test which actually triggers it. @lqd + // created a minimization for an ICE in typenum, but that one no + // longer fails here. cc trait-system-refactor-initiative#105. let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc); let certainty = Certainty::Maybe { cause, opaque_types_jank: OpaqueTypesJank::AllGood }; self.probe_trait_candidate(source) diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index c40739d12e6..9b3dc1f691f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -664,7 +664,7 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>( pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>( cx: I, self_ty: I::Ty, -) -> Result<(ty::Binder<I, (I::FnInputTys, I::Ty)>, I::FunctionId, I::GenericArgs), NoSolution> { +) -> Result<(ty::Binder<I, (I::Ty, I::Ty)>, I::FunctionId, I::GenericArgs), NoSolution> { match self_ty.kind() { ty::FnDef(def_id, args) => { let sig = cx.fn_sig(def_id); @@ -673,7 +673,8 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>( && cx.fn_is_const(def_id) { Ok(( - sig.instantiate(cx, args).map_bound(|sig| (sig.inputs(), sig.output())), + sig.instantiate(cx, args) + .map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())), def_id, args, )) diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index cb72c1cd92b..65a5edf6b72 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -234,12 +234,12 @@ where let self_ty = goal.predicate.self_ty(); let (inputs_and_output, def_id, args) = structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?; + let (inputs, output) = ecx.instantiate_binder_with_infer(inputs_and_output); // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - let output_is_sized_pred = inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]) - }); + let output_is_sized_pred = + ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]); let requirements = cx .const_conditions(def_id.into()) .iter_instantiated(cx, args) @@ -251,15 +251,12 @@ where }) .chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]); - let pred = inputs_and_output - .map_bound(|(inputs, _)| { - ty::TraitRef::new( - cx, - goal.predicate.def_id(), - [goal.predicate.self_ty(), Ty::new_tup(cx, inputs.as_slice())], - ) - }) - .to_host_effect_clause(cx, goal.predicate.constness); + let pred = ty::Binder::dummy(ty::TraitRef::new( + cx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), inputs], + )) + .to_host_effect_clause(cx, goal.predicate.constness); Self::probe_and_consider_implied_clause( ecx, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index bb86357a85f..f25003bbfe9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -194,7 +194,7 @@ where D: SolverDelegate<Interner = I>, I: Interner, { - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn evaluate_root_goal( &self, goal: Goal<I, I::Predicate>, @@ -206,6 +206,7 @@ where }) } + #[instrument(level = "debug", skip(self), ret)] fn root_goal_may_hold_opaque_types_jank( &self, goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>, @@ -357,7 +358,7 @@ where f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R, ) -> R { let (ref delegate, input, var_values) = D::build_with_canonical(cx, &canonical_input); - for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { + for (key, ty) in input.predefined_opaques_in_body.iter() { let prev = delegate.register_hidden_type_in_storage(key, ty, I::Span::dummy()); // It may be possible that two entries in the opaque type storage end up // with the same key after resolving contained inference variables. @@ -467,7 +468,7 @@ where let opaque_types = self.delegate.clone_opaque_types_lookup_table(); let (goal, opaque_types) = eager_resolve_vars(self.delegate, (goal, opaque_types)); - let (orig_values, canonical_goal) = canonicalize_goal(self.delegate, goal, opaque_types); + let (orig_values, canonical_goal) = canonicalize_goal(self.delegate, goal, &opaque_types); let canonical_result = self.search_graph.evaluate_goal( self.cx(), canonical_goal, @@ -548,7 +549,6 @@ where .canonical .value .predefined_opaques_in_body - .opaque_types .len(), stalled_vars, sub_roots, @@ -633,28 +633,19 @@ where // the certainty of all the goals. #[instrument(level = "trace", skip(self))] pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolution> { - let mut response = Ok(Certainty::overflow(false)); for _ in 0..FIXPOINT_STEP_LIMIT { - // FIXME: This match is a bit ugly, it might be nice to change the inspect - // stuff to use a closure instead. which should hopefully simplify this a bit. match self.evaluate_added_goals_step() { - Ok(Some(cert)) => { - response = Ok(cert); - break; - } Ok(None) => {} + Ok(Some(cert)) => return Ok(cert), Err(NoSolution) => { - response = Err(NoSolution); - break; + self.tainted = Err(NoSolution); + return Err(NoSolution); } } } - if response.is_err() { - self.tainted = Err(NoSolution); - } - - response + debug!("try_evaluate_added_goals: encountered overflow"); + Ok(Certainty::overflow(false)) } /// Iterate over all added goals: returning `Ok(Some(_))` in case we can stop rerunning. @@ -1557,7 +1548,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree<D: SolverDelegate<Interner = I>, let opaque_types = delegate.clone_opaque_types_lookup_table(); let (goal, opaque_types) = eager_resolve_vars(delegate, (goal, opaque_types)); - let (orig_values, canonical_goal) = canonicalize_goal(delegate, goal, opaque_types); + let (orig_values, canonical_goal) = canonicalize_goal(delegate, goal, &opaque_types); let (canonical_result, final_revision) = delegate.cx().evaluate_root_goal_for_proof_tree_raw(canonical_goal); diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index afb86aaf8ab..a58caeecc33 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -381,6 +381,7 @@ where } /// The result of evaluating a goal. +#[derive_where(Debug; I: Interner)] pub struct GoalEvaluation<I: Interner> { /// The goal we've evaluated. This is the input goal, but potentially with its /// inference variables resolved. This never applies any inference constraints diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 653c59c5d42..0674b3d42ab 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -451,23 +451,22 @@ where return ecx.forced_ambiguity(MaybeCause::Ambiguity); } }; + let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output); // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]) - }); + let output_is_sized_pred = + ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]); - let pred = tupled_inputs_and_output - .map_bound(|(inputs, output)| ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new( - cx, - goal.predicate.def_id(), - [goal.predicate.self_ty(), inputs], - ), - term: output.into(), - }) - .upcast(cx); + let pred = ty::ProjectionPredicate { + projection_term: ty::AliasTerm::new( + cx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), inputs], + ), + term: output.into(), + } + .upcast(cx); Self::probe_and_consider_implied_clause( ecx, @@ -497,76 +496,56 @@ where goal_kind, env_region, )?; + let AsyncCallableRelevantTypes { + tupled_inputs_ty, + output_coroutine_ty, + coroutine_return_ty, + } = ecx.instantiate_binder_with_infer(tupled_inputs_and_output_and_coroutine); // A built-in `AsyncFn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( - |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| { - ty::TraitRef::new( - cx, - cx.require_trait_lang_item(SolverTraitLangItem::Sized), - [output_ty], - ) - }, + let output_is_sized_pred = ty::TraitRef::new( + cx, + cx.require_trait_lang_item(SolverTraitLangItem::Sized), + [output_coroutine_ty], ); - let pred = tupled_inputs_and_output_and_coroutine - .map_bound( - |AsyncCallableRelevantTypes { - tupled_inputs_ty, - output_coroutine_ty, - coroutine_return_ty, - }| { - let (projection_term, term) = if cx - .is_lang_item(goal.predicate.def_id(), SolverLangItem::CallOnceFuture) - { - ( - ty::AliasTerm::new( - cx, - goal.predicate.def_id(), - [goal.predicate.self_ty(), tupled_inputs_ty], - ), - output_coroutine_ty.into(), - ) - } else if cx - .is_lang_item(goal.predicate.def_id(), SolverLangItem::CallRefFuture) - { - ( - ty::AliasTerm::new( - cx, - goal.predicate.def_id(), - [ - I::GenericArg::from(goal.predicate.self_ty()), - tupled_inputs_ty.into(), - env_region.into(), - ], - ), - output_coroutine_ty.into(), - ) - } else if cx - .is_lang_item(goal.predicate.def_id(), SolverLangItem::AsyncFnOnceOutput) - { - ( - ty::AliasTerm::new( - cx, - goal.predicate.def_id(), - [ - I::GenericArg::from(goal.predicate.self_ty()), - tupled_inputs_ty.into(), - ], - ), - coroutine_return_ty.into(), - ) - } else { - panic!( - "no such associated type in `AsyncFn*`: {:?}", - goal.predicate.def_id() - ) - }; - ty::ProjectionPredicate { projection_term, term } - }, - ) - .upcast(cx); + let (projection_term, term) = + if cx.is_lang_item(goal.predicate.def_id(), SolverLangItem::CallOnceFuture) { + ( + ty::AliasTerm::new( + cx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), tupled_inputs_ty], + ), + output_coroutine_ty.into(), + ) + } else if cx.is_lang_item(goal.predicate.def_id(), SolverLangItem::CallRefFuture) { + ( + ty::AliasTerm::new( + cx, + goal.predicate.def_id(), + [ + I::GenericArg::from(goal.predicate.self_ty()), + tupled_inputs_ty.into(), + env_region.into(), + ], + ), + output_coroutine_ty.into(), + ) + } else if cx.is_lang_item(goal.predicate.def_id(), SolverLangItem::AsyncFnOnceOutput) { + ( + ty::AliasTerm::new( + cx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), tupled_inputs_ty], + ), + coroutine_return_ty.into(), + ) + } else { + panic!("no such associated type in `AsyncFn*`: {:?}", goal.predicate.def_id()) + }; + let pred = ty::ProjectionPredicate { projection_term, term }.upcast(cx); Self::probe_and_consider_implied_clause( ecx, diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index aa9dfc9a9a2..109c8476ccb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -74,20 +74,28 @@ where } } - fn is_initial_provisional_result( - cx: Self::Cx, - kind: PathKind, - input: CanonicalInput<I>, - result: QueryResult<I>, - ) -> bool { - Self::initial_provisional_result(cx, kind, input) == result + fn is_initial_provisional_result(result: QueryResult<I>) -> Option<PathKind> { + match result { + Ok(response) => { + if has_no_inference_or_external_constraints(response) { + if response.value.certainty == Certainty::Yes { + return Some(PathKind::Coinductive); + } else if response.value.certainty == Certainty::overflow(false) { + return Some(PathKind::Unknown); + } + } + + None + } + Err(NoSolution) => Some(PathKind::Inductive), + } } - fn on_stack_overflow(cx: I, input: CanonicalInput<I>) -> QueryResult<I> { + fn stack_overflow_result(cx: I, input: CanonicalInput<I>) -> QueryResult<I> { response_no_constraints(cx, input, Certainty::overflow(true)) } - fn on_fixpoint_overflow(cx: I, input: CanonicalInput<I>) -> QueryResult<I> { + fn fixpoint_overflow_result(cx: I, input: CanonicalInput<I>) -> QueryResult<I> { response_no_constraints(cx, input, Certainty::overflow(false)) } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 3974114e9b4..e790ecd595b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -369,18 +369,16 @@ where return ecx.forced_ambiguity(MaybeCause::Ambiguity); } }; + let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output); // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]) - }); + let output_is_sized_pred = + ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]); - let pred = tupled_inputs_and_output - .map_bound(|(inputs, _)| { - ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) - }) - .upcast(cx); + let pred = + ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) + .upcast(cx); Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), @@ -408,28 +406,26 @@ where // This region doesn't matter because we're throwing away the coroutine type Region::new_static(cx), )?; + let AsyncCallableRelevantTypes { + tupled_inputs_ty, + output_coroutine_ty, + coroutine_return_ty: _, + } = ecx.instantiate_binder_with_infer(tupled_inputs_and_output_and_coroutine); // A built-in `AsyncFn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) - let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( - |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| { - ty::TraitRef::new( - cx, - cx.require_trait_lang_item(SolverTraitLangItem::Sized), - [output_coroutine_ty], - ) - }, + let output_is_sized_pred = ty::TraitRef::new( + cx, + cx.require_trait_lang_item(SolverTraitLangItem::Sized), + [output_coroutine_ty], ); - let pred = tupled_inputs_and_output_and_coroutine - .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| { - ty::TraitRef::new( - cx, - goal.predicate.def_id(), - [goal.predicate.self_ty(), tupled_inputs_ty], - ) - }) - .upcast(cx); + let pred = ty::TraitRef::new( + cx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), tupled_inputs_ty], + ) + .upcast(cx); Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 88b67d792de..c26c7b9122a 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -9,6 +9,7 @@ #![feature(default_field_values)] #![feature(if_let_guard)] #![feature(iter_intersperse)] +#![feature(iter_order_by)] #![recursion_limit = "256"] // tidy-alphabetical-end diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a28af7833c3..a9fbd0fa33d 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2748,28 +2748,7 @@ impl<'a> Parser<'a> { if token::Colon != self.token.kind { return first_pat; } - if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) - || !self.look_ahead(1, |token| token.is_non_reserved_ident()) - { - let mut snapshot_type = self.create_snapshot_for_diagnostic(); - snapshot_type.bump(); // `:` - match snapshot_type.parse_ty() { - Err(inner_err) => { - inner_err.cancel(); - } - Ok(ty) => { - let Err(mut err) = self.expected_one_of_not_found(&[], &[]) else { - return first_pat; - }; - err.span_label(ty.span, "specifying the type of a pattern isn't supported"); - self.restore_snapshot(snapshot_type); - let span = first_pat.span.to(ty.span); - first_pat = self.mk_pat(span, PatKind::Wild); - err.emit(); - } - } - return first_pat; - } + // The pattern looks like it might be a path with a `::` -> `:` typo: // `match foo { bar:baz => {} }` let colon_span = self.token.span; @@ -2857,7 +2836,13 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } else { - first_pat = self.mk_pat(new_span, PatKind::Wild); + first_pat = self.mk_pat( + new_span, + PatKind::Err( + self.dcx() + .span_delayed_bug(colon_span, "recovered bad path pattern"), + ), + ); } self.restore_snapshot(snapshot_pat); } @@ -2870,7 +2855,14 @@ impl<'a> Parser<'a> { err.span_label(ty.span, "specifying the type of a pattern isn't supported"); self.restore_snapshot(snapshot_type); let new_span = first_pat.span.to(ty.span); - first_pat = self.mk_pat(new_span, PatKind::Wild); + first_pat = + self.mk_pat( + new_span, + PatKind::Err(self.dcx().span_delayed_bug( + colon_span, + "recovered bad pattern with type", + )), + ); } } err.emit(); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 81a5d48d94e..8046abcd70b 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3612,7 +3612,7 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw::Async) && self.is_gen_block(kw::Gen, 1) } - fn is_certainly_not_a_block(&self) -> bool { + fn is_likely_struct_lit(&self) -> bool { // `{ ident, ` and `{ ident: ` cannot start a block. self.look_ahead(1, |t| t.is_ident()) && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon) @@ -3624,24 +3624,50 @@ impl<'a> Parser<'a> { path: &ast::Path, ) -> Option<PResult<'a, Box<Expr>>> { let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); - if struct_allowed || self.is_certainly_not_a_block() { - if let Err(err) = self.expect(exp!(OpenBrace)) { - return Some(Err(err)); + match (struct_allowed, self.is_likely_struct_lit()) { + // A struct literal isn't expected and one is pretty much assured not to be present. The + // only situation that isn't detected is when a struct with a single field was attempted + // in a place where a struct literal wasn't expected, but regular parser errors apply. + // Happy path. + (false, false) => None, + (true, _) => { + // A struct is accepted here, try to parse it and rely on `parse_expr_struct` for + // any kind of recovery. Happy path. + if let Err(err) = self.expect(exp!(OpenBrace)) { + return Some(Err(err)); + } + Some(self.parse_expr_struct(qself.clone(), path.clone(), true)) } - let expr = self.parse_expr_struct(qself.clone(), path.clone(), true); - if let (Ok(expr), false) = (&expr, struct_allowed) { - // This is a struct literal, but we don't can't accept them here. - self.dcx().emit_err(errors::StructLiteralNotAllowedHere { - span: expr.span, - sub: errors::StructLiteralNotAllowedHereSugg { - left: path.span.shrink_to_lo(), - right: expr.span.shrink_to_hi(), - }, - }); + (false, true) => { + // We have something like `match foo { bar,` or `match foo { bar:`, which means the + // user might have meant to write a struct literal as part of the `match` + // discriminant. This is done purely for error recovery. + let snapshot = self.create_snapshot_for_diagnostic(); + if let Err(err) = self.expect(exp!(OpenBrace)) { + return Some(Err(err)); + } + match self.parse_expr_struct(qself.clone(), path.clone(), false) { + Ok(expr) => { + // This is a struct literal, but we don't accept them here. + self.dcx().emit_err(errors::StructLiteralNotAllowedHere { + span: expr.span, + sub: errors::StructLiteralNotAllowedHereSugg { + left: path.span.shrink_to_lo(), + right: expr.span.shrink_to_hi(), + }, + }); + Some(Ok(expr)) + } + Err(err) => { + // We couldn't parse a valid struct, rollback and let the parser emit an + // error elsewhere. + err.cancel(); + self.restore_snapshot(snapshot); + None + } + } } - return Some(expr); } - None } pub(super) fn parse_struct_fields( diff --git a/compiler/rustc_parse/src/parser/tokenstream/tests.rs b/compiler/rustc_parse/src/parser/tokenstream/tests.rs index 19b2c98f5af..63177a72744 100644 --- a/compiler/rustc_parse/src/parser/tokenstream/tests.rs +++ b/compiler/rustc_parse/src/parser/tokenstream/tests.rs @@ -15,7 +15,7 @@ fn sp(a: u32, b: u32) -> Span { } fn cmp_token_stream(a: &TokenStream, b: &TokenStream) -> bool { - a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.eq_unspanned(y)) + a.iter().eq_by(b.iter(), |x, y| x.eq_unspanned(y)) } #[test] diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 75537caa894..df4016dfa1b 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -93,15 +93,6 @@ passes_dead_codes = } } never {$participle} -passes_debug_visualizer_invalid = - invalid argument - .note_1 = expected: `natvis_file = "..."` - .note_2 = OR - .note_3 = expected: `gdb_script_file = "..."` - -passes_debug_visualizer_placement = - attribute should be applied to a module - passes_debug_visualizer_unreadable = couldn't read {$file}: {$error} @@ -149,8 +140,17 @@ passes_doc_attribute_not_attribute = nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]` .help = only existing builtin attributes are allowed in core/std -passes_doc_cfg_hide_takes_list = - `#[doc(cfg_hide(...))]` takes a list of attributes +passes_doc_auto_cfg_expects_hide_or_show = + only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]` + +passes_doc_auto_cfg_hide_show_expects_list = + `#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items + +passes_doc_auto_cfg_hide_show_unexpected_item = + `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items + +passes_doc_auto_cfg_wrong_literal = + expected boolean for `#[doc(auto_cfg = ...)]` passes_doc_expect_str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] @@ -349,10 +349,6 @@ passes_invalid_attr_at_crate_level = passes_invalid_attr_at_crate_level_item = the inner attribute doesn't annotate this {$kind} -passes_invalid_macro_export_arguments = invalid `#[macro_export]` argument - -passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments - passes_lang_item_fn = {$name -> [panic_impl] `#[panic_handler]` *[other] `{$name}` lang item @@ -392,9 +388,6 @@ passes_loop_match_attr = `#[loop_match]` should be applied to a loop .label = not a loop -passes_macro_export = - `#[macro_export]` only has an effect on macro definitions - passes_macro_export_on_decl_macro = `#[macro_export]` has no effect on declarative macro definitions .note = declarative macros follow the same exporting rules as regular items diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4d5a8447695..4ea237cfa03 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,7 @@ use std::collections::hash_map::Entry; use std::slice; use rustc_abi::{Align, ExternAbi, Size}; -use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast}; +use rustc_ast::{AttrStyle, LitKind, MetaItem, MetaItemInner, MetaItemKind, ast}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; @@ -38,8 +38,8 @@ use rustc_middle::{bug, span_bug}; use rustc_session::config::CrateType; use rustc_session::lint; use rustc_session::lint::builtin::{ - CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, - MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, + CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_ATTRIBUTES, + MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; use rustc_span::edition::Edition; @@ -217,7 +217,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }, Attribute::Parsed(AttributeKind::Link(_, attr_span)) => { self.check_link(hir_id, *attr_span, span, target) - } + }, + Attribute::Parsed(AttributeKind::MacroExport { span, .. }) => { + self.check_macro_export(hir_id, *span, target) + }, Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -253,6 +256,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::MacroEscape( .. ) | AttributeKind::RustcLayoutScalarValidRangeStart(..) | AttributeKind::RustcLayoutScalarValidRangeEnd(..) + | AttributeKind::RustcSimdMonomorphizeLaneLimit(..) | AttributeKind::ExportStable | AttributeKind::FfiConst(..) | AttributeKind::UnstableFeatureBound(..) @@ -278,6 +282,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::ObjcClass { .. } | AttributeKind::ObjcSelector { .. } | AttributeKind::RustcCoherenceIsCore(..) + | AttributeKind::DebuggerVisualizer(..) ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -298,7 +303,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &mut doc_aliases, ), [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target), - [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target), [sym::rustc_no_implicit_autorefs, ..] => { self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target) } @@ -331,7 +335,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::rustc_has_incoherent_inherent_impls, ..] => { self.check_has_incoherent_inherent_impls(attr, span, target) } - [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } @@ -1157,16 +1160,59 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes. - /// - fn check_doc_cfg_hide(&self, meta: &MetaItemInner, hir_id: HirId) { - if meta.meta_item_list().is_none() { - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span(), - errors::DocCfgHideTakesList, - ); + /// Check that the `#![doc(auto_cfg)]` attribute has the expected input. + fn check_doc_auto_cfg(&self, meta: &MetaItem, hir_id: HirId) { + match &meta.kind { + MetaItemKind::Word => {} + MetaItemKind::NameValue(lit) => { + if !matches!(lit.kind, LitKind::Bool(_)) { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span, + errors::DocAutoCfgWrongLiteral, + ); + } + } + MetaItemKind::List(list) => { + for item in list { + let Some(attr_name @ (sym::hide | sym::show)) = item.name() else { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span, + errors::DocAutoCfgExpectsHideOrShow, + ); + continue; + }; + if let Some(list) = item.meta_item_list() { + for item in list { + let valid = item.meta_item().is_some_and(|meta| { + meta.path.segments.len() == 1 + && matches!( + &meta.kind, + MetaItemKind::Word | MetaItemKind::NameValue(_) + ) + }); + if !valid { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + item.span(), + errors::DocAutoCfgHideShowUnexpectedItem { attr_name }, + ); + } + } + } else { + self.tcx.emit_node_span_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span, + errors::DocAutoCfgHideShowExpectsList { attr_name }, + ); + } + } + } } } @@ -1242,10 +1288,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_attr_crate_level(attr, style, meta, hir_id); } - Some(sym::cfg_hide) => { - if self.check_attr_crate_level(attr, style, meta, hir_id) { - self.check_doc_cfg_hide(meta, hir_id); - } + Some(sym::auto_cfg) => { + self.check_doc_auto_cfg(i_meta, hir_id); } Some(sym::inline | sym::no_inline) => { @@ -1780,20 +1824,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if the items on the `#[debugger_visualizer]` attribute are valid. - fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) { - // Here we only check that the #[debugger_visualizer] attribute is attached - // to nothing other than a module. All other checks are done in the - // `debugger_visualizer` query where they need to be done for decoding - // anyway. - match target { - Target::Mod => {} - _ => { - self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span() }); - } - } - } - /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. /// (Allows proc_macro functions) fn check_rustc_allow_const_fn_unstable( @@ -1850,45 +1880,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) { + fn check_macro_export(&self, hir_id: HirId, attr_span: Span, target: Target) { if target != Target::MacroDef { + return; + } + + // special case when `#[macro_export]` is applied to a macro 2.0 + let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro(); + let is_decl_macro = !macro_definition.macro_rules; + + if is_decl_macro { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), - errors::MacroExport::Normal, + attr_span, + errors::MacroExport::OnDeclMacro, ); - } else if let Some(meta_item_list) = attr.meta_item_list() - && !meta_item_list.is_empty() - { - if meta_item_list.len() > 1 { - self.tcx.emit_node_span_lint( - INVALID_MACRO_EXPORT_ARGUMENTS, - hir_id, - attr.span(), - errors::MacroExport::TooManyItems, - ); - } else if !meta_item_list[0].has_name(sym::local_inner_macros) { - self.tcx.emit_node_span_lint( - INVALID_MACRO_EXPORT_ARGUMENTS, - hir_id, - meta_item_list[0].span(), - errors::MacroExport::InvalidArgument, - ); - } - } else { - // special case when `#[macro_export]` is applied to a macro 2.0 - let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro(); - let is_decl_macro = !macro_definition.macro_rules; - - if is_decl_macro { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::MacroExport::OnDeclMacro, - ); - } } } @@ -2253,7 +2260,9 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { // In the long run, the checks should be harmonized. if let ItemKind::Macro(_, macro_def, _) = item.kind { let def_id = item.owner_id.to_def_id(); - if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) { + if macro_def.macro_rules + && !find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::MacroExport { .. }) + { check_non_exported_macro_for_invalid_attrs(self.tcx, item); } } @@ -2384,7 +2393,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { // which were unsuccessfully resolved due to cannot determine // resolution for the attribute macro error. const ATTRS_TO_CHECK: &[Symbol] = &[ - sym::macro_export, sym::rustc_main, sym::derive, sym::test, diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index 7a7a8175e55..7211f3cf85b 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -1,67 +1,60 @@ //! Detecting usage of the `#[debugger_visualizer]` attribute. -use rustc_ast::Attribute; +use rustc_ast::ast::NodeId; +use rustc_ast::{HasNodeId, ItemKind, ast}; +use rustc_attr_parsing::AttributeParser; use rustc_expand::base::resolve_path; -use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; +use rustc_hir::Attribute; +use rustc_hir::attrs::{AttributeKind, DebugVisualizer}; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::query::{LocalCrate, Providers}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::sym; +use rustc_span::{DUMMY_SP, Span, sym}; -use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable}; +use crate::errors::DebugVisualizerUnreadable; impl DebuggerVisualizerCollector<'_> { - fn check_for_debugger_visualizer(&mut self, attr: &Attribute) { - if attr.has_name(sym::debugger_visualizer) { - let Some(hints) = attr.meta_item_list() else { - self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span }); - return; - }; + fn check_for_debugger_visualizer( + &mut self, + attrs: &[ast::Attribute], + span: Span, + node_id: NodeId, + ) { + if let Some(Attribute::Parsed(AttributeKind::DebuggerVisualizer(visualizers))) = + AttributeParser::parse_limited( + &self.sess, + attrs, + sym::debugger_visualizer, + span, + node_id, + None, + ) + { + for DebugVisualizer { span, visualizer_type, path } in visualizers { + let file = match resolve_path(&self.sess, path.as_str(), span) { + Ok(file) => file, + Err(err) => { + err.emit(); + return; + } + }; - let [hint] = hints.as_slice() else { - self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span }); - return; - }; - - let Some(meta_item) = hint.meta_item() else { - self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span }); - return; - }; - - let (visualizer_type, visualizer_path) = match (meta_item.name(), meta_item.value_str()) - { - (Some(sym::natvis_file), Some(value)) => (DebuggerVisualizerType::Natvis, value), - (Some(sym::gdb_script_file), Some(value)) => { - (DebuggerVisualizerType::GdbPrettyPrinter, value) - } - (_, _) => { - self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span }); - return; - } - }; - - let file = match resolve_path(&self.sess, visualizer_path.as_str(), attr.span) { - Ok(file) => file, - Err(err) => { - err.emit(); - return; - } - }; - - match self.sess.source_map().load_binary_file(&file) { - Ok((source, _)) => { - self.visualizers.push(DebuggerVisualizerFile::new( - source, - visualizer_type, - file, - )); - } - Err(error) => { - self.sess.dcx().emit_err(DebugVisualizerUnreadable { - span: meta_item.span, - file: &file, - error, - }); + match self.sess.source_map().load_binary_file(&file) { + Ok((source, _)) => { + self.visualizers.push(DebuggerVisualizerFile::new( + source, + visualizer_type, + file, + )); + } + Err(error) => { + self.sess.dcx().emit_err(DebugVisualizerUnreadable { + span, + file: &file, + error, + }); + } } } } @@ -74,9 +67,15 @@ struct DebuggerVisualizerCollector<'a> { } impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> { - fn visit_attribute(&mut self, attr: &'ast Attribute) { - self.check_for_debugger_visualizer(attr); - rustc_ast::visit::walk_attribute(self, attr); + fn visit_item(&mut self, item: &'ast rustc_ast::Item) -> Self::Result { + if let ItemKind::Mod(..) = item.kind { + self.check_for_debugger_visualizer(&item.attrs, item.span, item.node_id()); + } + rustc_ast::visit::walk_item(self, item); + } + fn visit_crate(&mut self, krate: &'ast ast::Crate) -> Self::Result { + self.check_for_debugger_visualizer(&krate.attrs, DUMMY_SP, krate.id); + rustc_ast::visit::walk_crate(self, krate); } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 2da4b6f52cf..f0726014e0a 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -309,8 +309,24 @@ pub(crate) struct DocTestLiteral; pub(crate) struct DocTestTakesList; #[derive(LintDiagnostic)] -#[diag(passes_doc_cfg_hide_takes_list)] -pub(crate) struct DocCfgHideTakesList; +#[diag(passes_doc_auto_cfg_wrong_literal)] +pub(crate) struct DocAutoCfgWrongLiteral; + +#[derive(LintDiagnostic)] +#[diag(passes_doc_auto_cfg_expects_hide_or_show)] +pub(crate) struct DocAutoCfgExpectsHideOrShow; + +#[derive(LintDiagnostic)] +#[diag(passes_doc_auto_cfg_hide_show_expects_list)] +pub(crate) struct DocAutoCfgHideShowExpectsList { + pub attr_name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(passes_doc_auto_cfg_hide_show_unexpected_item)] +pub(crate) struct DocAutoCfgHideShowUnexpectedItem { + pub attr_name: Symbol, +} #[derive(LintDiagnostic)] #[diag(passes_doc_test_unknown_any)] @@ -476,23 +492,6 @@ pub(crate) struct MacroOnlyAttribute { } #[derive(Diagnostic)] -#[diag(passes_debug_visualizer_placement)] -pub(crate) struct DebugVisualizerPlacement { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_debug_visualizer_invalid)] -#[note(passes_note_1)] -#[note(passes_note_2)] -#[note(passes_note_3)] -pub(crate) struct DebugVisualizerInvalid { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(passes_debug_visualizer_unreadable)] pub(crate) struct DebugVisualizerUnreadable<'a> { #[primary_span] @@ -530,18 +529,9 @@ pub(crate) struct RustcForceInlineCoro { #[derive(LintDiagnostic)] pub(crate) enum MacroExport { - #[diag(passes_macro_export)] - Normal, - #[diag(passes_macro_export_on_decl_macro)] #[note] OnDeclMacro, - - #[diag(passes_invalid_macro_export_arguments)] - InvalidArgument, - - #[diag(passes_invalid_macro_export_arguments_too_many_items)] - TooManyItems, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index d9f8085083e..0652461e975 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -120,7 +120,7 @@ impl<'p, 'tcx: 'p> fmt::Debug for RustcPatCtxt<'p, 'tcx> { impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// Type inference occasionally gives us opaque types in places where corresponding patterns /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited - /// types, we use the corresponding concrete type if possible. + /// types, we use the corresponding hidden type if possible. // FIXME(#132279): This will be unnecessary once we have a TypingMode which supports revealing // opaque types defined in a body. #[inline] @@ -146,7 +146,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// know it. fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> { self.typeck_results - .concrete_opaque_types + .hidden_types .get(&key.def_id) .map(|x| ty::EarlyBinder::bind(x.ty).instantiate(self.tcx, key.args)) } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 1bddbd03cc3..c9dbb204f61 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -45,7 +45,7 @@ use tracing::debug; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } //////////////////////////////////////////////////////////////////////////////// -/// Generic infrastructure used to implement specific visitors below. +// Generic infrastructure used to implement specific visitors below. //////////////////////////////////////////////////////////////////////////////// struct LazyDefPathStr<'tcx> { @@ -309,10 +309,7 @@ fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visib if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 } } -//////////////////////////////////////////////////////////////////////////////// /// Visitor used to determine impl visibility and reachability. -//////////////////////////////////////////////////////////////////////////////// - struct FindMin<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> { tcx: TyCtxt<'tcx>, effective_visibilities: &'a EffectiveVisibilities, @@ -387,10 +384,7 @@ impl VisibilityLike for EffectiveVisibility { } } -//////////////////////////////////////////////////////////////////////////////// /// The embargo visitor, used to determine the exports of the AST. -//////////////////////////////////////////////////////////////////////////////// - struct EmbargoVisitor<'tcx> { tcx: TyCtxt<'tcx>, @@ -849,9 +843,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> } } -//////////////////////////////////////////////////////////////////////////////// /// Visitor, used for EffectiveVisibilities table checking -//////////////////////////////////////////////////////////////////////////////// pub struct TestReachabilityVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, effective_visibilities: &'a EffectiveVisibilities, @@ -909,13 +901,11 @@ impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> { } } -////////////////////////////////////////////////////////////////////////////////////// /// Name privacy visitor, checks privacy and reports violations. +/// /// Most of name privacy checks are performed during the main resolution phase, /// or later in type checking when field accesses and associated items are resolved. /// This pass performs remaining checks for fields in struct expressions and patterns. -////////////////////////////////////////////////////////////////////////////////////// - struct NamePrivacyVisitor<'tcx> { tcx: TyCtxt<'tcx>, maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, @@ -1120,12 +1110,10 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { } } -//////////////////////////////////////////////////////////////////////////////////////////// /// Type privacy visitor, checks types for privacy and reports violations. +/// /// Both explicitly written types and inferred types of expressions and patterns are checked. /// Checks are performed on "semantic" types regardless of names and their hygiene. -//////////////////////////////////////////////////////////////////////////////////////////// - struct TypePrivacyVisitor<'tcx> { tcx: TyCtxt<'tcx>, module_def_id: LocalModDefId, @@ -1345,13 +1333,11 @@ impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> { } } -/////////////////////////////////////////////////////////////////////////////// /// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and /// finds any private components in it. +/// /// PrivateItemsInPublicInterfacesVisitor ensures there are no private types /// and traits in public interfaces. -/////////////////////////////////////////////////////////////////////////////// - struct SearchInterfaceForPrivateItemsVisitor<'tcx> { tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs index 276adacd99e..7bd06fee721 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -836,14 +836,6 @@ pub enum ProjectionElem { /// Like an explicit cast from an opaque type to a concrete type, but without /// requiring an intermediate variable. OpaqueCast(Ty), - - /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where - /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping - /// explicit during optimizations and codegen. - /// - /// This projection doesn't impact the runtime behavior of the program except for potentially changing - /// some type metadata of the interpreter or codegen backend. - Subtype(Ty), } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] @@ -1028,6 +1020,7 @@ pub enum CastKind { PtrToPtr, FnPtrToPtr, Transmute, + Subtype, } #[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] @@ -1089,7 +1082,7 @@ impl ProjectionElem { Self::subslice_ty(ty, *from, *to, *from_end) } ProjectionElem::Downcast(_) => Ok(ty), - ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty), + ProjectionElem::OpaqueCast(ty) => Ok(*ty), } } diff --git a/compiler/rustc_public/src/mir/visit.rs b/compiler/rustc_public/src/mir/visit.rs index 04c4d4d2a82..7563c9ca008 100644 --- a/compiler/rustc_public/src/mir/visit.rs +++ b/compiler/rustc_public/src/mir/visit.rs @@ -471,7 +471,6 @@ macro_rules! visit_place_fns { ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} ProjectionElem::Downcast(_idx) => {} ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), - ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), } } }; @@ -512,7 +511,6 @@ macro_rules! visit_place_fns { ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} ProjectionElem::Downcast(_idx) => {} ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), - ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), } } }; diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs index dc9abd88614..064fb6c6803 100644 --- a/compiler/rustc_public/src/unstable/convert/internal.rs +++ b/compiler/rustc_public/src/unstable/convert/internal.rs @@ -703,9 +703,6 @@ impl RustcInternal for ProjectionElem { ProjectionElem::OpaqueCast(ty) => { rustc_middle::mir::PlaceElem::OpaqueCast(ty.internal(tables, tcx)) } - ProjectionElem::Subtype(ty) => { - rustc_middle::mir::PlaceElem::Subtype(ty.internal(tables, tcx)) - } } } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index b10af6526ea..62ab91d17ba 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -356,6 +356,7 @@ impl<'tcx> Stable<'tcx> for mir::CastKind { PtrToPtr => crate::mir::CastKind::PtrToPtr, FnPtrToPtr => crate::mir::CastKind::FnPtrToPtr, Transmute => crate::mir::CastKind::Transmute, + Subtype => crate::mir::CastKind::Subtype, } } } @@ -453,7 +454,6 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> { // found at https://github.com/rust-lang/rust/pull/117517#issuecomment-1811683486 Downcast(_, idx) => crate::mir::ProjectionElem::Downcast(idx.stable(tables, cx)), OpaqueCast(ty) => crate::mir::ProjectionElem::OpaqueCast(ty.stable(tables, cx)), - Subtype(ty) => crate::mir::ProjectionElem::Subtype(ty.stable(tables, cx)), UnwrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"), } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 7f14f878d37..59440e5407f 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -453,7 +453,10 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { TyKind::Alias(alias_kind.stable(tables, cx), alias_ty.stable(tables, cx)) } ty::Param(param_ty) => TyKind::Param(param_ty.stable(tables, cx)), - ty::Bound(debruijn_idx, bound_ty) => { + ty::Bound(ty::BoundVarIndexKind::Canonical, _) => { + unreachable!() + } + ty::Bound(ty::BoundVarIndexKind::Bound(debruijn_idx), bound_ty) => { TyKind::Bound(debruijn_idx.as_usize(), bound_ty.stable(tables, cx)) } ty::CoroutineWitness(def_id, args) => TyKind::RigidTy(RigidTy::CoroutineWitness( @@ -907,7 +910,7 @@ impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> { index: early_reg.index, name: early_reg.name.to_string(), }), - ty::ReBound(db_index, bound_reg) => RegionKind::ReBound( + ty::ReBound(ty::BoundVarIndexKind::Bound(db_index), bound_reg) => RegionKind::ReBound( db_index.as_u32(), BoundRegion { var: bound_reg.var.as_u32(), diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index fa3c06059b3..c10b6ca7e71 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -5,7 +5,6 @@ //! unexpanded macros in the fragment are visited and registered. //! Imports are also considered items and placed into modules here, but not resolved yet. -use std::cell::Cell; use std::sync::Arc; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; @@ -35,6 +34,7 @@ use crate::Namespace::{MacroNS, TypeNS, ValueNS}; use crate::def_collector::collect_definitions; use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; +use crate::ref_mut::CmCell; use crate::{ BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used, @@ -87,7 +87,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // because they can be fetched by glob imports from those modules, and bring traits // into scope both directly and through glob imports. let key = BindingKey::new_disambiguated(ident, ns, || { - parent.underscore_disambiguator.update(|d| d + 1); + // FIXME(batched): Will be fixed in batched resolution. + parent.underscore_disambiguator.update_unchecked(|d| d + 1); parent.underscore_disambiguator.get() }); if self @@ -477,7 +478,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { kind, parent_scope: self.parent_scope, module_path, - imported_module: Cell::new(None), + imported_module: CmCell::new(None), span, use_span: item.span, use_span_with_attributes: item.span_with_attributes(), @@ -505,7 +506,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); } } - ImportKind::Glob { .. } => current_module.globs.borrow_mut().push(import), + ImportKind::Glob { .. } => current_module.globs.borrow_mut(self.r).push(import), _ => unreachable!(), } } @@ -668,7 +669,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ast::UseTreeKind::Glob => { if !ast::attr::contains_name(&item.attrs, sym::prelude_import) { - let kind = ImportKind::Glob { max_vis: Cell::new(None), id }; + let kind = ImportKind::Glob { max_vis: CmCell::new(None), id }; self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis); } else { // Resolve the prelude import early. @@ -971,7 +972,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id }, root_id: item.id, parent_scope: self.parent_scope, - imported_module: Cell::new(module), + imported_module: CmCell::new(module), has_attributes: !item.attrs.is_empty(), use_span_with_attributes: item.span_with_attributes(), use_span: item.span, @@ -1103,7 +1104,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { kind: ImportKind::MacroUse { warn_private }, root_id: item.id, parent_scope: this.parent_scope, - imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), + imported_module: CmCell::new(Some(ModuleOrUniformRoot::Module(module))), use_span_with_attributes: item.span_with_attributes(), has_attributes: !item.attrs.is_empty(), use_span: item.span, @@ -1196,7 +1197,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { /// directly into its parent scope's module. fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'ra> { let invoc_id = self.visit_invoc(id); - self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id); + self.parent_scope.module.unexpanded_invocations.borrow_mut(self.r).insert(invoc_id); self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id)) } @@ -1274,7 +1275,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { kind: ImportKind::MacroExport, root_id: item.id, parent_scope: self.parent_scope, - imported_module: Cell::new(None), + imported_module: CmCell::new(None), has_attributes: false, use_span_with_attributes: span, use_span: span, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 35051675fd8..4415300777f 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -492,14 +492,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => Err(Determinacy::Determined), }, Scope::Module(module, derive_fallback_lint_id) => { - // FIXME: use `finalize_scope` here. let (adjusted_parent_scope, adjusted_finalize) = if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) { - (parent_scope, finalize) + (parent_scope, finalize_scope!()) } else { ( &ParentScope { module, ..*parent_scope }, - finalize.map(|f| Finalize { used: Used::Scope, ..f }), + finalize_scope!().map(|f| Finalize { used: Used::Scope, ..f }), ) }; let binding = this.reborrow().resolve_ident_in_module_unadjusted( @@ -557,8 +556,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => Err(Determinacy::Determined), }, Scope::ExternPreludeItems => { - // FIXME: use `finalize_scope` here. - match this.reborrow().extern_prelude_get_item(ident, finalize.is_some()) { + match this + .reborrow() + .extern_prelude_get_item(ident, finalize_scope!().is_some()) + { Some(binding) => { extern_prelude_item_binding = Some(binding); Ok((binding, Flags::empty())) @@ -900,6 +901,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding, if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, parent_scope, + module, finalize, shadowing, ); @@ -1024,6 +1026,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding: Option<NameBinding<'ra>>, shadowed_glob: Option<NameBinding<'ra>>, parent_scope: &ParentScope<'ra>, + module: Module<'ra>, finalize: Finalize, shadowing: Shadowing, ) -> Result<NameBinding<'ra>, (Determinacy, Weak)> { @@ -1075,6 +1078,37 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } + // If we encounter a re-export for a type with private fields, it will not be able to + // be constructed through this re-export. We track that case here to expand later + // privacy errors with appropriate information. + if let Res::Def(_, def_id) = binding.res() { + let struct_ctor = match def_id.as_local() { + Some(def_id) => self.struct_constructors.get(&def_id).cloned(), + None => { + let ctor = self.cstore().ctor_untracked(def_id); + ctor.map(|(ctor_kind, ctor_def_id)| { + let ctor_res = Res::Def( + DefKind::Ctor(rustc_hir::def::CtorOf::Struct, ctor_kind), + ctor_def_id, + ); + let ctor_vis = self.tcx.visibility(ctor_def_id); + let field_visibilities = self + .tcx + .associated_item_def_ids(def_id) + .iter() + .map(|field_id| self.tcx.visibility(field_id)) + .collect(); + (ctor_res, ctor_vis, field_visibilities) + }) + } + }; + if let Some((_, _, fields)) = struct_ctor + && fields.iter().any(|vis| !self.is_accessible_from(*vis, module)) + { + self.inaccessible_ctor_reexport.insert(path_span, binding.span); + } + } + self.record_use(ident, binding, used); return Ok(binding); } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 33c2c7436d1..ce90a1bcd31 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1,6 +1,5 @@ //! A bunch of methods and structures more or less related to resolving imports. -use std::cell::Cell; use std::mem; use rustc_ast::NodeId; @@ -32,6 +31,7 @@ use crate::errors::{ CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates, ConsiderAddingMacroExport, ConsiderMarkingAsPub, ConsiderMarkingAsPubCrate, }; +use crate::ref_mut::CmCell; use crate::{ AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion, Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, @@ -68,7 +68,7 @@ pub(crate) enum ImportKind<'ra> { /// It will directly use `source` when the format is `use prefix::source`. target: Ident, /// Bindings introduced by the import. - bindings: PerNS<Cell<PendingBinding<'ra>>>, + bindings: PerNS<CmCell<PendingBinding<'ra>>>, /// `true` for `...::{self [as target]}` imports, `false` otherwise. type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` @@ -89,7 +89,7 @@ pub(crate) enum ImportKind<'ra> { Glob { // The visibility of the greatest re-export. // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. - max_vis: Cell<Option<Visibility>>, + max_vis: CmCell<Option<Visibility>>, id: NodeId, }, ExternCrate { @@ -182,7 +182,7 @@ pub(crate) struct ImportData<'ra> { /// |`use ::foo` | `ModuleOrUniformRoot::ExternPrelude` | 2018+ editions | /// |`use ::foo` | `ModuleOrUniformRoot::ModuleAndExternPrelude` | a special case in 2015 edition | /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - | - pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>, + pub imported_module: CmCell<Option<ModuleOrUniformRoot<'ra>>>, pub vis: Visibility, /// Span of the visibility. @@ -320,7 +320,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && (vis == import_vis || max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx))) { - max_vis.set(Some(vis.expect_local())) + // FIXME(batched): Will be fixed in batched import resolution. + max_vis.set_unchecked(Some(vis.expect_local())) } self.arenas.alloc_name_binding(NameBindingData { @@ -349,7 +350,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // because they can be fetched by glob imports from those modules, and bring traits // into scope both directly and through glob imports. let key = BindingKey::new_disambiguated(ident, ns, || { - module.underscore_disambiguator.update(|d| d + 1); + // FIXME(batched): Will be fixed in batched resolution. + module.underscore_disambiguator.update_unchecked(|d| d + 1); module.underscore_disambiguator.get() }); self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| { @@ -482,7 +484,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } }; - let Ok(glob_importers) = module.glob_importers.try_borrow_mut() else { + let Ok(glob_importers) = module.glob_importers.try_borrow_mut_unchecked() else { return t; }; @@ -862,7 +864,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } }; - import.imported_module.set(Some(module)); + // FIXME(batched): Will be fixed in batched import resolution. + import.imported_module.set_unchecked(Some(module)); let (source, target, bindings, type_ns_only) = match import.kind { ImportKind::Single { source, target, ref bindings, type_ns_only, .. } => { (source, target, bindings, type_ns_only) @@ -937,7 +940,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PendingBinding::Pending } }; - bindings[ns].set(binding); + // FIXME(batched): Will be fixed in batched import resolution. + bindings[ns].set_unchecked(binding); } }); @@ -1508,7 +1512,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Add to module's glob_importers - module.glob_importers.borrow_mut().push(import); + module.glob_importers.borrow_mut_unchecked().push(import); // Ensure that `resolutions` isn't borrowed during `try_define`, // since it might get updated via a glob cycle. @@ -1550,7 +1554,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // reporting conflicts, and reporting unresolved imports. fn finalize_resolutions_in(&mut self, module: Module<'ra>) { // Since import resolution is finished, globs will not define any more names. - *module.globs.borrow_mut() = Vec::new(); + *module.globs.borrow_mut(self) = Vec::new(); let Some(def_id) = module.opt_def_id() else { return }; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9e3c0938836..8c2ddda7f98 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1942,44 +1942,77 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { return true; }; + let update_message = + |this: &mut Self, err: &mut Diag<'_>, source: &PathSource<'_, '_, '_>| { + match source { + // e.g. `if let Enum::TupleVariant(field1, field2) = _` + PathSource::TupleStruct(_, pattern_spans) => { + err.primary_message( + "cannot match against a tuple struct which contains private fields", + ); + + // Use spans of the tuple struct pattern. + Some(Vec::from(*pattern_spans)) + } + // e.g. `let _ = Enum::TupleVariant(field1, field2);` + PathSource::Expr(Some(Expr { + kind: ExprKind::Call(path, args), + span: call_span, + .. + })) => { + err.primary_message( + "cannot initialize a tuple struct which contains private fields", + ); + this.suggest_alternative_construction_methods( + def_id, + err, + path.span, + *call_span, + &args[..], + ); + // Use spans of the tuple struct definition. + this.r + .field_idents(def_id) + .map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>()) + } + _ => None, + } + }; let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module); + if let Some(use_span) = self.r.inaccessible_ctor_reexport.get(&span) + && is_accessible + { + err.span_note( + *use_span, + "the type is accessed through this re-export, but the type's constructor \ + is not visible in this import's scope due to private fields", + ); + if is_accessible + && fields + .iter() + .all(|vis| self.r.is_accessible_from(*vis, self.parent_scope.module)) + { + err.span_suggestion_verbose( + span, + "the type can be constructed directly, because its fields are \ + available from the current scope", + // Using `tcx.def_path_str` causes the compiler to hang. + // We don't need to handle foreign crate types because in that case you + // can't access the ctor either way. + format!( + "crate{}", // The method already has leading `::`. + self.r.tcx.def_path(def_id).to_string_no_crate_verbose(), + ), + Applicability::MachineApplicable, + ); + } + update_message(self, err, &source); + } if !is_expected(ctor_def) || is_accessible { return true; } - let field_spans = match source { - // e.g. `if let Enum::TupleVariant(field1, field2) = _` - PathSource::TupleStruct(_, pattern_spans) => { - err.primary_message( - "cannot match against a tuple struct which contains private fields", - ); - - // Use spans of the tuple struct pattern. - Some(Vec::from(pattern_spans)) - } - // e.g. `let _ = Enum::TupleVariant(field1, field2);` - PathSource::Expr(Some(Expr { - kind: ExprKind::Call(path, args), - span: call_span, - .. - })) => { - err.primary_message( - "cannot initialize a tuple struct which contains private fields", - ); - self.suggest_alternative_construction_methods( - def_id, - err, - path.span, - *call_span, - &args[..], - ); - // Use spans of the tuple struct definition. - self.r - .field_idents(def_id) - .map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>()) - } - _ => None, - }; + let field_spans = update_message(self, err, &source); if let Some(spans) = field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len()) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8b185ce7ef2..b44b1c966a4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -19,6 +19,7 @@ #![feature(default_field_values)] #![feature(if_let_guard)] #![feature(iter_intersperse)] +#![feature(ptr_as_ref_unchecked)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![recursion_limit = "256"] @@ -26,7 +27,7 @@ use std::cell::{Cell, Ref, RefCell}; use std::collections::BTreeSet; -use std::fmt; +use std::fmt::{self}; use std::sync::Arc; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; @@ -95,6 +96,8 @@ pub mod rustdoc; pub use macros::registered_tools_ast; +use crate::ref_mut::{CmCell, CmRefCell}; + rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[derive(Debug)] @@ -592,22 +595,22 @@ struct ModuleData<'ra> { /// Resolutions in modules from other crates are not populated until accessed. lazy_resolutions: Resolutions<'ra>, /// True if this is a module from other crate that needs to be populated on access. - populate_on_access: Cell<bool>, + populate_on_access: Cell<bool>, // FIXME(parallel): Use an atomic in parallel import resolution /// Used to disambiguate underscore items (`const _: T = ...`) in the module. - underscore_disambiguator: Cell<u32>, + underscore_disambiguator: CmCell<u32>, /// Macro invocations that can expand into items in this module. - unexpanded_invocations: RefCell<FxHashSet<LocalExpnId>>, + unexpanded_invocations: CmRefCell<FxHashSet<LocalExpnId>>, /// Whether `#[no_implicit_prelude]` is active. no_implicit_prelude: bool, - glob_importers: RefCell<Vec<Import<'ra>>>, - globs: RefCell<Vec<Import<'ra>>>, + glob_importers: CmRefCell<Vec<Import<'ra>>>, + globs: CmRefCell<Vec<Import<'ra>>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. traits: - RefCell<Option<Box<[(Macros20NormalizedIdent, NameBinding<'ra>, Option<Module<'ra>>)]>>>, + CmRefCell<Option<Box<[(Macros20NormalizedIdent, NameBinding<'ra>, Option<Module<'ra>>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -656,12 +659,12 @@ impl<'ra> ModuleData<'ra> { kind, lazy_resolutions: Default::default(), populate_on_access: Cell::new(is_foreign), - underscore_disambiguator: Cell::new(0), + underscore_disambiguator: CmCell::new(0), unexpanded_invocations: Default::default(), no_implicit_prelude, - glob_importers: RefCell::new(Vec::new()), - globs: RefCell::new(Vec::new()), - traits: RefCell::new(None), + glob_importers: CmRefCell::new(Vec::new()), + globs: CmRefCell::new(Vec::new()), + traits: CmRefCell::new(None), span, expansion, self_binding, @@ -696,7 +699,7 @@ impl<'ra> Module<'ra> { /// This modifies `self` in place. The traits will be stored in `self.traits`. fn ensure_traits<'tcx>(self, resolver: &impl AsRef<Resolver<'ra, 'tcx>>) { - let mut traits = self.traits.borrow_mut(); + let mut traits = self.traits.borrow_mut(resolver.as_ref()); if traits.is_none() { let mut collected_traits = Vec::new(); self.for_each_child(resolver, |r, name, ns, binding| { @@ -1164,6 +1167,11 @@ pub struct Resolver<'ra, 'tcx> { /// Crate-local macro expanded `macro_export` referred to by a module-relative path. macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(), + /// When a type is re-exported that has an inaccessible constructor because it has fields that + /// are inaccessible from the import's scope, we mark that as the type won't be able to be built + /// through the re-export. We use this information to extend the existing diagnostic. + inaccessible_ctor_reexport: FxHashMap<Span, Span>, + arenas: &'ra ResolverArenas<'ra>, dummy_binding: NameBinding<'ra>, builtin_types_bindings: FxHashMap<Symbol, NameBinding<'ra>>, @@ -1592,6 +1600,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { glob_map: Default::default(), used_imports: FxHashSet::default(), maybe_unused_trait_imports: Default::default(), + inaccessible_ctor_reexport: Default::default(), arenas, dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT), @@ -1974,6 +1983,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> { if module.populate_on_access.get() { + // FIXME(batched): Will be fixed in batched import resolution. module.populate_on_access.set(false); self.build_reduced_graph_external(module); } @@ -2504,9 +2514,20 @@ pub fn provide(providers: &mut Providers) { providers.registered_tools = macros::registered_tools; } +/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions. +/// +/// `Cm` stands for "conditionally mutable". +/// +/// Prefer constructing it through [`Resolver::cm`] to ensure correctness. +type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>; + mod ref_mut { + use std::cell::{BorrowMutError, Cell, Ref, RefCell, RefMut}; + use std::fmt; use std::ops::Deref; + use crate::Resolver; + /// A wrapper around a mutable reference that conditionally allows mutable access. pub(crate) struct RefOrMut<'a, T> { p: &'a mut T, @@ -2555,11 +2576,86 @@ mod ref_mut { self.p } } -} -/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions. -/// -/// `Cm` stands for "conditionally mutable". -/// -/// Prefer constructing it through [`Resolver::cm`] to ensure correctness. -type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>; + /// A wrapper around a [`Cell`] that only allows mutation based on a condition in the resolver. + #[derive(Default)] + pub(crate) struct CmCell<T>(Cell<T>); + + impl<T: Copy + fmt::Debug> fmt::Debug for CmCell<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("CmCell").field(&self.get()).finish() + } + } + + impl<T: Copy> Clone for CmCell<T> { + #[inline] + fn clone(&self) -> CmCell<T> { + CmCell::new(self.get()) + } + } + + impl<T: Copy> CmCell<T> { + pub(crate) const fn get(&self) -> T { + self.0.get() + } + + pub(crate) fn update_unchecked(&self, f: impl FnOnce(T) -> T) + where + T: Copy, + { + let old = self.get(); + self.set_unchecked(f(old)); + } + } + + impl<T> CmCell<T> { + pub(crate) const fn new(value: T) -> CmCell<T> { + CmCell(Cell::new(value)) + } + + pub(crate) fn set_unchecked(&self, val: T) { + self.0.set(val); + } + + pub(crate) fn into_inner(self) -> T { + self.0.into_inner() + } + } + + /// A wrapper around a [`RefCell`] that only allows mutable borrows based on a condition in the resolver. + #[derive(Default)] + pub(crate) struct CmRefCell<T>(RefCell<T>); + + impl<T> CmRefCell<T> { + pub(crate) const fn new(value: T) -> CmRefCell<T> { + CmRefCell(RefCell::new(value)) + } + + #[inline] + #[track_caller] + pub(crate) fn borrow_mut_unchecked(&self) -> RefMut<'_, T> { + self.0.borrow_mut() + } + + #[inline] + #[track_caller] + pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> RefMut<'_, T> { + if r.assert_speculative { + panic!("Not allowed to mutably borrow a CmRefCell during speculative resolution"); + } + self.borrow_mut_unchecked() + } + + #[inline] + #[track_caller] + pub(crate) fn try_borrow_mut_unchecked(&self) -> Result<RefMut<'_, T>, BorrowMutError> { + self.0.try_borrow_mut() + } + + #[inline] + #[track_caller] + pub(crate) fn borrow(&self) -> Ref<'_, T> { + self.0.borrow() + } + } +} diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index d3e98ef839b..c50dfd41b51 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -189,7 +189,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { let output_macro_rules_scope = self.build_reduced_graph(fragment, parent_scope); self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope); - parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion); + parent_scope.module.unexpanded_invocations.borrow_mut(self).remove(&expansion); if let Some(unexpanded_invocations) = self.impl_unexpanded_invocations.get_mut(&self.invocation_parent(expansion)) { diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index ec7a4a81a71..621cc0fb3ef 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -287,7 +287,7 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, // u6region[I[<region-disambiguator>][<region-index>]E] as vendor extended type let mut s = String::new(); match region.kind() { - RegionKind::ReBound(debruijn, r) => { + RegionKind::ReBound(ty::BoundVarIndexKind::Bound(debruijn), r) => { s.push_str("u6regionI"); // Debruijn index, which identifies the binder, as region disambiguator let num = debruijn.index() as u64; @@ -303,7 +303,8 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, s.push_str("u6region"); compress(dict, DictKey::Region(region), &mut s); } - RegionKind::ReEarlyParam(..) + RegionKind::ReBound(ty::BoundVarIndexKind::Canonical, _) + | RegionKind::ReEarlyParam(..) | RegionKind::ReLateParam(..) | RegionKind::ReStatic | RegionKind::ReError(_) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 795cb2b2cfe..d1426ff55fb 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -29,7 +29,8 @@ use rustc_span::{ SourceFileHashAlgorithm, Symbol, sym, }; use rustc_target::spec::{ - FramePointer, LinkSelfContainedComponents, LinkerFeatures, SplitDebuginfo, Target, TargetTuple, + FramePointer, LinkSelfContainedComponents, LinkerFeatures, PanicStrategy, SplitDebuginfo, + Target, TargetTuple, }; use tracing::debug; @@ -257,6 +258,8 @@ pub enum AutoDiff { LooseTypes, /// Runs Enzyme's aggressive inlining Inline, + /// Disable Type Tree + NoTT, } /// Settings for `-Z instrument-xray` flag. @@ -1192,6 +1195,7 @@ pub struct OutputFilenames { filestem: String, pub single_output_file: Option<OutFileName>, temps_directory: Option<PathBuf>, + explicit_dwo_out_directory: Option<PathBuf>, pub outputs: OutputTypes, } @@ -1224,6 +1228,7 @@ impl OutputFilenames { out_filestem: String, single_output_file: Option<OutFileName>, temps_directory: Option<PathBuf>, + explicit_dwo_out_directory: Option<PathBuf>, extra: String, outputs: OutputTypes, ) -> Self { @@ -1231,6 +1236,7 @@ impl OutputFilenames { out_directory, single_output_file, temps_directory, + explicit_dwo_out_directory, outputs, crate_stem: format!("{out_crate_name}{extra}"), filestem: format!("{out_filestem}{extra}"), @@ -1280,7 +1286,14 @@ impl OutputFilenames { codegen_unit_name: &str, invocation_temp: Option<&str>, ) -> PathBuf { - self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name, invocation_temp) + let p = self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name, invocation_temp); + if let Some(dwo_out) = &self.explicit_dwo_out_directory { + let mut o = dwo_out.clone(); + o.push(p.file_name().unwrap()); + o + } else { + p + } } /// Like `temp_path`, but also supports things where there is no corresponding @@ -1620,6 +1633,7 @@ pub struct PacRet { pub struct BranchProtection { pub bti: bool, pub pac_ret: Option<PacRet>, + pub gcs: bool, } pub(crate) const fn default_lib_output() -> CrateType { @@ -2799,6 +2813,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M } } + if !unstable_options_enabled && cg.panic == Some(PanicStrategy::ImmediateAbort) { + early_dcx.early_fatal( + "`-Cpanic=immediate-abort` requires `-Zunstable-options` and a nightly compiler", + ) + } + let crate_name = matches.opt_str("crate-name"); let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref()); // Parse any `-l` flags, which link to native libraries. diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index 7e970461ab7..a72f6201dce 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -125,7 +125,9 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) { None | Some(_), ) => disallow(cfg, "-Z sanitizer=cfi"), (sym::proc_macro, None) => disallow(cfg, "--crate-type proc-macro"), - (sym::panic, Some(sym::abort | sym::unwind)) => disallow(cfg, "-C panic"), + (sym::panic, Some(sym::abort | sym::unwind | sym::immediate_abort)) => { + disallow(cfg, "-C panic") + } (sym::target_feature, Some(_)) => disallow(cfg, "-C target-feature"), (sym::unix, None) | (sym::windows, None) @@ -203,7 +205,14 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { ins_none!(sym::overflow_checks); } + // We insert a cfg for the name of session's panic strategy. + // Since the ImmediateAbort strategy is new, it also sets cfg(panic="abort"), so that code + // which is trying to detect whether unwinding is enabled by checking for cfg(panic="abort") + // does not need to be updated. ins_sym!(sym::panic, sess.panic_strategy().desc_symbol()); + if sess.panic_strategy() == PanicStrategy::ImmediateAbort { + ins_sym!(sym::panic, PanicStrategy::Abort.desc_symbol()); + } // JUSTIFICATION: before wrapper fn is available #[allow(rustc::bad_opt_access)] @@ -250,11 +259,11 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { }); let mut has_atomic = false; for (i, align) in [ - (8, layout.i8_align.abi), - (16, layout.i16_align.abi), - (32, layout.i32_align.abi), - (64, layout.i64_align.abi), - (128, layout.i128_align.abi), + (8, layout.i8_align), + (16, layout.i16_align), + (32, layout.i32_align), + (64, layout.i64_align), + (128, layout.i128_align), ] { if i >= sess.target.min_atomic_width() && i <= sess.target.max_atomic_width() { if !has_atomic { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 69facde6936..6dd90546de1 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -792,7 +792,7 @@ mod desc { pub(crate) const parse_list: &str = "a space-separated list of strings"; pub(crate) const parse_list_with_polarity: &str = "a comma-separated list of strings, with elements beginning with + or -"; - pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintTAFn`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`"; + pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintTAFn`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`, `NoTT`"; pub(crate) const parse_offload: &str = "a comma separated list of settings: `Enable`"; pub(crate) const parse_comma_list: &str = "a comma-separated list of strings"; pub(crate) const parse_opt_comma_list: &str = parse_comma_list; @@ -802,7 +802,7 @@ mod desc { pub(crate) const parse_threads: &str = parse_number; pub(crate) const parse_time_passes_format: &str = "`text` (default) or `json`"; pub(crate) const parse_passes: &str = "a space-separated list of passes, or `all`"; - pub(crate) const parse_panic_strategy: &str = "either `unwind` or `abort`"; + pub(crate) const parse_panic_strategy: &str = "either `unwind`, `abort`, or `immediate-abort`"; pub(crate) const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`"; pub(crate) const parse_patchable_function_entry: &str = "either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops)"; pub(crate) const parse_opt_panic_strategy: &str = parse_panic_strategy; @@ -866,7 +866,7 @@ mod desc { pub(crate) const parse_polonius: &str = "either no value or `legacy` (the default), or `next`"; pub(crate) const parse_stack_protector: &str = "one of (`none` (default), `basic`, `strong`, or `all`)"; - pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf`"; + pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set)"; pub(crate) const parse_proc_macro_execution_strategy: &str = "one of supported execution strategies (`same-thread`, or `cross-thread`)"; pub(crate) const parse_remap_path_scope: &str = @@ -1165,6 +1165,7 @@ pub mod parse { match v { Some("unwind") => *slot = Some(PanicStrategy::Unwind), Some("abort") => *slot = Some(PanicStrategy::Abort), + Some("immediate-abort") => *slot = Some(PanicStrategy::ImmediateAbort), _ => return false, } true @@ -1174,6 +1175,7 @@ pub mod parse { match v { Some("unwind") => *slot = PanicStrategy::Unwind, Some("abort") => *slot = PanicStrategy::Abort, + Some("immediate-abort") => *slot = PanicStrategy::ImmediateAbort, _ => return false, } true @@ -1479,6 +1481,7 @@ pub mod parse { "PrintPasses" => AutoDiff::PrintPasses, "LooseTypes" => AutoDiff::LooseTypes, "Inline" => AutoDiff::Inline, + "NoTT" => AutoDiff::NoTT, _ => { // FIXME(ZuseZ4): print an error saying which value is not recognized return false; @@ -1903,6 +1906,7 @@ pub mod parse { Some(pac) => pac.pc = true, _ => return false, }, + "gcs" => slot.gcs = true, _ => return false, }; } @@ -2630,6 +2634,8 @@ written to standard error output)"), file which is ignored by the linker `single`: sections which do not require relocation are written into object file but ignored by the linker"), + split_dwarf_out_dir : Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], + "location for writing split DWARF objects (`.dwo`) if enabled"), split_lto_unit: Option<bool> = (None, parse_opt_bool, [TRACKED], "enable LTO unit splitting (default: no)"), src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index d0dd2cdac0c..25b46241c52 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -777,9 +777,11 @@ impl Session { // Otherwise, we can defer to the `-C force-unwind-tables=<yes/no>` // value, if it is provided, or disable them, if not. self.target.requires_uwtable - || self.opts.cg.force_unwind_tables.unwrap_or( - self.panic_strategy() == PanicStrategy::Unwind || self.target.default_uwtable, - ) + || self + .opts + .cg + .force_unwind_tables + .unwrap_or(self.panic_strategy().unwinds() || self.target.default_uwtable) } /// Returns the number of query threads that should be used for this @@ -1229,7 +1231,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } // KCFI requires panic=abort - if sess.is_sanitizer_kcfi_enabled() && sess.panic_strategy() != PanicStrategy::Abort { + if sess.is_sanitizer_kcfi_enabled() && sess.panic_strategy().unwinds() { sess.dcx().emit_err(errors::SanitizerKcfiRequiresPanicAbort); } diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index c32593a6d95..bb2cda77dff 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -81,8 +81,8 @@ cfg_select! { // use `loadu`, which supports unaligned loading. let chunk = unsafe { _mm_loadu_si128(chunk.as_ptr() as *const __m128i) }; - // For character in the chunk, see if its byte value is < 0, which - // indicates that it's part of a UTF-8 char. + // For each character in the chunk, see if its byte value is < 0, + // which indicates that it's part of a UTF-8 char. let multibyte_test = _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)); // Create a bit mask from the comparison results. let multibyte_mask = _mm_movemask_epi8(multibyte_test); @@ -132,8 +132,111 @@ cfg_select! { } } } + target_arch = "loongarch64" => { + fn analyze_source_file_dispatch( + src: &str, + lines: &mut Vec<RelativeBytePos>, + multi_byte_chars: &mut Vec<MultiByteChar>, + ) { + use std::arch::is_loongarch_feature_detected; + + if is_loongarch_feature_detected!("lsx") { + unsafe { + analyze_source_file_lsx(src, lines, multi_byte_chars); + } + } else { + analyze_source_file_generic( + src, + src.len(), + RelativeBytePos::from_u32(0), + lines, + multi_byte_chars, + ); + } + } + + /// Checks 16 byte chunks of text at a time. If the chunk contains + /// something other than printable ASCII characters and newlines, the + /// function falls back to the generic implementation. Otherwise it uses + /// LSX intrinsics to quickly find all newlines. + #[target_feature(enable = "lsx")] + unsafe fn analyze_source_file_lsx( + src: &str, + lines: &mut Vec<RelativeBytePos>, + multi_byte_chars: &mut Vec<MultiByteChar>, + ) { + use std::arch::loongarch64::*; + + const CHUNK_SIZE: usize = 16; + + let (chunks, tail) = src.as_bytes().as_chunks::<CHUNK_SIZE>(); + + // This variable keeps track of where we should start decoding a + // chunk. If a multi-byte character spans across chunk boundaries, + // we need to skip that part in the next chunk because we already + // handled it. + let mut intra_chunk_offset = 0; + + for (chunk_index, chunk) in chunks.iter().enumerate() { + // All LSX memory instructions support unaligned access, so using + // vld is fine. + let chunk = unsafe { lsx_vld::<0>(chunk.as_ptr() as *const i8) }; + + // For each character in the chunk, see if its byte value is < 0, + // which indicates that it's part of a UTF-8 char. + let multibyte_mask = lsx_vmskltz_b(chunk); + // Create a bit mask from the comparison results. + let multibyte_mask = lsx_vpickve2gr_w::<0>(multibyte_mask); + + // If the bit mask is all zero, we only have ASCII chars here: + if multibyte_mask == 0 { + assert!(intra_chunk_offset == 0); + + // Check for newlines in the chunk + let newlines_test = lsx_vseqi_b::<{b'\n' as i32}>(chunk); + let newlines_mask = lsx_vmskltz_b(newlines_test); + let mut newlines_mask = lsx_vpickve2gr_w::<0>(newlines_mask); + + let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1); + + while newlines_mask != 0 { + let index = newlines_mask.trailing_zeros(); + + lines.push(RelativeBytePos(index) + output_offset); + + // Clear the bit, so we can find the next one. + newlines_mask &= newlines_mask - 1; + } + } else { + // The slow path. + // There are multibyte chars in here, fallback to generic decoding. + let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset; + intra_chunk_offset = analyze_source_file_generic( + &src[scan_start..], + CHUNK_SIZE - intra_chunk_offset, + RelativeBytePos::from_usize(scan_start), + lines, + multi_byte_chars, + ); + } + } + + // There might still be a tail left to analyze + let tail_start = src.len() - tail.len() + intra_chunk_offset; + if tail_start < src.len() { + analyze_source_file_generic( + &src[tail_start..], + src.len() - tail_start, + RelativeBytePos::from_usize(tail_start), + lines, + multi_byte_chars, + ); + } + } + } _ => { - // The target (or compiler version) does not support SSE2 ... + // The target (or compiler version) does not support vector instructions + // our specialized implementations need (x86 SSE2, loongarch64 LSX)... fn analyze_source_file_dispatch( src: &str, lines: &mut Vec<RelativeBytePos>, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index e95b743b1ce..ededbea57e9 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -17,7 +17,7 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(round_char_boundary))] +#![cfg_attr(target_arch = "loongarch64", feature(stdarch_loongarch))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4fef65f46b1..b34a64108e3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -545,6 +545,7 @@ symbols! { attributes, audit_that, augmented_assignments, + auto_cfg, auto_traits, autodiff, autodiff_forward, @@ -628,7 +629,6 @@ symbols! { cfg_emscripten_wasm_eh, cfg_eval, cfg_fmt_debug, - cfg_hide, cfg_overflow_checks, cfg_panic, cfg_relocation_model, @@ -679,6 +679,7 @@ symbols! { cmpxchg16b_target_feature, cmse_nonsecure_entry, coerce_pointee_validated, + coerce_shared, coerce_unsized, cold, cold_path, @@ -794,6 +795,7 @@ symbols! { ctlz, ctlz_nonzero, ctpop, + ctr, cttz, cttz_nonzero, custom_attribute, @@ -938,6 +940,7 @@ symbols! { ermsb_target_feature, exact_div, except, + exception_handling: "exception-handling", exchange_malloc, exclusive_range_pattern, exhaustive_integer_patterns, @@ -1148,6 +1151,7 @@ symbols! { hashset_iter_ty, hexagon_target_feature, hidden, + hide, hint, homogeneous_aggregate, host, @@ -1195,6 +1199,7 @@ symbols! { if_let_rescope, if_while_or_patterns, ignore, + immediate_abort: "immediate-abort", impl_header_lifetime_elision, impl_lint_pass, impl_trait_in_assoc_type, @@ -1333,6 +1338,7 @@ symbols! { loongarch_target_feature, loop_break_value, loop_match, + lr, lt, m68k_target_feature, macro_at_most_once_rep, @@ -1940,6 +1946,7 @@ symbols! { rustc_regions, rustc_reservation_impl, rustc_serialize, + rustc_simd_monomorphize_lane_limit, rustc_skip_during_method_dispatch, rustc_specialization_trait, rustc_std_internal_symbol, @@ -1983,6 +1990,7 @@ symbols! { shl_assign, shorter_tail_lifetimes, should_panic, + show, shr, shr_assign, sig_dfl, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 9fa7e2f1003..aeac40a65bd 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -262,15 +262,16 @@ impl<'tcx> V0SymbolMangler<'tcx> { fn print_pat(&mut self, pat: ty::Pattern<'tcx>) -> Result<(), std::fmt::Error> { Ok(match *pat { ty::PatternKind::Range { start, end } => { - let consts = [start, end]; - for ct in consts { - Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct).print(self)?; - } + self.push("R"); + self.print_const(start)?; + self.print_const(end)?; } ty::PatternKind::Or(patterns) => { + self.push("O"); for pat in patterns { self.print_pat(pat)?; } + self.push("E"); } }) } @@ -412,7 +413,10 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { // Bound lifetimes use indices starting at 1, // see `BinderLevel` for more details. - ty::ReBound(debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }) => { + ty::ReBound( + ty::BoundVarIndexKind::Bound(debruijn), + ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }, + ) => { let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; let depth = binder.lifetime_depths.start + var.as_u32(); @@ -498,12 +502,9 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { } ty::Pat(ty, pat) => { - // HACK: Represent as tuple until we have something better. - // HACK: constants are used in arrays, even if the types don't match. - self.push("T"); + self.push("W"); ty.print(self)?; self.print_pat(pat)?; - self.push("E"); } ty::Array(ty, len) => { diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index e06f881e4b1..0601613567e 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -1260,11 +1260,12 @@ impl InlineAsmClobberAbi { v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - // cr0-cr1, cr5-cr7, xer + // cr0-cr1, cr5-cr7, ctr, lr, xer cr0, cr1, cr5, cr6, cr7, + ctr, + lr, xer, - // lr and ctr are reserved } }, InlineAsmClobberAbi::S390x => clobbered_regs! { diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index f3934afa6d9..2348a0fd202 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -13,6 +13,8 @@ def_reg_class! { freg, vreg, cr, + ctr, + lr, xer, } } @@ -56,7 +58,7 @@ impl PowerPCInlineAsmRegClass { altivec: VecI8(16), VecI16(8), VecI32(4), VecF32(4); vsx: F32, F64, VecI64(2), VecF64(2); }, - Self::cr | Self::xer => &[], + Self::cr | Self::ctr | Self::lr | Self::xer => &[], } } } @@ -195,6 +197,8 @@ def_regs! { cr5: cr = ["cr5"], cr6: cr = ["cr6"], cr7: cr = ["cr7"], + ctr: ctr = ["ctr"], + lr: lr = ["lr"], xer: xer = ["xer"], #error = ["r1", "1", "sp"] => "the stack pointer cannot be used as an operand for inline asm", @@ -206,10 +210,6 @@ def_regs! { "r30 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["r31", "31", "fp"] => "the frame pointer cannot be used as an operand for inline asm", - #error = ["lr"] => - "the link register cannot be used as an operand for inline asm", - #error = ["ctr"] => - "the counter register cannot be used as an operand for inline asm", #error = ["vrsave"] => "the vrsave register cannot be used as an operand for inline asm", } @@ -247,6 +247,8 @@ impl PowerPCInlineAsmReg { (v24, "24"), (v25, "25"), (v26, "26"), (v27, "27"), (v28, "28"), (v29, "29"), (v30, "30"), (v31, "31"); (cr, "cr"); (cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7"); + (ctr, "ctr"); + (lr, "lr"); (xer, "xer"); } } diff --git a/compiler/rustc_target/src/callconv/arm.rs b/compiler/rustc_target/src/callconv/arm.rs index 70830fa07b6..abc9a404e2e 100644 --- a/compiler/rustc_target/src/callconv/arm.rs +++ b/compiler/rustc_target/src/callconv/arm.rs @@ -77,7 +77,7 @@ where } } - let align = arg.layout.align.abi.bytes(); + let align = arg.layout.align.bytes(); let total = arg.layout.size; arg.cast_to(Uniform::consecutive(if align <= 4 { Reg::i32() } else { Reg::i64() }, total)); } diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 9213d73e24e..bc3c9601fa3 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -322,7 +322,7 @@ fn classify_arg<'a, Ty, C>( } let total = arg.layout.size; - let align = arg.layout.align.abi.bits(); + let align = arg.layout.align.bits(); // "Scalars wider than 2✕XLEN are passed by reference and are replaced in // the argument list with the address." diff --git a/compiler/rustc_target/src/callconv/mips.rs b/compiler/rustc_target/src/callconv/mips.rs index 48a01da865b..8ffd7bd1778 100644 --- a/compiler/rustc_target/src/callconv/mips.rs +++ b/compiler/rustc_target/src/callconv/mips.rs @@ -24,7 +24,7 @@ where } let dl = cx.data_layout(); let size = arg.layout.size; - let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align).abi; + let align = arg.layout.align.abi.max(dl.i32_align).min(dl.i64_align); if arg.layout.is_aggregate() { let pad_i32 = !offset.is_aligned(align); diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index 0209838bec1..8386a15933c 100644 --- a/compiler/rustc_target/src/callconv/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs @@ -110,9 +110,9 @@ where // We only care about aligned doubles if let BackendRepr::Scalar(scalar) = field.backend_repr { if scalar.primitive() == Primitive::Float(Float::F64) { - if offset.is_aligned(dl.f64_align.abi) { + if offset.is_aligned(dl.f64_align) { // Insert enough integers to cover [last_offset, offset) - assert!(last_offset.is_aligned(dl.f64_align.abi)); + assert!(last_offset.is_aligned(dl.f64_align)); for _ in 0..((offset - last_offset).bits() / 64) .min((prefix.len() - prefix_index) as u64) { diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 7a7c63c475b..c59af581a1f 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -332,7 +332,7 @@ impl CastTarget { self.prefix .iter() .filter_map(|x| x.map(|reg| reg.align(cx))) - .fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| { + .fold(cx.data_layout().aggregate_align.max(self.rest.align(cx)), |acc, align| { acc.max(align) }) } diff --git a/compiler/rustc_target/src/callconv/nvptx64.rs b/compiler/rustc_target/src/callconv/nvptx64.rs index 44977de7fcb..dc32dd87a7e 100644 --- a/compiler/rustc_target/src/callconv/nvptx64.rs +++ b/compiler/rustc_target/src/callconv/nvptx64.rs @@ -21,7 +21,7 @@ fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) { /// the pass mode used for aggregates in arg and ret position fn classify_aggregate<Ty>(arg: &mut ArgAbi<'_, Ty>) { - let align_bytes = arg.layout.align.abi.bytes(); + let align_bytes = arg.layout.align.bytes(); let size = arg.layout.size; let reg = match align_bytes { @@ -60,7 +60,7 @@ where // "`extern \"ptx-kernel\"` doesn't allow passing types other than primitives and structs" // ); - let align_bytes = arg.layout.align.abi.bytes(); + let align_bytes = arg.layout.align.bytes(); let unit = match align_bytes { 1 => Reg::i8(), diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs index 89ec85e4b66..be1d13816ef 100644 --- a/compiler/rustc_target/src/callconv/powerpc64.rs +++ b/compiler/rustc_target/src/callconv/powerpc64.rs @@ -89,7 +89,7 @@ where // Aggregates larger than i64 should be padded at the tail to fill out a whole number // of i64s or i128s, depending on the aggregate alignment. Always use an array for // this, even if there is only a single element. - let reg = if arg.layout.align.abi.bytes() > 8 { Reg::i128() } else { Reg::i64() }; + let reg = if arg.layout.align.bytes() > 8 { Reg::i128() } else { Reg::i64() }; arg.cast_to(Uniform::consecutive( reg, size.align_to(Align::from_bytes(reg.size.bytes()).unwrap()), diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index 161e2c1645f..16de3fe070d 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -328,7 +328,7 @@ fn classify_arg<'a, Ty, C>( } let total = arg.layout.size; - let align = arg.layout.align.abi.bits(); + let align = arg.layout.align.bits(); // "Scalars wider than 2✕XLEN are passed by reference and are replaced in // the argument list with the address." diff --git a/compiler/rustc_target/src/callconv/sparc.rs b/compiler/rustc_target/src/callconv/sparc.rs index 48a01da865b..8ffd7bd1778 100644 --- a/compiler/rustc_target/src/callconv/sparc.rs +++ b/compiler/rustc_target/src/callconv/sparc.rs @@ -24,7 +24,7 @@ where } let dl = cx.data_layout(); let size = arg.layout.size; - let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align).abi; + let align = arg.layout.align.abi.max(dl.i32_align).min(dl.i64_align); if arg.layout.is_aggregate() { let pad_i32 = !offset.is_aligned(align); diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index ecc9067ced3..62c8ed1dc21 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -29,7 +29,7 @@ where data.has_float = true; - if !data.last_offset.is_aligned(dl.f64_align.abi) && data.last_offset < offset { + if !data.last_offset.is_aligned(dl.f64_align) && data.last_offset < offset { if data.prefix_index == data.prefix.len() { return data; } diff --git a/compiler/rustc_target/src/callconv/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs index a73a70a1a0c..561ee98787d 100644 --- a/compiler/rustc_target/src/callconv/xtensa.rs +++ b/compiler/rustc_target/src/callconv/xtensa.rs @@ -48,7 +48,7 @@ where } let size = arg.layout.size.bits(); - let needed_align = arg.layout.align.abi.bits(); + let needed_align = arg.layout.align.bits(); let mut must_use_stack = false; // Determine the number of GPRs needed to pass the current argument diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index ecc74264160..39e604bcce7 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -158,12 +158,22 @@ pub(crate) fn base( SplitDebuginfo::Off, ]), + // Tell the linker that we would like it to avoid irreproducible binaries. + // // This environment variable is pretty magical but is intended for // producing deterministic builds. This was first discovered to be used // by the `ar` tool as a way to control whether or not mtime entries in - // the archive headers were set to zero or not. It appears that - // eventually the linker got updated to do the same thing and now reads - // this environment variable too in recent versions. + // the archive headers were set to zero or not. + // + // In `ld64-351.8`, shipped with Xcode 9.3, the linker was updated to + // read this flag too. Linker versions that don't support this flag + // may embed modification timestamps in binaries (especially in debug + // information). + // + // A cleaner alternative would be to pass the `-reproducible` flag, + // though that is only supported since `ld64-819.6` shipped with Xcode + // 14, which is too new for our minimum supported version: + // https://doc.rust-lang.org/rustc/platform-support/apple-darwin.html#host-tooling // // For some more info see the commentary on #47086 link_env: Cow::Borrowed(&[(Cow::Borrowed("ZERO_AR_DATE"), Cow::Borrowed("1"))]), diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs index be15da7329d..6ab8597a4ec 100644 --- a/compiler/rustc_target/src/spec/base/mod.rs +++ b/compiler/rustc_target/src/spec/base/mod.rs @@ -21,6 +21,7 @@ pub(crate) mod linux_uclibc; pub(crate) mod linux_wasm; pub(crate) mod lynxos178; pub(crate) mod managarm_mlibc; +pub(crate) mod motor; pub(crate) mod msvc; pub(crate) mod netbsd; pub(crate) mod nto_qnx; diff --git a/compiler/rustc_target/src/spec/base/motor.rs b/compiler/rustc_target/src/spec/base/motor.rs new file mode 100644 index 00000000000..18485b2cef2 --- /dev/null +++ b/compiler/rustc_target/src/spec/base/motor.rs @@ -0,0 +1,34 @@ +use crate::spec::{ + Cc, FramePointer, LinkerFlavor, Lld, PanicStrategy, StackProbeType, TargetOptions, +}; + +pub(crate) fn opts() -> TargetOptions { + let pre_link_args = TargetOptions::link_args( + LinkerFlavor::Gnu(Cc::No, Lld::No), + &[ + "-e", + "motor_start", + "--no-undefined", + "--error-unresolved-symbols", + "--no-undefined-version", + "-u", + "__rust_abort", + ], + ); + TargetOptions { + os: "motor".into(), + executables: true, + // TLS is false below because if true, the compiler assumes + // we handle TLS at the ELF loading level, which we don't. + // We use "OS level" TLS (see thread/local.rs in stdlib). + has_thread_local: false, + frame_pointer: FramePointer::NonLeaf, + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::No), + main_needs_argc_argv: true, + panic_strategy: PanicStrategy::Abort, + pre_link_args, + stack_probes: StackProbeType::Inline, + supports_stack_protector: true, + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/base/wasm.rs b/compiler/rustc_target/src/spec/base/wasm.rs index 88e7af5e669..7ede45766ea 100644 --- a/compiler/rustc_target/src/spec/base/wasm.rs +++ b/compiler/rustc_target/src/spec/base/wasm.rs @@ -81,11 +81,6 @@ pub(crate) fn options() -> TargetOptions { // threaded model which will legalize atomics to normal operations. singlethread: true, - // Symbol visibility takes care of this for the WebAssembly. - // Additionally the only known linker, LLD, doesn't support the script - // arguments just yet - limit_rdylib_exports: false, - // we use the LLD shipped with the Rust toolchain by default linker: Some("rust-lld".into()), linker_flavor: LinkerFlavor::WasmLld(Cc::No), diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs index 4ba11021988..2867428e42f 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnu.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs @@ -93,10 +93,7 @@ pub(crate) fn opts() -> TargetOptions { binary_format: BinaryFormat::Coff, allows_weak_linkage: false, pre_link_args, - pre_link_objects: crt_objects::pre_mingw(), - post_link_objects: crt_objects::post_mingw(), pre_link_objects_self_contained: crt_objects::pre_mingw_self_contained(), - post_link_objects_self_contained: crt_objects::post_mingw_self_contained(), link_self_contained: LinkSelfContainedDefault::InferredForMingw, late_link_args, late_link_args_dynamic, diff --git a/compiler/rustc_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs index e3b6430a463..2d84e78f255 100644 --- a/compiler/rustc_target/src/spec/crt_objects.rs +++ b/compiler/rustc_target/src/spec/crt_objects.rs @@ -86,6 +86,17 @@ pub(super) fn post_musl_self_contained() -> CrtObjects { pub(super) fn pre_mingw_self_contained() -> CrtObjects { new(&[ + (LinkOutputKind::DynamicNoPicExe, &["crt2.o"]), + (LinkOutputKind::DynamicPicExe, &["crt2.o"]), + (LinkOutputKind::StaticNoPicExe, &["crt2.o"]), + (LinkOutputKind::StaticPicExe, &["crt2.o"]), + (LinkOutputKind::DynamicDylib, &["dllcrt2.o"]), + (LinkOutputKind::StaticDylib, &["dllcrt2.o"]), + ]) +} + +pub(super) fn pre_i686_mingw_self_contained() -> CrtObjects { + new(&[ (LinkOutputKind::DynamicNoPicExe, &["crt2.o", "rsbegin.o"]), (LinkOutputKind::DynamicPicExe, &["crt2.o", "rsbegin.o"]), (LinkOutputKind::StaticNoPicExe, &["crt2.o", "rsbegin.o"]), @@ -95,15 +106,15 @@ pub(super) fn pre_mingw_self_contained() -> CrtObjects { ]) } -pub(super) fn post_mingw_self_contained() -> CrtObjects { +pub(super) fn post_i686_mingw_self_contained() -> CrtObjects { all("rsend.o") } -pub(super) fn pre_mingw() -> CrtObjects { +pub(super) fn pre_i686_mingw() -> CrtObjects { all("rsbegin.o") } -pub(super) fn post_mingw() -> CrtObjects { +pub(super) fn post_i686_mingw() -> CrtObjects { all("rsend.o") } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f705af52bd8..4a82a8bd888 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -834,6 +834,7 @@ crate::target_spec_enum! { pub enum PanicStrategy { Unwind = "unwind", Abort = "abort", + ImmediateAbort = "immediate-abort", } parse_error_type = "panic strategy"; @@ -852,8 +853,13 @@ impl PanicStrategy { match *self { PanicStrategy::Unwind => sym::unwind, PanicStrategy::Abort => sym::abort, + PanicStrategy::ImmediateAbort => sym::immediate_abort, } } + + pub fn unwinds(self) -> bool { + matches!(self, PanicStrategy::Unwind) + } } crate::target_spec_enum! { @@ -1642,6 +1648,7 @@ supported_targets! { ("aarch64-unknown-hermit", aarch64_unknown_hermit), ("riscv64gc-unknown-hermit", riscv64gc_unknown_hermit), ("x86_64-unknown-hermit", x86_64_unknown_hermit), + ("x86_64-unknown-motor", x86_64_unknown_motor), ("x86_64-unikraft-linux-musl", x86_64_unikraft_linux_musl), diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs index d227d63c4a3..0ae7cd7a377 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs @@ -12,7 +12,7 @@ pub(crate) fn target() -> Target { llvm_target: "armebv7r-none-eabi".into(), metadata: TargetMetadata { description: Some("Bare Armv7-R, Big Endian".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs index c373afb914e..71ffd8baed5 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs @@ -12,7 +12,7 @@ pub(crate) fn target() -> Target { llvm_target: "armebv7r-none-eabihf".into(), metadata: TargetMetadata { description: Some("Bare Armv7-R, Big Endian, hardfloat".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs index e78f7839974..06dd2629775 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs @@ -34,7 +34,7 @@ pub(crate) fn target() -> Target { description: Some("ARMv7-A Cortex-A9 VEX V5 Brain".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs index e775c8fc524..a0d403bd05e 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs @@ -1,4 +1,6 @@ -use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base}; +use crate::spec::{ + Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base, crt_objects, +}; pub(crate) fn target() -> Target { let mut base = base::windows_gnu::opts(); @@ -15,6 +17,10 @@ pub(crate) fn target() -> Target { &["-m", "i386pe", "--large-address-aware"], ); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Wl,--large-address-aware"]); + base.pre_link_objects = crt_objects::pre_i686_mingw(); + base.post_link_objects = crt_objects::post_i686_mingw(); + base.pre_link_objects_self_contained = crt_objects::pre_i686_mingw_self_contained(); + base.post_link_objects_self_contained = crt_objects::post_i686_mingw_self_contained(); Target { llvm_target: "i686-pc-windows-gnu".into(), diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs index d42e097b0fd..38c3c7dfaa1 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs @@ -5,8 +5,6 @@ pub(crate) fn target() -> Target { base.cpu = "mips64r2".into(); base.features = "+mips64r2,+xgot".into(); base.max_atomic_width = Some(64); - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - base.crt_static_default = true; Target { // LLVM doesn't recognize "muslabi64" yet. llvm_target: "mips64el-unknown-linux-musl".into(), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs index a0eb4a254fc..06e5cfaed92 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs @@ -6,11 +6,18 @@ use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base}; pub(crate) fn target() -> Target { let mut options = base::linux_wasm::opts(); - options - .add_pre_link_args(LinkerFlavor::WasmLld(Cc::No), &["--export-memory", "--shared-memory"]); + options.add_pre_link_args( + LinkerFlavor::WasmLld(Cc::No), + &["--export-memory", "--shared-memory", "--max-memory=1073741824"], + ); options.add_pre_link_args( LinkerFlavor::WasmLld(Cc::Yes), - &["--target=wasm32-wasi-threads", "-Wl,--export-memory,", "-Wl,--shared-memory"], + &[ + "--target=wasm32-wasi-threads", + "-Wl,--export-memory,", + "-Wl,--shared-memory", + "-Wl,--max-memory=1073741824", + ], ); Target { diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs index 44d906a507d..c735c72cb1c 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { options.add_pre_link_args( LinkerFlavor::WasmLld(Cc::No), - &["--import-memory", "--export-memory", "--shared-memory"], + &["--import-memory", "--export-memory", "--shared-memory", "--max-memory=1073741824"], ); options.add_pre_link_args( LinkerFlavor::WasmLld(Cc::Yes), @@ -28,6 +28,7 @@ pub(crate) fn target() -> Target { "-Wl,--import-memory", "-Wl,--export-memory,", "-Wl,--shared-memory", + "-Wl,--max-memory=1073741824", ], ); diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_motor.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_motor.rs new file mode 100644 index 00000000000..0fd43357a76 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_motor.rs @@ -0,0 +1,38 @@ +use crate::spec::{ + CodeModel, LinkSelfContainedDefault, LldFlavor, RelocModel, RelroLevel, Target, base, +}; + +pub(crate) fn target() -> Target { + let mut base = base::motor::opts(); + base.cpu = "x86-64".into(); + base.max_atomic_width = Some(64); + base.code_model = Some(CodeModel::Small); + + // We want fully static relocatable binaries. It was surprisingly + // difficult to make it happen reliably, especially various + // linker-related options below. Mostly trial and error. + base.position_independent_executables = true; + base.relro_level = RelroLevel::Full; + base.static_position_independent_executables = true; + base.relocation_model = RelocModel::Pic; + base.lld_flavor_json = LldFlavor::Ld; + base.link_self_contained = LinkSelfContainedDefault::True; + base.dynamic_linking = false; + base.crt_static_default = true; + base.crt_static_respected = true; + + Target { + llvm_target: "x86_64-unknown-none-elf".into(), + metadata: crate::spec::TargetMetadata { + description: Some("Motor OS".into()), + tier: Some(3), + host_tools: None, + std: None, + }, + pointer_width: 64, + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), + arch: "x86_64".into(), + options: base, + } +} diff --git a/compiler/rustc_thread_pool/src/latch.rs b/compiler/rustc_thread_pool/src/latch.rs index 18d654d9f78..58dabaf35c0 100644 --- a/compiler/rustc_thread_pool/src/latch.rs +++ b/compiler/rustc_thread_pool/src/latch.rs @@ -388,13 +388,17 @@ impl Latch for CountLatch { #[inline] unsafe fn set(this: *const Self) { if unsafe { (*this).counter.fetch_sub(1, Ordering::SeqCst) == 1 } { - // NOTE: Once we call `set` on the internal `latch`, + // SAFETY: Once we call `set` on the internal `latch`, // the target may proceed and invalidate `this`! match unsafe { &(*this).kind } { CountLatchKind::Stealing { latch, registry, worker_index } => { let registry = Arc::clone(registry); + let worker_index = *worker_index; + // SAFETY: We don't use any references from `this` after this call. if unsafe { CoreLatch::set(latch) } { - registry.notify_worker_latch_is_set(*worker_index); + // We **must not** access any part of `this` anymore, which + // is why we read and shadowed these fields beforehand. + registry.notify_worker_latch_is_set(worker_index); } } CountLatchKind::Blocking { latch } => unsafe { LockLatch::set(latch) }, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 149f5e638b1..bec12750728 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1305,8 +1305,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { if ty.is_structural_eq_shallow(self.tcx) { diag.span_suggestion( - span, - "add `#[derive(ConstParamTy)]` to the struct", + span.shrink_to_lo(), + format!("add `#[derive(ConstParamTy)]` to the {}", def.descr()), "#[derive(ConstParamTy)]\n", Applicability::MachineApplicable, ); @@ -1314,8 +1314,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // FIXME(adt_const_params): We should check there's not already an // overlapping `Eq`/`PartialEq` impl. diag.span_suggestion( - span, - "add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct", + span.shrink_to_lo(), + format!( + "add `#[derive(ConstParamTy, PartialEq, Eq)]` to the {}", + def.descr() + ), "#[derive(ConstParamTy, PartialEq, Eq)]\n", Applicability::MachineApplicable, ); @@ -1894,6 +1897,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { other: bool, param_env: ty::ParamEnv<'tcx>, ) -> bool { + let parent_map = self.tcx.visible_parent_map(()); let alternative_candidates = |def_id: DefId| { let mut impl_candidates: Vec<_> = self .tcx @@ -1918,7 +1922,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // FIXME(compiler-errors): This could be generalized, both to // be more granular, and probably look past other `#[fundamental]` // types, too. - self.tcx.visibility(def.did()).is_accessible_from(body_def_id, self.tcx) + let mut did = def.did(); + if self.tcx.visibility(did).is_accessible_from(body_def_id, self.tcx) { + // don't suggest foreign `#[doc(hidden)]` types + if !did.is_local() { + while let Some(parent) = parent_map.get(&did) { + if self.tcx.is_doc_hidden(did) { + return false; + } + did = *parent; + } + } + true + } else { + false + } } else { true } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index b3d1b8e3888..9052031ce4f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -21,7 +21,7 @@ use rustc_infer::traits::{ }; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::{ErrorGuaranteed, ExpnKind, Span}; +use rustc_span::{DesugaringKind, ErrorGuaranteed, ExpnKind, Span}; use tracing::{info, instrument}; pub use self::overflow::*; @@ -154,9 +154,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) .collect(); - // Ensure `T: Sized`, `T: MetaSized`, `T: PointeeSized` and `T: WF` obligations come last. + // Ensure `T: Sized`, `T: MetaSized`, `T: PointeeSized` and `T: WF` obligations come last, + // and `Subtype` obligations from `FormatLiteral` desugarings come first. // This lets us display diagnostics with more relevant type information and hide redundant // E0282 errors. + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] + enum ErrorSortKey { + SubtypeFormat(usize, usize), + OtherKind, + SizedTrait, + MetaSizedTrait, + PointeeSizedTrait, + Coerce, + WellFormed, + } errors.sort_by_key(|e| { let maybe_sizedness_did = match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred.def_id()), @@ -165,12 +176,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; match e.obligation.predicate.kind().skip_binder() { - _ if maybe_sizedness_did == self.tcx.lang_items().sized_trait() => 1, - _ if maybe_sizedness_did == self.tcx.lang_items().meta_sized_trait() => 2, - _ if maybe_sizedness_did == self.tcx.lang_items().pointee_sized_trait() => 3, - ty::PredicateKind::Coerce(_) => 4, - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 5, - _ => 0, + ty::PredicateKind::Subtype(_) + if matches!( + e.obligation.cause.span.desugaring_kind(), + Some(DesugaringKind::FormatLiteral { .. }) + ) => + { + let (_, row, col, ..) = + self.tcx.sess.source_map().span_to_location_info(e.obligation.cause.span); + ErrorSortKey::SubtypeFormat(row, col) + } + _ if maybe_sizedness_did == self.tcx.lang_items().sized_trait() => { + ErrorSortKey::SizedTrait + } + _ if maybe_sizedness_did == self.tcx.lang_items().meta_sized_trait() => { + ErrorSortKey::MetaSizedTrait + } + _ if maybe_sizedness_did == self.tcx.lang_items().pointee_sized_trait() => { + ErrorSortKey::PointeeSizedTrait + } + ty::PredicateKind::Coerce(_) => ErrorSortKey::Coerce, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => { + ErrorSortKey::WellFormed + } + _ => ErrorSortKey::OtherKind, } }); diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 4c50c44b841..cd076d1cb69 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -9,7 +9,7 @@ use rustc_middle::infer::canonical::{ Canonical, CanonicalQueryInput, CanonicalQueryResponse, QueryResponse, }; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast}; +use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable, Upcast}; use rustc_span::DUMMY_SP; use tracing::instrument; @@ -31,19 +31,7 @@ impl<'tcx> InferCtxt<'tcx> { fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); - - // FIXME(#132279): This should be removed as it causes us to incorrectly - // handle opaques in their defining scope, and stalled coroutines. - if !self.next_trait_solver() && !(param_env, ty).has_infer() && !ty.has_coroutines() { - return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty); - } - let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, DUMMY_SP); - - // This can get called from typeck (by euv), and `moves_by_default` - // rightly refuses to work with inference variables, but - // moves_by_default has a cache, which we want to use in other - // cases. traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id) } diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 2b33b8ac9f8..debc4fda15a 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -77,6 +77,8 @@ impl<'tcx> InferCtxt<'tcx> { /// /// Prefer this method over `resolve_regions_with_normalize`, unless you are /// doing something specific for normalization. + /// + /// This function assumes that all infer variables are already constrained. fn resolve_regions( &self, body_id: LocalDefId, diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 3260dd712b9..6ab92531e4e 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -830,7 +830,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEscapingBoundRegions<'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - if let ty::ReBound(debruijn, _) = r.kind() + if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind() && debruijn < self.binder { r diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index ae731505abf..34e0176d213 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -1,6 +1,6 @@ use rustc_infer::traits::solve::Goal; use rustc_macros::extension; -use rustc_middle::span_bug; +use rustc_middle::{span_bug, ty}; use rustc_next_trait_solver::solve::SolverDelegateEvalExt; use crate::infer::InferCtxt; @@ -22,7 +22,7 @@ impl<'tcx> InferCtxt<'tcx> { /// for more details. fn predicate_may_hold_opaque_types_jank(&self, obligation: &PredicateObligation<'tcx>) -> bool { if self.next_trait_solver() { - <&SolverDelegate<'tcx>>::from(self).root_goal_may_hold_opaque_types_jank(Goal::new( + self.goal_may_hold_opaque_types_jank(Goal::new( self.tcx, obligation.param_env, obligation.predicate, @@ -32,6 +32,13 @@ impl<'tcx> InferCtxt<'tcx> { } } + /// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank) + /// for more details. + fn goal_may_hold_opaque_types_jank(&self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> bool { + assert!(self.next_trait_solver()); + <&SolverDelegate<'tcx>>::from(self).root_goal_may_hold_opaque_types_jank(goal) + } + /// Evaluates whether the predicate can be satisfied in the given /// `ParamEnv`, and returns `false` if not certain. However, this is /// not entirely accurate if inference variables are involved. diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index a54eb80fedc..c6eb0caee1a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -145,7 +145,9 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor { #[inline] fn visit_region(&mut self, r: ty::Region<'tcx>) { match r.kind() { - ty::ReBound(debruijn, _) if debruijn > self.outer_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) + if debruijn > self.outer_index => + { self.escaping = self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize()); } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 6ce68507d65..a96cb738b81 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -100,9 +100,9 @@ where } else if let Err(guar) = infcx.tcx.check_potentially_region_dependent_goals(root_def_id) { Err(guar) } else { - Err(infcx - .dcx() - .delayed_bug(format!("errors selecting obligation during MIR typeck: {errors:?}"))) + Err(infcx.dcx().delayed_bug(format!( + "errors selecting obligation during MIR typeck: {name} {root_def_id:?} {errors:?}" + ))) } })?; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 7540cbe3fd1..e55ffb4d5fd 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -55,6 +55,12 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( span: Span, disable_implied_bounds_hack: bool, ) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> { + // Inside mir borrowck, each computation starts with an empty list. + assert!( + ocx.infcx.inner.borrow().region_obligations().is_empty(), + "compute_implied_outlives_bounds assumes region obligations are empty before starting" + ); + let normalize_ty = |ty| -> Result<_, NoSolution> { // We must normalize the type so we can compute the right outlives components. // for example, if we have some constrained param type like `T: Trait<Out = U>`, @@ -143,7 +149,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( && ty.visit_with(&mut ContainsBevyParamSet { tcx: ocx.infcx.tcx }).is_break() { for TypeOutlivesConstraint { sup_type, sub_region, .. } in - ocx.infcx.take_registered_region_obligations() + ocx.infcx.clone_registered_region_obligations() { let mut components = smallvec![]; push_outlives_components(ocx.infcx.tcx, sup_type, &mut components); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 1dd31990ab7..fb4f28412d4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2359,7 +2359,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { if self.infcx.can_define_opaque_ty(def_id) { unreachable!() } else { - // We can resolve the `impl Trait` to its concrete type, + // We can resolve the opaque type to its hidden type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. match self.tcx().type_of_opaque(def_id) { diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index d7ea26a2ab1..7f626e8c4e8 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -279,6 +279,7 @@ pub(crate) mod rustc { LayoutError::Unknown(..) | LayoutError::ReferencesError(..) | LayoutError::TooGeneric(..) + | LayoutError::InvalidSimd { .. } | LayoutError::NormalizationFailure(..) => Self::UnknownLayout, LayoutError::SizeOverflow(..) => Self::SizeOverflow, LayoutError::Cycle(err) => Self::TypeError(*err), @@ -360,7 +361,7 @@ pub(crate) mod rustc { ty::Ref(region, ty, mutability) => { let layout = layout_of(cx, *ty)?; - let referent_align = layout.align.abi.bytes_usize(); + let referent_align = layout.align.bytes_usize(); let referent_size = layout.size.bytes_usize(); Ok(Tree::Ref(Reference { diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 0298e7e0e95..f92c405242c 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -79,19 +79,6 @@ pub(crate) struct UnexpectedFnPtrAssociatedItem { } #[derive(Diagnostic)] -#[diag(ty_utils_zero_length_simd_type)] -pub(crate) struct ZeroLengthSimdType<'tcx> { - pub ty: Ty<'tcx>, -} - -#[derive(Diagnostic)] -#[diag(ty_utils_oversized_simd_type)] -pub(crate) struct OversizedSimdType<'tcx> { - pub ty: Ty<'tcx>, - pub max_lanes: u64, -} - -#[derive(Diagnostic)] #[diag(ty_utils_non_primitive_simd_type)] pub(crate) struct NonPrimitiveSimdType<'tcx> { pub ty: Ty<'tcx>, diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index c4cb43011ad..317d101dafe 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -7,12 +7,14 @@ use rustc_abi::{ VariantIdx, Variants, WrappingRange, }; use rustc_hashes::Hash64; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use rustc_index::IndexVec; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::layout::{ - FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, + FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, SimdLayoutError, TyAndLayout, }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ @@ -23,7 +25,7 @@ use rustc_span::{Symbol, sym}; use tracing::{debug, instrument}; use {rustc_abi as abi, rustc_hir as hir}; -use crate::errors::{NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType}; +use crate::errors::NonPrimitiveSimdType; mod invariant; @@ -121,11 +123,11 @@ fn map_error<'tcx>( } LayoutCalculatorError::ZeroLengthSimdType => { // Can't be caught in typeck if the array length is generic. - cx.tcx().dcx().emit_fatal(ZeroLengthSimdType { ty }) + LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } } LayoutCalculatorError::OversizedSimdType { max_lanes } => { // Can't be caught in typeck if the array length is generic. - cx.tcx().dcx().emit_fatal(OversizedSimdType { ty, max_lanes }) + LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } } LayoutCalculatorError::NonPrimitiveSimdType(field) => { // This error isn't caught in typeck, e.g., if @@ -563,6 +565,22 @@ fn layout_of_uncached<'tcx>( let e_ly = cx.layout_of(e_ty)?; + // Check for the rustc_simd_monomorphize_lane_limit attribute and check the lane limit + if let Some(limit) = find_attr!( + tcx.get_all_attrs(def.did()), + AttributeKind::RustcSimdMonomorphizeLaneLimit(limit) => limit + ) { + if !limit.value_within_limit(e_len as usize) { + return Err(map_error( + &cx, + ty, + rustc_abi::LayoutCalculatorError::OversizedSimdType { + max_lanes: limit.0 as u64, + }, + )); + } + } + map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))? } @@ -777,7 +795,7 @@ fn variant_info_for_adt<'tcx>( name, offset: offset.bytes(), size: field_layout.size.bytes(), - align: field_layout.align.abi.bytes(), + align: field_layout.align.bytes(), type_name: None, } }) @@ -786,7 +804,7 @@ fn variant_info_for_adt<'tcx>( VariantInfo { name: n, kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact }, - align: layout.align.abi.bytes(), + align: layout.align.bytes(), size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() }, fields: field_info, } @@ -859,7 +877,7 @@ fn variant_info_for_coroutine<'tcx>( name: *name, offset: offset.bytes(), size: field_layout.size.bytes(), - align: field_layout.align.abi.bytes(), + align: field_layout.align.bytes(), type_name: None, } }) @@ -887,7 +905,7 @@ fn variant_info_for_coroutine<'tcx>( }), offset: offset.bytes(), size: field_layout.size.bytes(), - align: field_layout.align.abi.bytes(), + align: field_layout.align.bytes(), // Include the type name if there is no field name, or if the name is the // __awaitee placeholder symbol which means a child future being `.await`ed. type_name: (field_name.is_none() || field_name == Some(sym::__awaitee)) @@ -928,7 +946,7 @@ fn variant_info_for_coroutine<'tcx>( name: Some(Symbol::intern(&ty::CoroutineArgs::variant_name(variant_idx))), kind: SizeKind::Exact, size: variant_size.bytes(), - align: variant_layout.align.abi.bytes(), + align: variant_layout.align.bytes(), fields, } }) diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 1311ee31182..b768269215f 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, TyAndLayout}; pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { let tcx = cx.tcx(); - if !layout.size.bytes().is_multiple_of(layout.align.abi.bytes()) { + if !layout.size.bytes().is_multiple_of(layout.align.bytes()) { bug!("size is not a multiple of align, in the following layout:\n{layout:#?}"); } if layout.size.bytes() >= tcx.data_layout.obj_size_bound() { @@ -300,8 +300,8 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou if variant.align.abi > layout.align.abi { bug!( "Type with alignment {} bytes has variant with alignment {} bytes: {layout:#?}", - layout.align.abi.bytes(), - variant.align.abi.bytes(), + layout.align.bytes(), + variant.align.bytes(), ) } // Skip empty variants. diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index e91e5055e90..bb25a14ef74 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -235,7 +235,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { // bounds of the RPITIT. Shift these binders back out when // constructing the top-level projection predicate. let shifted_alias_ty = fold_regions(self.tcx, unshifted_alias_ty, |re, depth| { - if let ty::ReBound(index, bv) = re.kind() { + if let ty::ReBound(ty::BoundVarIndexKind::Bound(index), bv) = re.kind() { if depth != ty::INNERMOST { return ty::Region::new_error_with_message( self.tcx, diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 6591d3148cb..94b950357e1 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -4,6 +4,7 @@ use std::ops::{ControlFlow, Deref}; use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::instrument; use crate::data_structures::SsoHashSet; @@ -11,7 +12,7 @@ use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldabl use crate::inherent::*; use crate::lift::Lift; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use crate::{self as ty, Interner}; +use crate::{self as ty, DebruijnIndex, Interner}; /// `Binder` is a binder for higher-ranked lifetimes or types. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` @@ -299,7 +300,9 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> { return ControlFlow::Break(()); } match t.kind() { - ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { + ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty) + if debruijn == self.binder_index => + { let idx = bound_ty.var().as_usize(); if self.bound_vars.len() <= idx { panic!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars); @@ -317,7 +320,9 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> { return ControlFlow::Break(()); } match c.kind() { - ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.binder_index => { + ty::ConstKind::Bound(debruijn, bound_const) + if debruijn == ty::BoundVarIndexKind::Bound(self.binder_index) => + { let idx = bound_const.var().as_usize(); if self.bound_vars.len() <= idx { panic!("Not enough bound vars: {:?} not found in {:?}", c, self.bound_vars); @@ -332,7 +337,7 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> { fn visit_region(&mut self, r: I::Region) -> Self::Result { match r.kind() { - ty::ReBound(index, br) if index == self.binder_index => { + ty::ReBound(index, br) if index == ty::BoundVarIndexKind::Bound(self.binder_index) => { let idx = br.var().as_usize(); if self.bound_vars.len() <= idx { panic!("Not enough bound vars: {:?} not found in {:?}", r, self.bound_vars); @@ -913,3 +918,33 @@ impl<'a, I: Interner> ArgFolder<'a, I> { } } } + +/// Okay, we do something fun for `Bound` types/regions/consts: +/// Specifically, we distinguish between *canonically* bound things and +/// `for<>` bound things. And, really, it comes down to caching during +/// canonicalization and instantiation. +/// +/// To understand why we do this, imagine we have a type `(T, for<> fn(T))`. +/// If we just tracked canonically bound types with a `DebruijnIndex` (as we +/// used to), then the canonicalized type would be something like +/// `for<0> (^0.0, for<> fn(^1.0))` and so we can't cache `T -> ^0.0`, +/// we have to also factor in binder level. (Of course, we don't cache that +/// exactly, but rather the entire enclosing type, but the point stands.) +/// +/// Of course, this is okay because we don't ever nest canonicalization, so +/// `BoundVarIndexKind::Canonical` is unambiguous. We, alternatively, could +/// have some sentinel `DebruijinIndex`, but that just seems too scary. +/// +/// This doesn't seem to have a huge perf swing either way, but in the next +/// solver, canonicalization is hot and there are some pathological cases where +/// this is needed (`post-mono-higher-ranked-hang`). +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +pub enum BoundVarIndexKind { + Bound(DebruijnIndex), + Canonical, +} diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index ecf3ae4f8b2..7b4b953b2cf 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -230,13 +230,13 @@ impl<I: Interner> CanonicalVarValues<I> { pub fn is_identity(&self) -> bool { self.var_values.iter().enumerate().all(|(bv, arg)| match arg.kind() { ty::GenericArgKind::Lifetime(r) => { - matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if br.var().as_usize() == bv) + matches!(r.kind(), ty::ReBound(ty::BoundVarIndexKind::Canonical, br) if br.var().as_usize() == bv) } ty::GenericArgKind::Type(ty) => { - matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var().as_usize() == bv) + matches!(ty.kind(), ty::Bound(ty::BoundVarIndexKind::Canonical, bt) if bt.var().as_usize() == bv) } ty::GenericArgKind::Const(ct) => { - matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.var().as_usize() == bv) + matches!(ct.kind(), ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bc) if bc.var().as_usize() == bv) } }) } @@ -246,21 +246,23 @@ impl<I: Interner> CanonicalVarValues<I> { for arg in self.var_values.iter() { match arg.kind() { ty::GenericArgKind::Lifetime(r) => { - if matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if var == br.var()) { + if matches!(r.kind(), ty::ReBound(ty::BoundVarIndexKind::Canonical, br) if var == br.var()) + { var = var + 1; } else { // It's ok if this region var isn't an identity variable } } ty::GenericArgKind::Type(ty) => { - if matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if var == bt.var()) { + if matches!(ty.kind(), ty::Bound(ty::BoundVarIndexKind::Canonical, bt) if var == bt.var()) + { var = var + 1; } else { return false; } } ty::GenericArgKind::Const(ct) => { - if matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if var == bc.var()) + if matches!(ct.kind(), ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bc) if var == bc.var()) { var = var + 1; } else { @@ -284,16 +286,13 @@ impl<I: Interner> CanonicalVarValues<I> { | CanonicalVarKind::Int | CanonicalVarKind::Float | CanonicalVarKind::PlaceholderTy(_) => { - Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) - .into() + Ty::new_canonical_bound(cx, ty::BoundVar::from_usize(i)).into() } CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { - Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) - .into() + Region::new_canonical_bound(cx, ty::BoundVar::from_usize(i)).into() } CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => { - Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) - .into() + Const::new_canonical_bound(cx, ty::BoundVar::from_usize(i)).into() } } }, diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 6de41b47bde..273b6096008 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -7,7 +7,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; -use crate::{self as ty, DebruijnIndex, Interner}; +use crate::{self as ty, BoundVarIndexKind, Interner}; /// Represents a constant in Rust. #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] @@ -23,7 +23,7 @@ pub enum ConstKind<I: Interner> { Infer(InferConst), /// Bound const variable, used only when preparing a trait query. - Bound(DebruijnIndex, I::BoundConst), + Bound(BoundVarIndexKind, I::BoundConst), /// A placeholder const - universally quantified higher-ranked const. Placeholder(I::PlaceholderConst), diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 24704c5bb53..34b030ee768 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -133,6 +133,9 @@ bitflags::bitflags! { /// Does this type have any coroutines in it? const HAS_TY_CORO = 1 << 24; + + /// Does this have have a `Bound(BoundVarIndexKind::Canonical, _)`? + const HAS_CANONICAL_BOUND = 1 << 25; } } @@ -254,7 +257,12 @@ impl<I: Interner> FlagComputation<I> { self.add_args(args.as_slice()); } - ty::Bound(debruijn, _) => { + ty::Bound(ty::BoundVarIndexKind::Canonical, _) => { + self.add_flags(TypeFlags::HAS_TY_BOUND); + self.add_flags(TypeFlags::HAS_CANONICAL_BOUND); + } + + ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _) => { self.add_bound_var(debruijn); self.add_flags(TypeFlags::HAS_TY_BOUND); } @@ -347,6 +355,7 @@ impl<I: Interner> FlagComputation<I> { fn add_ty_pat(&mut self, pat: <I as Interner>::Pat) { self.add_flags(pat.flags()); + self.add_exclusive_binder(pat.outer_exclusive_binder()); } fn add_predicate(&mut self, binder: ty::Binder<I, ty::PredicateKind<I>>) { @@ -434,7 +443,7 @@ impl<I: Interner> FlagComputation<I> { fn add_region(&mut self, r: I::Region) { self.add_flags(r.flags()); - if let ty::ReBound(debruijn, _) = r.kind() { + if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind() { self.add_bound_var(debruijn); } } @@ -454,10 +463,14 @@ impl<I: Interner> FlagComputation<I> { ty::InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH), ty::InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER), }, - ty::ConstKind::Bound(debruijn, _) => { + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), _) => { self.add_bound_var(debruijn); self.add_flags(TypeFlags::HAS_CT_BOUND); } + ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, _) => { + self.add_flags(TypeFlags::HAS_CT_BOUND); + self.add_flags(TypeFlags::HAS_CANONICAL_BOUND); + } ty::ConstKind::Param(_) => { self.add_flags(TypeFlags::HAS_CT_PARAM); } diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index a5eb8699e5f..d1a50599e8b 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -55,7 +55,7 @@ use tracing::{debug, instrument}; use crate::inherent::*; use crate::visit::{TypeVisitable, TypeVisitableExt as _}; -use crate::{self as ty, Interner, TypeFlags}; +use crate::{self as ty, BoundVarIndexKind, Interner, TypeFlags}; /// This trait is implemented for every type that can be folded, /// providing the skeleton of the traversal. @@ -398,7 +398,9 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> { fn fold_region(&mut self, r: I::Region) -> I::Region { match r.kind() { - ty::ReBound(debruijn, br) if debruijn >= self.current_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) + if debruijn >= self.current_index => + { let debruijn = debruijn.shifted_in(self.amount); Region::new_bound(self.cx, debruijn, br) } @@ -408,7 +410,9 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> { fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { match ty.kind() { - ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { + ty::Bound(BoundVarIndexKind::Bound(debruijn), bound_ty) + if debruijn >= self.current_index => + { let debruijn = debruijn.shifted_in(self.amount); Ty::new_bound(self.cx, debruijn, bound_ty) } @@ -420,7 +424,9 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> { fn fold_const(&mut self, ct: I::Const) -> I::Const { match ct.kind() { - ty::ConstKind::Bound(debruijn, bound_ct) if debruijn >= self.current_index => { + ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ct) + if debruijn >= self.current_index => + { let debruijn = debruijn.shifted_in(self.amount); Const::new_bound(self.cx, debruijn, bound_ct) } @@ -435,7 +441,7 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> { pub fn shift_region<I: Interner>(cx: I, region: I::Region, amount: u32) -> I::Region { match region.kind() { - ty::ReBound(debruijn, br) if amount > 0 => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) if amount > 0 => { Region::new_bound(cx, debruijn.shifted_in(amount), br) } _ => region, @@ -515,7 +521,13 @@ where #[instrument(skip(self), level = "debug", ret)] fn fold_region(&mut self, r: I::Region) -> I::Region { match r.kind() { - ty::ReBound(debruijn, _) if debruijn < self.current_index => { + ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) + if debruijn < self.current_index => + { + debug!(?self.current_index, "skipped bound region"); + r + } + ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => { debug!(?self.current_index, "skipped bound region"); r } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index f743b84bce6..feafcee7bad 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -80,7 +80,7 @@ pub enum TypingMode<I: Interner> { /// the old solver as well. PostBorrowckAnalysis { defined_opaque_types: I::LocalDefIds }, /// After analysis, mostly during codegen and MIR optimizations, we're able to - /// reveal all opaque types. As the concrete type should *never* be observable + /// reveal all opaque types. As the hidden type should *never* be observable /// directly by the user, this should not be used by checks which may expose /// such details to the user. /// diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index b5b552dbaec..75ba0231d98 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -48,6 +48,8 @@ pub trait Ty<I: Interner<Ty = Self>>: fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; + fn new_canonical_bound(interner: I, var: ty::BoundVar) -> Self; + fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self; fn new_projection_from_args(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self { @@ -230,6 +232,8 @@ pub trait Region<I: Interner<Region = Self>>: fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; + fn new_canonical_bound(interner: I, var: ty::BoundVar) -> Self; + fn new_static(interner: I) -> Self; fn new_placeholder(interner: I, var: I::PlaceholderRegion) -> Self; @@ -260,6 +264,8 @@ pub trait Const<I: Interner<Const = Self>>: fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; + fn new_canonical_bound(interner: I, var: ty::BoundVar) -> Self; + fn new_placeholder(interner: I, param: I::PlaceholderConst) -> Self; fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>) -> Self; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index cf58aec14a6..886d1a78bcb 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -11,9 +11,7 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; use crate::relate::Relate; -use crate::solve::{ - CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, inspect, -}; +use crate::solve::{CanonicalInput, ExternalConstraintsData, QueryResult, inspect}; use crate::visit::{Flags, TypeVisitable}; use crate::{self as ty, CanonicalParamEnvCacheEntry, search_graph}; @@ -70,10 +68,10 @@ pub trait Interner: + Hash + Eq + TypeFoldable<Self> - + Deref<Target = PredefinedOpaquesData<Self>>; + + SliceLike<Item = (ty::OpaqueTypeKey<Self>, Self::Ty)>; fn mk_predefined_opaques_in_body( self, - data: PredefinedOpaquesData<Self>, + data: &[(ty::OpaqueTypeKey<Self>, Self::Ty)], ) -> Self::PredefinedOpaques; type LocalDefIds: Copy diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 61e0b67b163..c1e30196126 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -196,13 +196,20 @@ impl DebruijnIndex { pub fn debug_bound_var<T: std::fmt::Write>( fmt: &mut T, - debruijn: DebruijnIndex, + bound_index: BoundVarIndexKind, var: impl std::fmt::Debug, ) -> Result<(), std::fmt::Error> { - if debruijn == INNERMOST { - write!(fmt, "^{var:?}") - } else { - write!(fmt, "^{}_{:?}", debruijn.index(), var) + match bound_index { + BoundVarIndexKind::Bound(debruijn) => { + if debruijn == INNERMOST { + write!(fmt, "^{var:?}") + } else { + write!(fmt, "^{}_{:?}", debruijn.index(), var) + } + } + BoundVarIndexKind::Canonical => { + write!(fmt, "^c_{:?}", var) + } } } diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index 06048af0436..1e8585cf52c 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -7,7 +7,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use self::RegionKind::*; -use crate::{DebruijnIndex, Interner}; +use crate::{BoundVarIndexKind, Interner}; rustc_index::newtype_index! { /// A **region** **v**ariable **ID**. @@ -147,7 +147,7 @@ pub enum RegionKind<I: Interner> { /// Bound regions inside of types **must not** be erased, as they impact trait /// selection and the `TypeId` of that type. `for<'a> fn(&'a ())` and /// `fn(&'static ())` are different types and have to be treated as such. - ReBound(DebruijnIndex, I::BoundRegion), + ReBound(BoundVarIndexKind, I::BoundRegion), /// Late-bound function parameters are represented using a `ReBound`. When /// inside of a function, we convert these bound variables to placeholder diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 8f8f019510f..7aa58d096d5 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -86,14 +86,12 @@ pub trait Delegate: Sized { kind: PathKind, input: <Self::Cx as Cx>::Input, ) -> <Self::Cx as Cx>::Result; - fn is_initial_provisional_result( + fn is_initial_provisional_result(result: <Self::Cx as Cx>::Result) -> Option<PathKind>; + fn stack_overflow_result( cx: Self::Cx, - kind: PathKind, input: <Self::Cx as Cx>::Input, - result: <Self::Cx as Cx>::Result, - ) -> bool; - fn on_stack_overflow(cx: Self::Cx, input: <Self::Cx as Cx>::Input) -> <Self::Cx as Cx>::Result; - fn on_fixpoint_overflow( + ) -> <Self::Cx as Cx>::Result; + fn fixpoint_overflow_result( cx: Self::Cx, input: <Self::Cx as Cx>::Input, ) -> <Self::Cx as Cx>::Result; @@ -215,6 +213,27 @@ impl HeadUsages { let HeadUsages { inductive, unknown, coinductive, forced_ambiguity } = self; inductive == 0 && unknown == 0 && coinductive == 0 && forced_ambiguity == 0 } + + fn is_single(self, path_kind: PathKind) -> bool { + match path_kind { + PathKind::Inductive => matches!( + self, + HeadUsages { inductive: _, unknown: 0, coinductive: 0, forced_ambiguity: 0 }, + ), + PathKind::Unknown => matches!( + self, + HeadUsages { inductive: 0, unknown: _, coinductive: 0, forced_ambiguity: 0 }, + ), + PathKind::Coinductive => matches!( + self, + HeadUsages { inductive: 0, unknown: 0, coinductive: _, forced_ambiguity: 0 }, + ), + PathKind::ForcedAmbiguity => matches!( + self, + HeadUsages { inductive: 0, unknown: 0, coinductive: 0, forced_ambiguity: _ }, + ), + } + } } #[derive(Debug, Default)] @@ -869,7 +888,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { } debug!("encountered stack overflow"); - D::on_stack_overflow(cx, input) + D::stack_overflow_result(cx, input) } /// When reevaluating a goal with a changed provisional result, all provisional cache entry @@ -888,7 +907,29 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { !entries.is_empty() }); } +} +/// We need to rebase provisional cache entries when popping one of their cycle +/// heads from the stack. This may not necessarily mean that we've actually +/// reached a fixpoint for that cycle head, which impacts the way we rebase +/// provisional cache entries. +enum RebaseReason { + NoCycleUsages, + Ambiguity, + Overflow, + /// We've actually reached a fixpoint. + /// + /// This either happens in the first evaluation step for the cycle head. + /// In this case the used provisional result depends on the cycle `PathKind`. + /// We store this path kind to check whether the the provisional cache entry + /// we're rebasing relied on the same cycles. + /// + /// In later iterations cycles always return `stack_entry.provisional_result` + /// so we no longer depend on the `PathKind`. We store `None` in that case. + ReachedFixpoint(Option<PathKind>), +} + +impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> { /// A necessary optimization to handle complex solver cycles. A provisional cache entry /// relies on a set of cycle heads and the path towards these heads. When popping a cycle /// head from the stack after we've finished computing it, we can't be sure that the @@ -908,8 +949,9 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { /// to me. fn rebase_provisional_cache_entries( &mut self, + cx: X, stack_entry: &StackEntry<X>, - mut mutate_result: impl FnMut(X::Input, X::Result) -> X::Result, + rebase_reason: RebaseReason, ) { let popped_head_index = self.stack.next_index(); #[allow(rustc::potential_query_instability)] @@ -927,6 +969,10 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { return true; }; + let Some(new_highest_head_index) = heads.opt_highest_cycle_head_index() else { + return false; + }; + // We're rebasing an entry `e` over a head `p`. This head // has a number of own heads `h` it depends on. // @@ -977,22 +1023,37 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { let eph = ep.extend_with_paths(ph); heads.insert(head_index, eph, head.usages); } - } - let Some(head_index) = heads.opt_highest_cycle_head_index() else { - return false; - }; + // The provisional cache entry does depend on the provisional result + // of the popped cycle head. We need to mutate the result of our + // provisional cache entry in case we did not reach a fixpoint. + match rebase_reason { + // If the cycle head does not actually depend on itself, then + // the provisional result used by the provisional cache entry + // is not actually equal to the final provisional result. We + // need to discard the provisional cache entry in this case. + RebaseReason::NoCycleUsages => return false, + RebaseReason::Ambiguity => { + *result = D::propagate_ambiguity(cx, input, *result); + } + RebaseReason::Overflow => *result = D::fixpoint_overflow_result(cx, input), + RebaseReason::ReachedFixpoint(None) => {} + RebaseReason::ReachedFixpoint(Some(path_kind)) => { + if !popped_head.usages.is_single(path_kind) { + return false; + } + } + }; + } // We now care about the path from the next highest cycle head to the // provisional cache entry. *path_from_head = path_from_head.extend(Self::cycle_path_kind( &self.stack, stack_entry.step_kind_from_parent, - head_index, + new_highest_head_index, )); - // Mutate the result of the provisional cache entry in case we did - // not reach a fixpoint. - *result = mutate_result(input, *result); + true }); !entries.is_empty() @@ -1209,33 +1270,19 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { /// Whether we've reached a fixpoint when evaluating a cycle head. fn reached_fixpoint( &mut self, - cx: X, stack_entry: &StackEntry<X>, usages: HeadUsages, result: X::Result, - ) -> bool { + ) -> Result<Option<PathKind>, ()> { let provisional_result = stack_entry.provisional_result; - if usages.is_empty() { - true - } else if let Some(provisional_result) = provisional_result { - provisional_result == result + if let Some(provisional_result) = provisional_result { + if provisional_result == result { Ok(None) } else { Err(()) } + } else if let Some(path_kind) = D::is_initial_provisional_result(result) + .filter(|&path_kind| usages.is_single(path_kind)) + { + Ok(Some(path_kind)) } else { - let check = |k| D::is_initial_provisional_result(cx, k, stack_entry.input, result); - match usages { - HeadUsages { inductive: _, unknown: 0, coinductive: 0, forced_ambiguity: 0 } => { - check(PathKind::Inductive) - } - HeadUsages { inductive: 0, unknown: _, coinductive: 0, forced_ambiguity: 0 } => { - check(PathKind::Unknown) - } - HeadUsages { inductive: 0, unknown: 0, coinductive: _, forced_ambiguity: 0 } => { - check(PathKind::Coinductive) - } - HeadUsages { inductive: 0, unknown: 0, coinductive: 0, forced_ambiguity: _ } => { - check(PathKind::ForcedAmbiguity) - } - _ => false, - } + Err(()) } } @@ -1280,8 +1327,19 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { // is equal to the provisional result of the previous iteration, or because // this was only the head of either coinductive or inductive cycles, and the // final result is equal to the initial response for that case. - if self.reached_fixpoint(cx, &stack_entry, usages, result) { - self.rebase_provisional_cache_entries(&stack_entry, |_, result| result); + if let Ok(fixpoint) = self.reached_fixpoint(&stack_entry, usages, result) { + self.rebase_provisional_cache_entries( + cx, + &stack_entry, + RebaseReason::ReachedFixpoint(fixpoint), + ); + return EvaluationResult::finalize(stack_entry, encountered_overflow, result); + } else if usages.is_empty() { + self.rebase_provisional_cache_entries( + cx, + &stack_entry, + RebaseReason::NoCycleUsages, + ); return EvaluationResult::finalize(stack_entry, encountered_overflow, result); } @@ -1298,9 +1356,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { // we also taint all provisional cache entries which depend on the // current goal. if D::is_ambiguous_result(result) { - self.rebase_provisional_cache_entries(&stack_entry, |input, _| { - D::propagate_ambiguity(cx, input, result) - }); + self.rebase_provisional_cache_entries(cx, &stack_entry, RebaseReason::Ambiguity); return EvaluationResult::finalize(stack_entry, encountered_overflow, result); }; @@ -1309,10 +1365,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { i += 1; if i >= D::FIXPOINT_STEP_LIMIT { debug!("canonical cycle overflow"); - let result = D::on_fixpoint_overflow(cx, input); - self.rebase_provisional_cache_entries(&stack_entry, |input, _| { - D::on_fixpoint_overflow(cx, input) - }); + let result = D::fixpoint_overflow_result(cx, input); + self.rebase_provisional_cache_entries(cx, &stack_entry, RebaseReason::Overflow); return EvaluationResult::finalize(stack_entry, encountered_overflow, result); } diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 1a1606d8268..9d9a8e49847 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -109,19 +109,6 @@ pub struct QueryInput<I: Interner, P> { impl<I: Interner, P: Eq> Eq for QueryInput<I, P> {} -/// Opaques that are defined in the inference context before a query is called. -#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr( - feature = "nightly", - derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) -)] -pub struct PredefinedOpaquesData<I: Interner> { - pub opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>, -} - -impl<I: Interner> Eq for PredefinedOpaquesData<I> {} - /// Possible ways the given goal can be proven. #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] pub enum CandidateSource<I: Interner> { diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index dda59283677..bb80e2cf46d 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -15,7 +15,7 @@ pub use self::closure::*; use crate::inherent::*; #[cfg(feature = "nightly")] use crate::visit::TypeVisitable; -use crate::{self as ty, DebruijnIndex, FloatTy, IntTy, Interner, UintTy}; +use crate::{self as ty, BoundVarIndexKind, FloatTy, IntTy, Interner, UintTy}; mod closure; @@ -229,7 +229,7 @@ pub enum TyKind<I: Interner> { /// /// [1]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html /// [2]: https://rustc-dev-guide.rust-lang.org/traits/canonical-queries.html - Bound(DebruijnIndex, I::BoundTy), + Bound(BoundVarIndexKind, I::BoundTy), /// A placeholder type, used during higher ranked subtyping to instantiate /// bound variables. diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index 3a6d1acfa8d..4d9fd6040d8 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -344,7 +344,8 @@ impl<I: Interner> TypeVisitor<I> for HasRegionsBoundAt { } fn visit_region(&mut self, r: I::Region) -> Self::Result { - if matches!(r.kind(), ty::ReBound(binder, _) if self.binder == binder) { + if matches!(r.kind(), ty::ReBound(ty::BoundVarIndexKind::Bound(binder), _) if self.binder == binder) + { ControlFlow::Break(()) } else { ControlFlow::Continue(()) @@ -531,7 +532,7 @@ impl<I: Interner> TypeFolder<I> for FoldEscapingRegions<I> { } fn fold_region(&mut self, r: <I as Interner>::Region) -> <I as Interner>::Region { - if let ty::ReBound(debruijn, _) = r.kind() { + if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind() { assert!( debruijn <= self.debruijn, "cannot instantiate binder with escaping bound vars" diff --git a/compiler/rustc_windows_rc/Cargo.toml b/compiler/rustc_windows_rc/Cargo.toml index 080acd35c38..13f716897fa 100644 --- a/compiler/rustc_windows_rc/Cargo.toml +++ b/compiler/rustc_windows_rc/Cargo.toml @@ -5,7 +5,5 @@ edition = "2024" [dependencies] #tidy-alphabetical-start -# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version -# per crate", so if you change this, you need to also change it in `rustc_llvm` and `rustc_codegen_ssa`. -cc = "=1.2.16" +find-msvc-tools = "0.1.2" #tidy-alphabetical-end diff --git a/compiler/rustc_windows_rc/src/lib.rs b/compiler/rustc_windows_rc/src/lib.rs index 5e95557501e..15afaf7b94b 100644 --- a/compiler/rustc_windows_rc/src/lib.rs +++ b/compiler/rustc_windows_rc/src/lib.rs @@ -2,9 +2,7 @@ //! //! Uses values from the `CFG_VERSION` and `CFG_RELEASE` environment variables //! to set the product and file version information in the Windows resource file. -use std::{env, ffi, fs, path, process}; - -use cc::windows_registry; +use std::{env, fs, path, process}; /// The template for the Windows resource file. const RESOURCE_TEMPLATE: &str = include_str!("../rustc.rc.in"); @@ -38,7 +36,10 @@ pub fn compile_windows_resource_file( let resource_compiler = if let Ok(path) = env::var("RUSTC_WINDOWS_RC") { path.into() } else { - find_resource_compiler(&env::var("CARGO_CFG_TARGET_ARCH").unwrap()).expect("found rc.exe") + find_msvc_tools::find_tool(&env::var("CARGO_CFG_TARGET_ARCH").unwrap(), "rc.exe") + .expect("found rc.exe") + .path() + .to_owned() }; let rc_path = resources_dir.join(file_stem.with_extension("rc")); @@ -134,28 +135,3 @@ fn parse_version(version: &str) -> Option<ResourceVersion> { Some(ResourceVersion { major, minor, patch, build: 0 }) } } - -/// Find the Windows SDK resource compiler `rc.exe` for the given architecture or target triple. -/// Returns `None` if the tool could not be found. -fn find_resource_compiler(arch_or_target: &str) -> Option<path::PathBuf> { - find_windows_sdk_tool(arch_or_target, "rc.exe") -} - -/// Find a Windows SDK tool for the given architecture or target triple. -/// Returns `None` if the tool could not be found. -fn find_windows_sdk_tool(arch_or_target: &str, tool_name: &str) -> Option<path::PathBuf> { - // windows_registry::find_tool can only find MSVC tools, not Windows SDK tools, but - // cc does include the Windows SDK tools in the PATH environment of MSVC tools. - - let msvc_linker = windows_registry::find_tool(arch_or_target, "link.exe")?; - let path = &msvc_linker.env().iter().find(|(k, _)| k == "PATH")?.1; - find_tool_in_path(tool_name, path) -} - -/// Find a tool in the directories in a given PATH-like string. -fn find_tool_in_path<P: AsRef<ffi::OsStr>>(tool_name: &str, path: P) -> Option<path::PathBuf> { - env::split_paths(path.as_ref()).find_map(|p| { - let tool_path = p.join(tool_name); - if tool_path.try_exists().unwrap_or(false) { Some(tool_path) } else { None } - }) -} |
