diff options
| author | Laurențiu Nicola <lnicola@users.noreply.github.com> | 2024-11-01 12:26:18 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-11-01 12:26:18 +0000 |
| commit | cf6bc48353ba46fceb43f5efc37858c471d05bb7 (patch) | |
| tree | 0cff0055f2ed9e9d18df92e2d98f10d7b5359075 /compiler | |
| parent | a5b5b466b0517124e8c5d8610d708aa04a1c4fc7 (diff) | |
| parent | 9acf57c48e0d55e7b2d07dae2bb4fbfc3fc010dd (diff) | |
| download | rust-cf6bc48353ba46fceb43f5efc37858c471d05bb7.tar.gz rust-cf6bc48353ba46fceb43f5efc37858c471d05bb7.zip | |
Merge pull request #18457 from lnicola/sync-from-rust
minor: Sync from downstream
Diffstat (limited to 'compiler')
339 files changed, 3937 insertions, 3755 deletions
diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 7448f066d0a..3acd25e5461 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -9,9 +9,11 @@ bitflags = "2.4.1" rand = { version = "0.8.4", default-features = false, optional = true } rand_xoshiro = { version = "0.6.0", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } +rustc_feature = { path = "../rustc_feature", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } +rustc_span = { path = "../rustc_span", optional = true } tracing = "0.1" # tidy-alphabetical-end @@ -22,8 +24,10 @@ default = ["nightly", "randomize"] # without depending on rustc_data_structures, rustc_macros and rustc_serialize nightly = [ "dep:rustc_data_structures", + "dep:rustc_feature", "dep:rustc_macros", "dep:rustc_serialize", + "dep:rustc_span", "rustc_index/nightly", ] randomize = ["dep:rand", "dep:rand_xoshiro", "nightly"] diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index 872cae59a4e..ee63e46e88c 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -6,9 +6,9 @@ mod abi { #[cfg(feature = "nightly")] use rustc_macros::HashStable_Generic; -#[cfg(feature = "nightly")] -use crate::{Abi, FieldsShape, TyAbiInterface, TyAndLayout}; use crate::{Align, HasDataLayout, Size}; +#[cfg(feature = "nightly")] +use crate::{BackendRepr, FieldsShape, TyAbiInterface, TyAndLayout}; #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -128,11 +128,11 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { where Ty: TyAbiInterface<'a, C> + Copy, { - match self.abi { - Abi::Uninhabited => Err(Heterogeneous), + match self.backend_repr { + BackendRepr::Uninhabited => Err(Heterogeneous), // The primitive for this algorithm. - Abi::Scalar(scalar) => { + BackendRepr::Scalar(scalar) => { let kind = match scalar.primitive() { abi::Int(..) | abi::Pointer(_) => RegKind::Integer, abi::Float(_) => RegKind::Float, @@ -140,7 +140,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) } - Abi::Vector { .. } => { + BackendRepr::Vector { .. } => { assert!(!self.is_zst()); Ok(HomogeneousAggregate::Homogeneous(Reg { kind: RegKind::Vector, @@ -148,7 +148,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { })) } - Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => { + BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { // Helper for computing `homogeneous_aggregate`, allowing a custom // starting offset (used below for handling variants). let from_fields_at = @@ -246,7 +246,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ok(result) } } - Abi::Aggregate { sized: false } => Err(Heterogeneous), + BackendRepr::Memory { sized: false } => Err(Heterogeneous), } } } diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_abi/src/extern_abi/mod.rs index c2095155afa..f7e41280131 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_abi/src/extern_abi/mod.rs @@ -7,9 +7,11 @@ use rustc_span::{Span, Symbol}; #[cfg(test)] mod tests; +use ExternAbi as Abi; + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)] #[derive(HashStable_Generic, Encodable, Decodable)] -pub enum Abi { +pub enum ExternAbi { // Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the // hashing tests. These are used in many places, so giving them stable values reduces test // churn. The specific values are meaningless. diff --git a/compiler/rustc_target/src/spec/abi/tests.rs b/compiler/rustc_abi/src/extern_abi/tests.rs index 4823058dd69..4823058dd69 100644 --- a/compiler/rustc_target/src/spec/abi/tests.rs +++ b/compiler/rustc_abi/src/extern_abi/tests.rs diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 141a15b99a3..e6d66f608da 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -6,7 +6,7 @@ use rustc_index::Idx; use tracing::debug; use crate::{ - Abi, AbiAndPrefAlign, Align, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, + AbiAndPrefAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, }; @@ -28,7 +28,7 @@ where VariantIdx: Idx, F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug, { - let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited()); + let uninhabited = fields.iter().any(|f| f.is_uninhabited()); // We cannot ignore alignment; that might lead us to entirely discard a variant and // produce an enum that is less aligned than it should be! let is_1zst = fields.iter().all(|f| f.is_1zst()); @@ -125,7 +125,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { offsets: [Size::ZERO, b_offset].into(), memory_index: [0, 1].into(), }, - abi: Abi::ScalarPair(a, b), + backend_repr: BackendRepr::ScalarPair(a, b), largest_niche, align, size, @@ -216,7 +216,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, - abi: Abi::Uninhabited, + backend_repr: BackendRepr::Uninhabited, largest_niche: None, align: dl.i8_align, size: Size::ZERO, @@ -331,7 +331,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { if let Ok(common) = common_non_zst_abi_and_align { // Discard valid range information and allow undef - let field_abi = field.abi.to_union(); + let field_abi = field.backend_repr.to_union(); if let Some((common_abi, common_align)) = common { if common_abi != field_abi { @@ -340,7 +340,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { } else { // Fields with the same non-Aggregate ABI should also // have the same alignment - if !matches!(common_abi, Abi::Aggregate { .. }) { + if !matches!(common_abi, BackendRepr::Memory { .. }) { assert_eq!( common_align, field.align.abi, "non-Aggregate field with matching ABI but differing alignment" @@ -369,11 +369,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // If all non-ZST fields have the same ABI, we may forward that ABI // for the union as a whole, unless otherwise inhibited. let abi = match common_non_zst_abi_and_align { - Err(AbiMismatch) | Ok(None) => Abi::Aggregate { sized: true }, + Err(AbiMismatch) | Ok(None) => BackendRepr::Memory { sized: true }, Ok(Some((abi, _))) => { if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) { // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt - Abi::Aggregate { sized: true } + BackendRepr::Memory { sized: true } } else { abi } @@ -387,7 +387,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { Ok(LayoutData { variants: Variants::Single { index: only_variant_idx }, fields: FieldsShape::Union(union_field_count), - abi, + backend_repr: abi, largest_niche: None, align, size: size.align_to(align.abi), @@ -434,23 +434,23 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // Already doesn't have any niches Scalar::Union { .. } => {} }; - match &mut st.abi { - Abi::Uninhabited => {} - Abi::Scalar(scalar) => hide_niches(scalar), - Abi::ScalarPair(a, b) => { + match &mut st.backend_repr { + BackendRepr::Uninhabited => {} + BackendRepr::Scalar(scalar) => hide_niches(scalar), + BackendRepr::ScalarPair(a, b) => { hide_niches(a); hide_niches(b); } - Abi::Vector { element, count: _ } => hide_niches(element), - Abi::Aggregate { sized: _ } => {} + BackendRepr::Vector { element, count: _ } => hide_niches(element), + BackendRepr::Memory { sized: _ } => {} } st.largest_niche = None; return Ok(st); } let (start, end) = scalar_valid_range; - match st.abi { - Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { + match st.backend_repr { + BackendRepr::Scalar(ref mut scalar) | BackendRepr::ScalarPair(ref mut scalar, _) => { // Enlarging validity ranges would result in missed // optimizations, *not* wrongly assuming the inner // value is valid. e.g. unions already enlarge validity ranges, @@ -607,8 +607,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { } // It can't be a Scalar or ScalarPair because the offset isn't 0. - if !layout.abi.is_uninhabited() { - layout.abi = Abi::Aggregate { sized: true }; + if !layout.is_uninhabited() { + layout.backend_repr = BackendRepr::Memory { sized: true }; } layout.size += this_offset; @@ -627,26 +627,26 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let same_size = size == variant_layouts[largest_variant_index].size; let same_align = align == variant_layouts[largest_variant_index].align; - let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) { - Abi::Uninhabited + let abi = if variant_layouts.iter().all(|v| v.is_uninhabited()) { + BackendRepr::Uninhabited } else if same_size && same_align && others_zst { - match variant_layouts[largest_variant_index].abi { + match variant_layouts[largest_variant_index].backend_repr { // When the total alignment and size match, we can use the // same ABI as the scalar variant with the reserved niche. - Abi::Scalar(_) => Abi::Scalar(niche_scalar), - Abi::ScalarPair(first, second) => { + BackendRepr::Scalar(_) => BackendRepr::Scalar(niche_scalar), + BackendRepr::ScalarPair(first, second) => { // Only the niche is guaranteed to be initialised, // so use union layouts for the other primitive. if niche_offset == Size::ZERO { - Abi::ScalarPair(niche_scalar, second.to_union()) + BackendRepr::ScalarPair(niche_scalar, second.to_union()) } else { - Abi::ScalarPair(first.to_union(), niche_scalar) + BackendRepr::ScalarPair(first.to_union(), niche_scalar) } } - _ => Abi::Aggregate { sized: true }, + _ => BackendRepr::Memory { sized: true }, } } else { - Abi::Aggregate { sized: true } + BackendRepr::Memory { sized: true } }; let layout = LayoutData { @@ -664,7 +664,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { offsets: [niche_offset].into(), memory_index: [0].into(), }, - abi, + backend_repr: abi, largest_niche, size, align, @@ -681,7 +681,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let discr_type = repr.discr_type(); let bits = Integer::from_attr(dl, discr_type).size().bits(); for (i, mut val) in discriminants { - if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) { + if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) { continue; } if discr_type.is_signed() { @@ -833,14 +833,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { end: (max as u128 & tag_mask), }, }; - let mut abi = Abi::Aggregate { sized: true }; + let mut abi = BackendRepr::Memory { sized: true }; - if layout_variants.iter().all(|v| v.abi.is_uninhabited()) { - abi = Abi::Uninhabited; + if layout_variants.iter().all(|v| v.is_uninhabited()) { + abi = BackendRepr::Uninhabited; } else if tag.size(dl) == size { // Make sure we only use scalar layout when the enum is entirely its // own tag (i.e. it has no padding nor any non-ZST variant fields). - abi = Abi::Scalar(tag); + abi = BackendRepr::Scalar(tag); } else { // Try to use a ScalarPair for all tagged enums. // That's possible only if we can find a common primitive type for all variants. @@ -864,8 +864,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { break; } }; - let prim = match field.abi { - Abi::Scalar(scalar) => { + let prim = match field.backend_repr { + BackendRepr::Scalar(scalar) => { common_prim_initialized_in_all_variants &= matches!(scalar, Scalar::Initialized { .. }); scalar.primitive() @@ -934,7 +934,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { { // We can use `ScalarPair` only when it matches our // already computed layout (including `#[repr(C)]`). - abi = pair.abi; + abi = pair.backend_repr; } } } @@ -942,12 +942,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the // variants to ensure they are consistent. This is because a downcast is // semantically a NOP, and thus should not affect layout. - if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + if matches!(abi, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) { for variant in &mut layout_variants { // We only do this for variants with fields; the others are not accessed anyway. // Also do not overwrite any already existing "clever" ABIs. - if variant.fields.count() > 0 && matches!(variant.abi, Abi::Aggregate { .. }) { - variant.abi = abi; + if variant.fields.count() > 0 + && matches!(variant.backend_repr, BackendRepr::Memory { .. }) + { + variant.backend_repr = abi; // Also need to bump up the size and alignment, so that the entire value fits // in here. variant.size = cmp::max(variant.size, size); @@ -970,7 +972,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { memory_index: [0].into(), }, largest_niche, - abi, + backend_repr: abi, align, size, max_repr_align, @@ -1252,7 +1254,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { } let mut layout_of_single_non_zst_field = None; let sized = unsized_field.is_none(); - let mut abi = Abi::Aggregate { sized }; + let mut abi = BackendRepr::Memory { sized }; let optimize_abi = !repr.inhibit_newtype_abi_optimization(); @@ -1270,16 +1272,16 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // 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 { - match field.abi { + match field.backend_repr { // For plain scalars, or vectors of them, we can't unpack // newtypes for `#[repr(C)]`, as that affects C ABIs. - Abi::Scalar(_) | Abi::Vector { .. } if optimize_abi => { - abi = field.abi; + BackendRepr::Scalar(_) | BackendRepr::Vector { .. } if optimize_abi => { + abi = field.backend_repr; } // But scalar pairs are Rust-specific and get // treated as aggregates by C ABIs anyway. - Abi::ScalarPair(..) => { - abi = field.abi; + BackendRepr::ScalarPair(..) => { + abi = field.backend_repr; } _ => {} } @@ -1288,8 +1290,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { // Two non-ZST fields, and they're both scalars. (Some((i, a)), Some((j, b)), None) => { - match (a.abi, b.abi) { - (Abi::Scalar(a), Abi::Scalar(b)) => { + match (a.backend_repr, b.backend_repr) { + (BackendRepr::Scalar(a), BackendRepr::Scalar(b)) => { // Order by the memory placement, not source order. let ((i, a), (j, b)) = if offsets[i] < offsets[j] { ((i, a), (j, b)) @@ -1315,7 +1317,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { { // We can use `ScalarPair` only when it matches our // already computed layout (including `#[repr(C)]`). - abi = pair.abi; + abi = pair.backend_repr; } } _ => {} @@ -1325,8 +1327,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { _ => {} } } - if fields.iter().any(|f| f.abi.is_uninhabited()) { - abi = Abi::Uninhabited; + if fields.iter().any(|f| f.is_uninhabited()) { + abi = BackendRepr::Uninhabited; } let unadjusted_abi_align = if repr.transparent() { @@ -1344,7 +1346,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets, memory_index }, - abi, + backend_repr: abi, largest_niche, align, size, diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index e029e1426b2..062447ea03f 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -83,8 +83,8 @@ impl<'a> Layout<'a> { &self.0.0.variants } - pub fn abi(self) -> Abi { - self.0.0.abi + pub fn backend_repr(self) -> BackendRepr { + self.0.0.backend_repr } pub fn largest_niche(self) -> Option<Niche> { @@ -114,7 +114,7 @@ impl<'a> Layout<'a> { pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool { self.size() == data_layout.pointer_size && self.align().abi == data_layout.pointer_align.abi - && matches!(self.abi(), Abi::Scalar(Scalar::Initialized { .. })) + && matches!(self.backend_repr(), BackendRepr::Scalar(Scalar::Initialized { .. })) } } @@ -196,9 +196,9 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty: TyAbiInterface<'a, C>, C: HasDataLayout, { - match self.abi { - Abi::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)), - Abi::Aggregate { .. } => { + match self.backend_repr { + BackendRepr::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)), + BackendRepr::Memory { .. } => { if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { self.field(cx, 0).is_single_fp_element(cx) } else { diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index b54efa4bb48..ec758785173 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1,6 +1,7 @@ // tidy-alphabetical-start #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", doc(rust_logo))] +#![cfg_attr(feature = "nightly", feature(assert_matches))] #![cfg_attr(feature = "nightly", feature(rustc_attrs))] #![cfg_attr(feature = "nightly", feature(rustdoc_internals))] #![cfg_attr(feature = "nightly", feature(step_trait))] @@ -28,8 +29,15 @@ mod layout; #[cfg(test)] mod tests; +#[cfg(feature = "nightly")] +mod extern_abi; + pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind}; #[cfg(feature = "nightly")] +pub use extern_abi::{ + AbiDisabled, AbiUnsupported, ExternAbi, all_names, enabled_names, is_enabled, is_stable, lookup, +}; +#[cfg(feature = "nightly")] pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx}; pub use layout::{LayoutCalculator, LayoutCalculatorError}; @@ -1344,11 +1352,19 @@ impl AddressSpace { pub const DATA: Self = AddressSpace(0); } -/// Describes how values of the type are passed by target ABIs, -/// in terms of categories of C types there are ABI rules for. +/// The way we represent values to the backend +/// +/// Previously this was conflated with the "ABI" a type is given, as in the platform-specific ABI. +/// In reality, this implies little about that, but is mostly used to describe the syntactic form +/// emitted for the backend, as most backends handle SSA values and blobs of memory differently. +/// The psABI may need consideration in doing so, but this enum does not constitute a promise for +/// how the value will be lowered to the calling convention, in itself. +/// +/// Generally, a codegen backend will prefer to handle smaller values as a scalar or short vector, +/// and larger values will usually prefer to be represented as memory. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] -pub enum Abi { +pub enum BackendRepr { Uninhabited, Scalar(Scalar), ScalarPair(Scalar, Scalar), @@ -1356,19 +1372,23 @@ pub enum Abi { element: Scalar, count: u64, }, - Aggregate { + // FIXME: I sometimes use memory, sometimes use an IR aggregate! + Memory { /// If true, the size is exact, otherwise it's only a lower bound. sized: bool, }, } -impl Abi { +impl BackendRepr { /// Returns `true` if the layout corresponds to an unsized type. #[inline] pub fn is_unsized(&self) -> bool { match *self { - Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, - Abi::Aggregate { sized } => !sized, + BackendRepr::Uninhabited + | BackendRepr::Scalar(_) + | BackendRepr::ScalarPair(..) + | BackendRepr::Vector { .. } => false, + BackendRepr::Memory { sized } => !sized, } } @@ -1381,7 +1401,7 @@ impl Abi { #[inline] pub fn is_signed(&self) -> bool { match self { - Abi::Scalar(scal) => match scal.primitive() { + BackendRepr::Scalar(scal) => match scal.primitive() { Primitive::Int(_, signed) => signed, _ => false, }, @@ -1392,61 +1412,67 @@ impl Abi { /// Returns `true` if this is an uninhabited type #[inline] pub fn is_uninhabited(&self) -> bool { - matches!(*self, Abi::Uninhabited) + matches!(*self, BackendRepr::Uninhabited) } /// Returns `true` if this is a scalar type #[inline] pub fn is_scalar(&self) -> bool { - matches!(*self, Abi::Scalar(_)) + matches!(*self, BackendRepr::Scalar(_)) } /// Returns `true` if this is a bool #[inline] pub fn is_bool(&self) -> bool { - matches!(*self, Abi::Scalar(s) if s.is_bool()) + matches!(*self, BackendRepr::Scalar(s) if s.is_bool()) } /// Returns the fixed alignment of this ABI, if any is mandated. pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> { Some(match *self { - Abi::Scalar(s) => s.align(cx), - Abi::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)), - Abi::Vector { element, count } => { + BackendRepr::Scalar(s) => s.align(cx), + BackendRepr::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)), + BackendRepr::Vector { element, count } => { cx.data_layout().vector_align(element.size(cx) * count) } - Abi::Uninhabited | Abi::Aggregate { .. } => return None, + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => return None, }) } /// Returns the fixed size of this ABI, if any is mandated. pub fn inherent_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> { Some(match *self { - Abi::Scalar(s) => { + BackendRepr::Scalar(s) => { // No padding in scalars. s.size(cx) } - Abi::ScalarPair(s1, s2) => { + BackendRepr::ScalarPair(s1, s2) => { // May have some padding between the pair. let field2_offset = s1.size(cx).align_to(s2.align(cx).abi); (field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi) } - Abi::Vector { element, count } => { + BackendRepr::Vector { element, count } => { // No padding in vectors, except possibly for trailing padding // to make the size a multiple of align (e.g. for vectors of size 3). (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi) } - Abi::Uninhabited | Abi::Aggregate { .. } => return None, + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => return None, }) } /// Discard validity range information and allow undef. pub fn to_union(&self) -> Self { match *self { - Abi::Scalar(s) => Abi::Scalar(s.to_union()), - Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()), - Abi::Vector { element, count } => Abi::Vector { element: element.to_union(), count }, - Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true }, + BackendRepr::Scalar(s) => BackendRepr::Scalar(s.to_union()), + BackendRepr::ScalarPair(s1, s2) => { + BackendRepr::ScalarPair(s1.to_union(), s2.to_union()) + } + BackendRepr::Vector { element, count } => { + BackendRepr::Vector { element: element.to_union(), count } + } + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => { + BackendRepr::Memory { sized: true } + } } } @@ -1454,12 +1480,12 @@ impl Abi { match (self, other) { // Scalar, Vector, ScalarPair have `Scalar` in them where we ignore validity ranges. // We do *not* ignore the sign since it matters for some ABIs (e.g. s390x). - (Abi::Scalar(l), Abi::Scalar(r)) => l.primitive() == r.primitive(), + (BackendRepr::Scalar(l), BackendRepr::Scalar(r)) => l.primitive() == r.primitive(), ( - Abi::Vector { element: element_l, count: count_l }, - Abi::Vector { element: element_r, count: count_r }, + BackendRepr::Vector { element: element_l, count: count_l }, + BackendRepr::Vector { element: element_r, count: count_r }, ) => element_l.primitive() == element_r.primitive() && count_l == count_r, - (Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) => { + (BackendRepr::ScalarPair(l1, l2), BackendRepr::ScalarPair(r1, r2)) => { l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive() } // Everything else must be strictly identical. @@ -1616,14 +1642,14 @@ pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> { /// must be taken into account. pub variants: Variants<FieldIdx, VariantIdx>, - /// The `abi` defines how this data is passed between functions, and it defines - /// value restrictions via `valid_range`. + /// The `backend_repr` defines how this data will be represented to the codegen backend, + /// and encodes value restrictions via `valid_range`. /// /// Note that this is entirely orthogonal to the recursive structure defined by /// `variants` and `fields`; for example, `ManuallyDrop<Result<isize, isize>>` has - /// `Abi::ScalarPair`! So, even with non-`Aggregate` `abi`, `fields` and `variants` + /// `IrForm::ScalarPair`! So, even with non-`Memory` `backend_repr`, `fields` and `variants` /// have to be taken into account to find all fields of this layout. - pub abi: Abi, + pub backend_repr: BackendRepr, /// The leaf scalar with the largest number of invalid values /// (i.e. outside of its `valid_range`), if it exists. @@ -1646,12 +1672,17 @@ pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> { impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { /// Returns `true` if this is an aggregate type (including a ScalarPair!) pub fn is_aggregate(&self) -> bool { - match self.abi { - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false, - Abi::ScalarPair(..) | Abi::Aggregate { .. } => true, + match self.backend_repr { + BackendRepr::Uninhabited | BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => false, + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true, } } + /// Returns `true` if this is an uninhabited type + pub fn is_uninhabited(&self) -> bool { + self.backend_repr.is_uninhabited() + } + pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self { let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); let size = scalar.size(cx); @@ -1659,7 +1690,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, - abi: Abi::Scalar(scalar), + backend_repr: BackendRepr::Scalar(scalar), largest_niche, size, align, @@ -1681,7 +1712,7 @@ where let LayoutData { size, align, - abi, + backend_repr, fields, largest_niche, variants, @@ -1691,7 +1722,7 @@ where f.debug_struct("Layout") .field("size", size) .field("align", align) - .field("abi", abi) + .field("abi", backend_repr) .field("fields", fields) .field("largest_niche", largest_niche) .field("variants", variants) @@ -1727,12 +1758,12 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { /// Returns `true` if the layout corresponds to an unsized type. #[inline] pub fn is_unsized(&self) -> bool { - self.abi.is_unsized() + self.backend_repr.is_unsized() } #[inline] pub fn is_sized(&self) -> bool { - self.abi.is_sized() + self.backend_repr.is_sized() } /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1). @@ -1745,10 +1776,12 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { /// Note that this does *not* imply that the type is irrelevant for layout! It can still have /// non-trivial alignment constraints. You probably want to use `is_1zst` instead. pub fn is_zst(&self) -> bool { - match self.abi { - Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, - Abi::Uninhabited => self.size.bytes() == 0, - Abi::Aggregate { sized } => sized && self.size.bytes() == 0, + match self.backend_repr { + BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) | BackendRepr::Vector { .. } => { + false + } + BackendRepr::Uninhabited => self.size.bytes() == 0, + BackendRepr::Memory { sized } => sized && self.size.bytes() == 0, } } @@ -1763,8 +1796,8 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { // 2nd point is quite hard to check though. self.size == other.size && self.is_sized() == other.is_sized() - && self.abi.eq_up_to_validity(&other.abi) - && self.abi.is_bool() == other.abi.is_bool() + && self.backend_repr.eq_up_to_validity(&other.backend_repr) + && self.backend_repr.is_bool() == other.backend_repr.is_bool() && self.align.abi == other.align.abi && self.max_repr_align == other.max_repr_align && self.unadjusted_abi_align == other.unadjusted_abi_align diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 8e4f4c8e71a..ec6ca70ae0a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2810,6 +2810,8 @@ pub struct ModSpans { /// E.g., `extern { .. }` or `extern "C" { .. }`. #[derive(Clone, Encodable, Decodable, Debug)] pub struct ForeignMod { + /// Span of the `extern` keyword. + pub extern_span: Span, /// `unsafe` keyword accepted syntactically for macro DSLs, but not /// semantically by Rust. pub safety: Safety, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 2afbd979c30..44bb44cb728 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -525,7 +525,7 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) { } fn walk_foreign_mod<T: MutVisitor>(vis: &mut T, foreign_mod: &mut ForeignMod) { - let ForeignMod { safety, abi: _, items } = foreign_mod; + let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod; visit_safety(vis, safety); items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 1d6abbef06c..3b9edef0615 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -368,7 +368,7 @@ impl Clone for TokenKind { // a copy. This is faster than the `derive(Clone)` version which has a // separate path for every variant. match self { - Interpolated(nt) => Interpolated(nt.clone()), + Interpolated(nt) => Interpolated(Lrc::clone(nt)), _ => unsafe { std::ptr::read(self) }, } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index eb71ec5f4ec..2f8115441de 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -366,7 +366,7 @@ impl WalkItemKind for ItemKind { } ModKind::Unloaded => {} }, - ItemKind::ForeignMod(ForeignMod { safety: _, abi: _, items }) => { + ItemKind::ForeignMod(ForeignMod { extern_span: _, safety: _, abi: _, items }) => { walk_list!(visitor, visit_foreign_item, items); } ItemKind::GlobalAsm(asm) => try_visit!(visitor.visit_inline_asm(asm)), diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 9d2b5690c23..20d3ce65fac 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -10,17 +10,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { b: &Block, targeted_by_break: bool, ) -> &'hir hir::Block<'hir> { - self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break)) + let hir_id = self.lower_node_id(b.id); + self.arena.alloc(self.lower_block_noalloc(hir_id, b, targeted_by_break)) } pub(super) fn lower_block_noalloc( &mut self, + hir_id: hir::HirId, b: &Block, targeted_by_break: bool, ) -> hir::Block<'hir> { let (stmts, expr) = self.lower_stmts(&b.stmts); let rules = self.lower_block_check_mode(&b.rules); - let hir_id = self.lower_node_id(b.id); hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break } } diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 3b85f1737bd..70c94f4019a 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -259,10 +259,11 @@ impl<'hir> LoweringContext<'_, 'hir> { self_param_id: pat_node_id, }; self_resolver.visit_block(block); + // Target expr needs to lower `self` path. + this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id); this.lower_target_expr(&block) } else { - let pat_hir_id = this.lower_node_id(pat_node_id); - this.generate_arg(pat_hir_id, span) + this.generate_arg(param.pat.hir_id, span) }; args.push(arg); } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a1a16d0ca26..b7cf2d252dc 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -3,6 +3,7 @@ use std::assert_matches::assert_matches; use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::HirId; use rustc_hir::def::{DefKind, Res}; @@ -70,8 +71,8 @@ impl<'hir> LoweringContext<'_, 'hir> { _ => (), } - let hir_id = self.lower_node_id(e.id); - self.lower_attrs(hir_id, &e.attrs); + let expr_hir_id = self.lower_node_id(e.id); + self.lower_attrs(expr_hir_id, &e.attrs); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -143,7 +144,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::IncludedBytes(bytes) => { let lit = self.arena.alloc(respan( self.lower_span(e.span), - LitKind::ByteStr(bytes.clone(), StrStyle::Cooked), + LitKind::ByteStr(Lrc::clone(bytes), StrStyle::Cooked), )); hir::ExprKind::Lit(lit) } @@ -175,18 +176,25 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::If(cond, then, else_opt) => { self.lower_expr_if(cond, then, else_opt.as_deref()) } - ExprKind::While(cond, body, opt_label) => self.with_loop_scope(e.id, |this| { - let span = this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None); - this.lower_expr_while_in_loop_scope(span, cond, body, *opt_label) - }), - ExprKind::Loop(body, opt_label, span) => self.with_loop_scope(e.id, |this| { - hir::ExprKind::Loop( - this.lower_block(body, false), - this.lower_label(*opt_label), - hir::LoopSource::Loop, - this.lower_span(*span), - ) - }), + ExprKind::While(cond, body, opt_label) => { + self.with_loop_scope(expr_hir_id, |this| { + let span = + this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None); + let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id); + this.lower_expr_while_in_loop_scope(span, cond, body, opt_label) + }) + } + ExprKind::Loop(body, opt_label, span) => { + self.with_loop_scope(expr_hir_id, |this| { + let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id); + hir::ExprKind::Loop( + this.lower_block(body, false), + opt_label, + hir::LoopSource::Loop, + this.lower_span(*span), + ) + }) + } ExprKind::TryBlock(body) => self.lower_expr_try_block(body), ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match( self.lower_expr(expr), @@ -212,7 +220,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder, *capture_clause, e.id, - hir_id, + expr_hir_id, *coroutine_kind, fn_decl, body, @@ -223,7 +231,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder, *capture_clause, e.id, - hir_id, + expr_hir_id, *constness, *movability, fn_decl, @@ -250,8 +258,16 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } ExprKind::Block(blk, opt_label) => { - let opt_label = self.lower_label(*opt_label); - hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label) + // Different from loops, label of block resolves to block id rather than + // expr node id. + let block_hir_id = self.lower_node_id(blk.id); + let opt_label = self.lower_label(*opt_label, blk.id, block_hir_id); + let hir_block = self.arena.alloc(self.lower_block_noalloc( + block_hir_id, + blk, + opt_label.is_some(), + )); + hir::ExprKind::Block(hir_block, opt_label) } ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span), ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp( @@ -354,7 +370,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span), }; - hir::Expr { hir_id, kind, span: self.lower_span(e.span) } + hir::Expr { hir_id: expr_hir_id, kind, span: self.lower_span(e.span) } }) } @@ -504,7 +520,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let if_expr = self.expr(span, if_kind); let block = self.block_expr(self.arena.alloc(if_expr)); let span = self.lower_span(span.with_hi(cond.span.hi())); - let opt_label = self.lower_label(opt_label); hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span) } @@ -512,8 +527,9 @@ impl<'hir> LoweringContext<'_, 'hir> { /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }` /// and save the block id to use it as a break target for desugaring of the `?` operator. fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> { - self.with_catch_scope(body.id, |this| { - let mut block = this.lower_block_noalloc(body, true); + let body_hir_id = self.lower_node_id(body.id); + self.with_catch_scope(body_hir_id, |this| { + let mut block = this.lower_block_noalloc(body_hir_id, body, true); // Final expression of the block (if present) or `()` with span at the end of block let (try_span, tail_expr) = if let Some(expr) = block.expr.take() { @@ -521,7 +537,7 @@ impl<'hir> LoweringContext<'_, 'hir> { this.mark_span_with_reason( DesugaringKind::TryBlock, expr.span, - Some(this.allow_try_trait.clone()), + Some(Lrc::clone(&this.allow_try_trait)), ), expr, ) @@ -529,7 +545,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let try_span = this.mark_span_with_reason( DesugaringKind::TryBlock, this.tcx.sess.source_map().end_point(body.span), - Some(this.allow_try_trait.clone()), + Some(Lrc::clone(&this.allow_try_trait)), ); (try_span, this.expr_unit(try_span)) @@ -638,7 +654,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::Async, self.lower_span(span), - Some(self.allow_gen_future.clone()), + Some(Lrc::clone(&self.allow_gen_future)), ); let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None); @@ -724,7 +740,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::Async, span, - Some(self.allow_gen_future.clone()), + Some(Lrc::clone(&self.allow_gen_future)), ); self.lower_attrs(inner_hir_id, &[Attribute { kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new( @@ -800,13 +816,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let features = match await_kind { FutureKind::Future => None, - FutureKind::AsyncIterator => Some(self.allow_for_await.clone()), + FutureKind::AsyncIterator => Some(Lrc::clone(&self.allow_for_await)), }; let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features); let gen_future_span = self.mark_span_with_reason( DesugaringKind::Await, full_span, - Some(self.allow_gen_future.clone()), + Some(Lrc::clone(&self.allow_gen_future)), ); let expr_hir_id = expr.hir_id; @@ -869,7 +885,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid); let ready_field = self.single_pat_field(gen_future_span, x_pat); let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field); - let break_x = self.with_loop_scope(loop_node_id, move |this| { + let break_x = self.with_loop_scope(loop_hir_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); this.arena.alloc(this.expr(gen_future_span, expr_break)) @@ -1101,8 +1117,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::CoroutineSource::Closure, ); - let hir_id = this.lower_node_id(coroutine_kind.closure_id()); - this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id); + this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id); (parameters, expr) }); @@ -1465,8 +1480,16 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } - fn lower_label(&self, opt_label: Option<Label>) -> Option<Label> { + // Record labelled expr's HirId so that we can retrieve it in `lower_jump_destination` without + // lowering node id again. + fn lower_label( + &mut self, + opt_label: Option<Label>, + dest_id: NodeId, + dest_hir_id: hir::HirId, + ) -> Option<Label> { let label = opt_label?; + self.ident_and_label_to_local_id.insert(dest_id, dest_hir_id.local_id); Some(Label { ident: self.lower_ident(label.ident) }) } @@ -1474,17 +1497,20 @@ impl<'hir> LoweringContext<'_, 'hir> { let target_id = match destination { Some((id, _)) => { if let Some(loop_id) = self.resolver.get_label_res(id) { - Ok(self.lower_node_id(loop_id)) + let local_id = self.ident_and_label_to_local_id[&loop_id]; + let loop_hir_id = HirId { owner: self.current_hir_id_owner, local_id }; + Ok(loop_hir_id) } else { Err(hir::LoopIdError::UnresolvedLabel) } } - None => self - .loop_scope - .map(|id| Ok(self.lower_node_id(id))) - .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)), + None => { + self.loop_scope.map(|id| Ok(id)).unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)) + } }; - let label = self.lower_label(destination.map(|(_, label)| label)); + let label = destination + .map(|(_, label)| label) + .map(|label| Label { ident: self.lower_ident(label.ident) }); hir::Destination { label, target_id } } @@ -1499,14 +1525,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn with_catch_scope<T>(&mut self, catch_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { + fn with_catch_scope<T>(&mut self, catch_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T { let old_scope = self.catch_scope.replace(catch_id); let result = f(self); self.catch_scope = old_scope; result } - fn with_loop_scope<T>(&mut self, loop_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { + fn with_loop_scope<T>(&mut self, loop_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T { // We're no longer in the base loop's condition; we're in another loop. let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; @@ -1658,9 +1684,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None); let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None); + let loop_hir_id = self.lower_node_id(e.id); + let label = self.lower_label(opt_label, e.id, loop_hir_id); + // `None => break` let none_arm = { - let break_expr = self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span)); + let break_expr = + self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span)); let pat = self.pat_none(for_span); self.arm(pat, break_expr) }; @@ -1668,7 +1698,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // Some(<pat>) => <body>, let some_arm = { let some_pat = self.pat_some(pat_span, pat); - let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); + let body_block = + self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false)); let body_expr = self.arena.alloc(self.expr_block(body_block)); self.arm(some_pat, body_expr) }; @@ -1722,12 +1753,11 @@ impl<'hir> LoweringContext<'_, 'hir> { // `[opt_ident]: loop { ... }` let kind = hir::ExprKind::Loop( loop_block, - self.lower_label(opt_label), + label, hir::LoopSource::ForLoop, self.lower_span(for_span.with_hi(head.span.hi())), ); - let loop_expr = - self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: for_span }); + let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span }); // `mut iter => { ... }` let iter_arm = self.arm(iter_pat, loop_expr); @@ -1812,13 +1842,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::QuestionMark, span, - Some(self.allow_try_trait.clone()), + Some(Lrc::clone(&self.allow_try_trait)), ); let try_span = self.tcx.sess.source_map().end_point(span); let try_span = self.mark_span_with_reason( DesugaringKind::QuestionMark, try_span, - Some(self.allow_try_trait.clone()), + Some(Lrc::clone(&self.allow_try_trait)), ); // `Try::branch(<expr>)` @@ -1867,8 +1897,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(residual_expr), unstable_span, ); - let ret_expr = if let Some(catch_node) = self.catch_scope { - let target_id = Ok(self.lower_node_id(catch_node)); + let ret_expr = if let Some(catch_id) = self.catch_scope { + let target_id = Ok(catch_id); self.arena.alloc(self.expr( try_span, hir::ExprKind::Break( @@ -1912,7 +1942,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::YeetExpr, span, - Some(self.allow_try_trait.clone()), + Some(Lrc::clone(&self.allow_try_trait)), ); let from_yeet_expr = self.wrap_in_try_constructor( @@ -1922,8 +1952,8 @@ impl<'hir> LoweringContext<'_, 'hir> { yeeted_span, ); - if let Some(catch_node) = self.catch_scope { - let target_id = Ok(self.lower_node_id(catch_node)); + if let Some(catch_id) = self.catch_scope { + let target_id = Ok(catch_id); hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr)) } else { hir::ExprKind::Ret(Some(from_yeet_expr)) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 97fa90d340e..d7245607501 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -154,7 +154,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> { let mut ident = i.ident; let vis_span = self.lower_span(i.vis.span); - let hir_id = self.lower_node_id(i.id); + let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let attrs = self.lower_attrs(hir_id, &i.attrs); let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind); let item = hir::Item { @@ -604,7 +604,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { - let hir_id = self.lower_node_id(i.id); + let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let owner_id = hir_id.expect_owner(); self.lower_attrs(hir_id, &i.attrs); let item = hir::ForeignItem { @@ -728,7 +728,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { - let hir_id = self.lower_node_id(i.id); + let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); self.lower_attrs(hir_id, &i.attrs); let trait_item_def_id = hir_id.expect_owner(); @@ -858,7 +858,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); - let hir_id = self.lower_node_id(i.id); + let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); self.lower_attrs(hir_id, &i.attrs); let (generics, kind) = match &i.kind { @@ -1086,7 +1086,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); // FIXME(async_fn_track_caller): Can this be moved above? - let hir_id = this.lower_node_id(coroutine_kind.closure_id()); + let hir_id = expr.hir_id; this.maybe_forward_track_caller(body.span, fn_id, hir_id); (parameters, expr) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 34b8137aea8..5a0e9e8aec0 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -40,23 +40,19 @@ #![warn(unreachable_pub)] // tidy-alphabetical-end -use std::collections::hash_map::Entry; - use rustc_ast::node_id::NodeMap; use rustc_ast::ptr::P; use rustc_ast::{self as ast, *}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; +use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::{ - self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, MissingLifetimeKind, - ParamName, TraitCandidate, + self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, ParamName, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -85,7 +81,6 @@ mod expr; mod format; mod index; mod item; -mod lifetime_collector; mod pat; mod path; @@ -115,8 +110,8 @@ struct LoweringContext<'a, 'hir> { /// outside of an `async fn`. current_item: Option<Span>, - catch_scope: Option<NodeId>, - loop_scope: Option<NodeId>, + catch_scope: Option<HirId>, + loop_scope: Option<HirId>, is_in_loop_condition: bool, is_in_trait_impl: bool, is_in_dyn_type: bool, @@ -140,7 +135,10 @@ struct LoweringContext<'a, 'hir> { impl_trait_defs: Vec<hir::GenericParam<'hir>>, impl_trait_bounds: Vec<hir::WherePredicate<'hir>>, - /// NodeIds that are lowered inside the current HIR owner. + /// NodeIds of pattern identifiers and labelled nodes that are lowered inside the current HIR owner. + ident_and_label_to_local_id: NodeMap<hir::ItemLocalId>, + /// NodeIds that are lowered inside the current HIR owner. Only used for duplicate lowering check. + #[cfg(debug_assertions)] node_id_to_local_id: NodeMap<hir::ItemLocalId>, allow_try_trait: Lrc<[Symbol]>, @@ -148,12 +146,6 @@ struct LoweringContext<'a, 'hir> { allow_async_iterator: Lrc<[Symbol]>, allow_for_await: Lrc<[Symbol]>, allow_async_fn_traits: Lrc<[Symbol]>, - - /// Mapping from generics `def_id`s to TAIT generics `def_id`s. - /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic - /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this - /// field from the original parameter 'a to the new parameter 'a1. - generics_def_id_map: Vec<LocalDefIdMap<LocalDefId>>, } impl<'a, 'hir> LoweringContext<'a, 'hir> { @@ -171,6 +163,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { current_hir_id_owner: hir::CRATE_OWNER_ID, current_def_id_parent: CRATE_DEF_ID, item_local_id_counter: hir::ItemLocalId::ZERO, + ident_and_label_to_local_id: Default::default(), + #[cfg(debug_assertions)] node_id_to_local_id: Default::default(), trait_map: Default::default(), @@ -196,7 +190,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller` // interact with `gen`/`async gen` blocks allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), - generics_def_id_map: Default::default(), } } @@ -279,7 +272,7 @@ enum ImplTraitContext { /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually /// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`. /// - OpaqueTy { origin: hir::OpaqueTyOrigin }, + OpaqueTy { origin: hir::OpaqueTyOrigin<LocalDefId> }, /// `impl Trait` is unstably accepted in this position. FeatureGated(ImplTraitPosition, Symbol), /// `impl Trait` is not accepted in this position. @@ -525,54 +518,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name /// resolver (if any). - fn orig_opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> { - self.resolver.node_id_to_def_id.get(&node).copied() - } - - /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name - /// resolver (if any), after applying any remapping from `get_remapped_def_id`. - /// - /// For example, in a function like `fn foo<'a>(x: &'a u32)`, - /// invoking with the id from the `ast::Lifetime` node found inside - /// the `&'a u32` type would return the `LocalDefId` of the - /// `'a` parameter declared on `foo`. - /// - /// This function also applies remapping from `get_remapped_def_id`. - /// These are used when synthesizing opaque types from `-> impl Trait` return types and so forth. - /// For example, in a function like `fn foo<'a>() -> impl Debug + 'a`, - /// we would create an opaque type `type FooReturn<'a1> = impl Debug + 'a1`. - /// When lowering the `Debug + 'a` bounds, we add a remapping to map `'a` to `'a1`. fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> { - self.orig_opt_local_def_id(node).map(|local_def_id| self.get_remapped_def_id(local_def_id)) + self.resolver.node_id_to_def_id.get(&node).copied() } fn local_def_id(&self, node: NodeId) -> LocalDefId { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) } - /// Get the previously recorded `to` local def id given the `from` local def id, obtained using - /// `generics_def_id_map` field. - fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId { - // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we - // push new mappings, so we first need to get the latest (innermost) mappings, hence `iter().rev()`. - // - // Consider: - // - // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}` - // - // We would end with a generics_def_id_map like: - // - // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]` - // - // for the opaque type generated on `impl Sized + 'b`, we want the result to be: impl_sized#'b. - // So, if we were trying to find first from the start (outermost) would give the wrong result, impl_trait#'b. - self.generics_def_id_map - .iter() - .rev() - .find_map(|map| map.get(&local_def_id).copied()) - .unwrap_or(local_def_id) - } - /// Freshen the `LoweringContext` and ready it to lower a nested item. /// The lowered item is registered into `self.children`. /// @@ -588,7 +541,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); - let current_node_ids = std::mem::take(&mut self.node_id_to_local_id); + let current_ident_and_label_to_local_id = + std::mem::take(&mut self.ident_and_label_to_local_id); + + #[cfg(debug_assertions)] + let current_node_id_to_local_id = std::mem::take(&mut self.node_id_to_local_id); let current_trait_map = std::mem::take(&mut self.trait_map); let current_owner = std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id }); @@ -602,8 +559,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // and the caller to refer to some of the subdefinitions' nodes' `LocalDefId`s. // Always allocate the first `HirId` for the owner itself. - let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO); - debug_assert_eq!(_old, None); + #[cfg(debug_assertions)] + { + let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO); + debug_assert_eq!(_old, None); + } let item = self.with_def_id_parent(def_id, f); debug_assert_eq!(def_id, item.def_id().def_id); @@ -614,7 +574,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs = current_attrs; self.bodies = current_bodies; - self.node_id_to_local_id = current_node_ids; + self.ident_and_label_to_local_id = current_ident_and_label_to_local_id; + + #[cfg(debug_assertions)] + { + self.node_id_to_local_id = current_node_id_to_local_id; + } self.trait_map = current_trait_map; self.current_hir_id_owner = current_owner; self.item_local_id_counter = current_local_counter; @@ -632,27 +597,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { result } - /// Installs the remapping `remap` in scope while `f` is being executed. - /// This causes references to the `LocalDefId` keys to be changed to - /// refer to the values instead. - /// - /// The remapping is used when one piece of AST expands to multiple - /// pieces of HIR. For example, the function `fn foo<'a>(...) -> impl Debug + 'a`, - /// expands to both a function definition (`foo`) and a TAIT for the return value, - /// both of which have a lifetime parameter `'a`. The remapping allows us to - /// rewrite the `'a` in the return value to refer to the - /// `'a` declared on the TAIT, instead of the function. - fn with_remapping<R>( - &mut self, - remap: LocalDefIdMap<LocalDefId>, - f: impl FnOnce(&mut Self) -> R, - ) -> R { - self.generics_def_id_map.push(remap); - let res = f(self); - self.generics_def_id_map.pop(); - res - } - fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); @@ -680,39 +624,37 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map }) } - /// This method allocates a new `HirId` for the given `NodeId` and stores it in - /// the `LoweringContext`'s `NodeId => HirId` map. + /// This method allocates a new `HirId` for the given `NodeId`. /// Take care not to call this method if the resulting `HirId` is then not /// actually used in the HIR, as that would trigger an assertion in the /// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped - /// properly. Calling the method twice with the same `NodeId` is fine though. + /// properly. Calling the method twice with the same `NodeId` is also forbidden. #[instrument(level = "debug", skip(self), ret)] fn lower_node_id(&mut self, ast_node_id: NodeId) -> HirId { assert_ne!(ast_node_id, DUMMY_NODE_ID); - match self.node_id_to_local_id.entry(ast_node_id) { - Entry::Occupied(o) => HirId { owner: self.current_hir_id_owner, local_id: *o.get() }, - Entry::Vacant(v) => { - // Generate a new `HirId`. - let owner = self.current_hir_id_owner; - let local_id = self.item_local_id_counter; - let hir_id = HirId { owner, local_id }; - - v.insert(local_id); - self.item_local_id_counter.increment_by(1); + let owner = self.current_hir_id_owner; + let local_id = self.item_local_id_counter; + assert_ne!(local_id, hir::ItemLocalId::ZERO); + self.item_local_id_counter.increment_by(1); + let hir_id = HirId { owner, local_id }; - assert_ne!(local_id, hir::ItemLocalId::ZERO); - if let Some(def_id) = self.opt_local_def_id(ast_node_id) { - self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); - } + if let Some(def_id) = self.opt_local_def_id(ast_node_id) { + self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); + } - if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) { - self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice()); - } + if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) { + self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice()); + } - hir_id - } + // Check whether the same `NodeId` is lowered more than once. + #[cfg(debug_assertions)] + { + let old = self.node_id_to_local_id.insert(ast_node_id, local_id); + assert_eq!(old, None); } + + hir_id } /// Generate a new `HirId` without a backing `NodeId`. @@ -729,7 +671,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_res(&mut self, res: Res<NodeId>) -> Res { let res: Result<Res, ()> = res.apply_id(|id| { let owner = self.current_hir_id_owner; - let local_id = self.node_id_to_local_id.get(&id).copied().ok_or(())?; + let local_id = self.ident_and_label_to_local_id.get(&id).copied().ok_or(())?; Ok(HirId { owner, local_id }) }); trace!(?res); @@ -1474,7 +1416,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_opaque_impl_trait( &mut self, span: Span, - origin: hir::OpaqueTyOrigin, + origin: hir::OpaqueTyOrigin<LocalDefId>, opaque_ty_node_id: NodeId, bounds: &GenericBounds, itctx: ImplTraitContext, @@ -1486,27 +1428,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - // Whether this opaque always captures lifetimes in scope. - // Right now, this is all RPITIT and TAITs, and when `lifetime_capture_rules_2024` - // is enabled. We don't check the span of the edition, since this is done - // on a per-opaque basis to account for nested opaques. - let always_capture_in_scope = match origin { - _ if self.tcx.features().lifetime_capture_rules_2024() => true, - hir::OpaqueTyOrigin::TyAlias { .. } => true, - hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(), - hir::OpaqueTyOrigin::AsyncFn { .. } => { - unreachable!("should be using `lower_coroutine_fn_ret_ty`") - } - }; - let captured_lifetimes_to_duplicate = lifetime_collector::lifetimes_for_opaque( - self.resolver, - always_capture_in_scope, - opaque_ty_node_id, - bounds, - span, - ); - debug!(?captured_lifetimes_to_duplicate); - // Feature gate for RPITIT + use<..> match origin { rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => { @@ -1529,22 +1450,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => {} } - self.lower_opaque_inner( - opaque_ty_node_id, - origin, - captured_lifetimes_to_duplicate, - span, - opaque_ty_span, - |this| this.lower_param_bounds(bounds, itctx), - ) + self.lower_opaque_inner(opaque_ty_node_id, origin, opaque_ty_span, |this| { + this.lower_param_bounds(bounds, itctx) + }) } fn lower_opaque_inner( &mut self, opaque_ty_node_id: NodeId, - origin: hir::OpaqueTyOrigin, - captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>, - span: Span, + origin: hir::OpaqueTyOrigin<LocalDefId>, opaque_ty_span: Span, lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], ) -> hir::TyKind<'hir> { @@ -1552,145 +1466,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_hir_id = self.lower_node_id(opaque_ty_node_id); debug!(?opaque_ty_def_id, ?opaque_ty_hir_id); - // Map from captured (old) lifetime to synthetic (new) lifetime. - // Used to resolve lifetimes in the bounds of the opaque. - let mut captured_to_synthesized_mapping = LocalDefIdMap::default(); - // List of (early-bound) synthetic lifetimes that are owned by the opaque. - // This is used to create the `hir::Generics` owned by the opaque. - let mut synthesized_lifetime_definitions = vec![]; - // Pairs of lifetime arg (that resolves to the captured lifetime) - // and the def-id of the (early-bound) synthetic lifetime definition. - // This is used both to create generics for the `TyKind::OpaqueDef` that - // we return, and also as a captured lifetime mapping for RPITITs. - let mut synthesized_lifetime_args = vec![]; - - for lifetime in captured_lifetimes_to_duplicate { - let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error); - let (old_def_id, missing_kind) = match res { - LifetimeRes::Param { param: old_def_id, binder: _ } => (old_def_id, None), - - LifetimeRes::Fresh { param, kind, .. } => { - debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); - if let Some(old_def_id) = self.orig_opt_local_def_id(param) { - (old_def_id, Some(kind)) - } else { - self.dcx() - .span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime"); - continue; - } - } - - // Opaques do not capture `'static` - LifetimeRes::Static { .. } | LifetimeRes::Error => { - continue; - } - - res => { - let bug_msg = format!( - "Unexpected lifetime resolution {:?} for {:?} at {:?}", - res, lifetime.ident, lifetime.ident.span - ); - span_bug!(lifetime.ident.span, "{}", bug_msg); - } - }; - - if captured_to_synthesized_mapping.get(&old_def_id).is_none() { - // Create a new lifetime parameter local to the opaque. - let duplicated_lifetime_node_id = self.next_node_id(); - let duplicated_lifetime_def_id = self.create_def( - opaque_ty_def_id, - duplicated_lifetime_node_id, - lifetime.ident.name, - DefKind::LifetimeParam, - self.lower_span(lifetime.ident.span), - ); - captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id); - // FIXME: Instead of doing this, we could move this whole loop - // into the `with_hir_id_owner`, then just directly construct - // the `hir::GenericParam` here. - synthesized_lifetime_definitions.push(( - duplicated_lifetime_node_id, - duplicated_lifetime_def_id, - self.lower_ident(lifetime.ident), - missing_kind, - )); - - // Now make an arg that we can use for the generic params of the opaque tykind. - let id = self.next_node_id(); - let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res); - let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id); - synthesized_lifetime_args.push((lifetime_arg, duplicated_lifetime_def_id)) - } - } - let opaque_ty_def = self.with_def_id_parent(opaque_ty_def_id, |this| { - // Install the remapping from old to new (if any). This makes sure that - // any lifetimes that would have resolved to the def-id of captured - // lifetimes are remapped to the new *synthetic* lifetimes of the opaque. - let bounds = this - .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this)); - - let generic_params = - this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map( - |&(new_node_id, new_def_id, ident, missing_kind)| { - let hir_id = this.lower_node_id(new_node_id); - let (name, kind) = if ident.name == kw::UnderscoreLifetime { - ( - hir::ParamName::Fresh, - hir::LifetimeParamKind::Elided( - missing_kind.unwrap_or(MissingLifetimeKind::Underscore), - ), - ) - } else { - (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) - }; - - hir::GenericParam { - hir_id, - def_id: new_def_id, - name, - span: ident.span, - pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { kind }, - colon_span: None, - source: hir::GenericParamSource::Generics, - } - }, - )); - debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params); - - let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args); - - trace!("registering opaque type with id {:#?}", opaque_ty_def_id); + let bounds = lower_item_bounds(this); let opaque_ty_def = hir::OpaqueTy { hir_id: opaque_ty_hir_id, def_id: opaque_ty_def_id, - generics: this.arena.alloc(hir::Generics { - params: generic_params, - predicates: &[], - has_where_clause_predicates: false, - where_clause_span: this.lower_span(span), - span: this.lower_span(span), - }), bounds, origin, - lifetime_mapping, span: this.lower_span(opaque_ty_span), }; this.arena.alloc(opaque_ty_def) }); - let generic_args = self.arena.alloc_from_iter( - synthesized_lifetime_args - .iter() - .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), - ); - - // Create the `Foo<...>` reference itself. Note that the `type - // Foo = impl Trait` is, internally, created as a child of the - // async fn, so the *type parameters* are inherited. It's - // only the lifetime parameters that we must supply. - hir::TyKind::OpaqueDef(opaque_ty_def, generic_args) + hir::TyKind::OpaqueDef(opaque_ty_def) } fn lower_precise_capturing_args( @@ -1865,20 +1653,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None), CoroutineKind::Gen { return_impl_trait_id, .. } => (return_impl_trait_id, None), CoroutineKind::AsyncGen { return_impl_trait_id, .. } => { - (return_impl_trait_id, Some(self.allow_async_iterator.clone())) + (return_impl_trait_id, Some(Lrc::clone(&self.allow_async_iterator))) } }; let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, allowed_features); - let captured_lifetimes = self - .resolver - .extra_lifetime_params(opaque_ty_node_id) - .into_iter() - .map(|(ident, id, _)| Lifetime { id, ident }) - .collect(); - let in_trait_or_impl = match fn_kind { FnDeclKind::Trait => Some(hir::RpitContext::Trait), FnDeclKind::Impl => Some(hir::RpitContext::TraitImpl), @@ -1889,8 +1670,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_ref = self.lower_opaque_inner( opaque_ty_node_id, hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl }, - captured_lifetimes, - span, opaque_ty_span, |this| { let bound = this.lower_coroutine_fn_output_type_to_bound( @@ -1987,10 +1766,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { res: LifetimeRes, ) -> &'hir hir::Lifetime { let res = match res { - LifetimeRes::Param { param, .. } => { - let param = self.get_remapped_def_id(param); - hir::LifetimeName::Param(param) - } + LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param), LifetimeRes::Fresh { param, .. } => { let param = self.local_def_id(param); hir::LifetimeName::Param(param) diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs deleted file mode 100644 index 8d47c856bdd..00000000000 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ /dev/null @@ -1,151 +0,0 @@ -use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor}; -use rustc_ast::{ - GenericBound, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind, -}; -use rustc_data_structures::fx::FxIndexSet; -use rustc_hir::def::{DefKind, LifetimeRes, Res}; -use rustc_middle::span_bug; -use rustc_middle::ty::ResolverAstLowering; -use rustc_span::Span; -use rustc_span::symbol::{Ident, kw}; - -use super::ResolverAstLoweringExt; - -struct LifetimeCollectVisitor<'ast> { - resolver: &'ast mut ResolverAstLowering, - always_capture_in_scope: bool, - current_binders: Vec<NodeId>, - collected_lifetimes: FxIndexSet<Lifetime>, -} - -impl<'ast> LifetimeCollectVisitor<'ast> { - fn new(resolver: &'ast mut ResolverAstLowering, always_capture_in_scope: bool) -> Self { - Self { - resolver, - always_capture_in_scope, - current_binders: Vec::new(), - collected_lifetimes: FxIndexSet::default(), - } - } - - fn visit_opaque(&mut self, opaque_ty_node_id: NodeId, bounds: &'ast GenericBounds, span: Span) { - // If we're edition 2024 or within a TAIT or RPITIT, *and* there is no - // `use<>` statement to override the default capture behavior, then - // capture all of the in-scope lifetimes. - if (self.always_capture_in_scope || span.at_least_rust_2024()) - && bounds.iter().all(|bound| !matches!(bound, GenericBound::Use(..))) - { - for (ident, id, _) in self.resolver.extra_lifetime_params(opaque_ty_node_id) { - self.record_lifetime_use(Lifetime { id, ident }); - } - } - - // We also recurse on the bounds to make sure we capture all the lifetimes - // mentioned in the bounds. These may disagree with the `use<>` list, in which - // case we will error on these later. We will also recurse to visit any - // nested opaques, which may *implicitly* capture lifetimes. - for bound in bounds { - self.visit_param_bound(bound, BoundKind::Bound); - } - } - - fn record_lifetime_use(&mut self, lifetime: Lifetime) { - match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) { - LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => { - if !self.current_binders.contains(&binder) { - self.collected_lifetimes.insert(lifetime); - } - } - LifetimeRes::Static { .. } | LifetimeRes::Error => { - self.collected_lifetimes.insert(lifetime); - } - LifetimeRes::Infer => {} - res => { - let bug_msg = format!( - "Unexpected lifetime resolution {:?} for {:?} at {:?}", - res, lifetime.ident, lifetime.ident.span - ); - span_bug!(lifetime.ident.span, "{}", bug_msg); - } - } - } - - /// This collect lifetimes that are elided, for nodes like `Foo<T>` where there are no explicit - /// lifetime nodes. Is equivalent to having "pseudo" nodes introduced for each of the node ids - /// in the list start..end. - fn record_elided_anchor(&mut self, node_id: NodeId, span: Span) { - if let Some(LifetimeRes::ElidedAnchor { start, end }) = - self.resolver.get_lifetime_res(node_id) - { - for i in start..end { - let lifetime = Lifetime { id: i, ident: Ident::new(kw::UnderscoreLifetime, span) }; - self.record_lifetime_use(lifetime); - } - } - } -} - -impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> { - fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) { - self.record_lifetime_use(*lifetime); - } - - fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) { - self.record_elided_anchor(path_segment.id, path_segment.ident.span); - visit::walk_path_segment(self, path_segment); - } - - fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) { - self.current_binders.push(t.trait_ref.ref_id); - - visit::walk_poly_trait_ref(self, t); - - self.current_binders.pop(); - } - - fn visit_ty(&mut self, t: &'ast Ty) { - match &t.kind { - TyKind::Path(None, _) => { - // We can sometimes encounter bare trait objects - // which are represented in AST as paths. - if let Some(partial_res) = self.resolver.get_partial_res(t.id) - && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = - partial_res.full_res() - { - self.current_binders.push(t.id); - visit::walk_ty(self, t); - self.current_binders.pop(); - } else { - visit::walk_ty(self, t); - } - } - TyKind::BareFn(_) => { - self.current_binders.push(t.id); - visit::walk_ty(self, t); - self.current_binders.pop(); - } - TyKind::Ref(None, _) | TyKind::PinnedRef(None, _) => { - self.record_elided_anchor(t.id, t.span); - visit::walk_ty(self, t); - } - TyKind::ImplTrait(opaque_ty_node_id, bounds) => { - self.visit_opaque(*opaque_ty_node_id, bounds, t.span) - } - _ => { - visit::walk_ty(self, t); - } - } - } -} - -pub(crate) fn lifetimes_for_opaque( - resolver: &mut ResolverAstLowering, - always_capture_in_scope: bool, - opaque_ty_node_id: NodeId, - bounds: &GenericBounds, - span: Span, -) -> FxIndexSet<Lifetime> { - let mut visitor = LifetimeCollectVisitor::new(resolver, always_capture_in_scope); - visitor.visit_opaque(opaque_ty_node_id, bounds, span); - visitor.collected_lifetimes -} diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 760f84564f1..ace7bfb5c73 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -21,13 +21,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> { ensure_sufficient_stack(|| { // loop here to avoid recursion + let pat_hir_id = self.lower_node_id(pattern.id); let node = loop { match &pattern.kind { PatKind::Wild => break hir::PatKind::Wild, PatKind::Never => break hir::PatKind::Never, PatKind::Ident(binding_mode, ident, sub) => { let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s)); - break self.lower_pat_ident(pattern, *binding_mode, *ident, lower_sub); + break self.lower_pat_ident( + pattern, + *binding_mode, + *ident, + pat_hir_id, + lower_sub, + ); } PatKind::Lit(e) => { break hir::PatKind::Lit(self.lower_expr_within_pat(e, false)); @@ -119,7 +126,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }; - self.pat_with_node_id_of(pattern, node) + self.pat_with_node_id_of(pattern, node, pat_hir_id) }) } @@ -187,10 +194,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut prev_rest_span = None; // Lowers `$bm $ident @ ..` to `$bm $ident @ _`. - let lower_rest_sub = |this: &mut Self, pat, &ann, &ident, sub| { - let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub)); - let node = this.lower_pat_ident(pat, ann, ident, lower_sub); - this.pat_with_node_id_of(pat, node) + let lower_rest_sub = |this: &mut Self, pat: &Pat, &ann, &ident, sub: &Pat| { + let sub_hir_id = this.lower_node_id(sub.id); + let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub, sub_hir_id)); + let pat_hir_id = this.lower_node_id(pat.id); + let node = this.lower_pat_ident(pat, ann, ident, pat_hir_id, lower_sub); + this.pat_with_node_id_of(pat, node, pat_hir_id) }; let mut iter = pats.iter(); @@ -200,7 +209,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here. PatKind::Rest => { prev_rest_span = Some(pat.span); - slice = Some(self.pat_wild_with_node_id_of(pat)); + let hir_id = self.lower_node_id(pat.id); + slice = Some(self.pat_wild_with_node_id_of(pat, hir_id)); break; } // Found a sub-slice pattern `$binding_mode $ident @ ..`. @@ -248,19 +258,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &Pat, annotation: BindingMode, ident: Ident, + hir_id: hir::HirId, lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>, ) -> hir::PatKind<'hir> { match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) { // `None` can occur in body-less function signatures res @ (None | Some(Res::Local(_))) => { - let canonical_id = match res { - Some(Res::Local(id)) => id, - _ => p.id, + let binding_id = match res { + Some(Res::Local(id)) => { + // In `Or` patterns like `VariantA(s) | VariantB(s, _)`, multiple identifier patterns + // will be resolved to the same `Res::Local`. Thus they just share a single + // `HirId`. + if id == p.id { + self.ident_and_label_to_local_id.insert(id, hir_id.local_id); + hir_id + } else { + hir::HirId { + owner: self.current_hir_id_owner, + local_id: self.ident_and_label_to_local_id[&id], + } + } + } + _ => { + self.ident_and_label_to_local_id.insert(p.id, hir_id.local_id); + hir_id + } }; - hir::PatKind::Binding( annotation, - self.lower_node_id(canonical_id), + binding_id, self.lower_ident(ident), lower_sub(self), ) @@ -280,18 +306,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { - self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild)) + fn pat_wild_with_node_id_of(&mut self, p: &Pat, hir_id: hir::HirId) -> &'hir hir::Pat<'hir> { + self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild, hir_id)) } - /// Construct a `Pat` with the `HirId` of `p.id` lowered. - fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> { - hir::Pat { - hir_id: self.lower_node_id(p.id), - kind, - span: self.lower_span(p.span), - default_binding_modes: true, - } + /// Construct a `Pat` with the `HirId` of `p.id` already lowered. + fn pat_with_node_id_of( + &mut self, + p: &Pat, + kind: hir::PatKind<'hir>, + hir_id: hir::HirId, + ) -> hir::Pat<'hir> { + hir::Pat { hir_id, kind, span: self.lower_span(p.span), default_binding_modes: true } } /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern. diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 6a0f03c8b31..133793e26ea 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -73,7 +73,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let bound_modifier_allowed_features = if let Res::Def(DefKind::Trait, async_def_id) = res && self.tcx.async_fn_trait_kind_from_def_id(async_def_id).is_some() { - Some(self.allow_async_fn_traits.clone()) + Some(Lrc::clone(&self.allow_async_fn_traits)) } else { None }; diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 0a4f86d4822..dee48586f34 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -677,9 +677,8 @@ impl<'a> AstValidator<'a> { Self::check_decl_no_pat(&bfty.decl, |span, _, _| { self.dcx().emit_err(errors::PatternFnPointer { span }); }); - if let Extern::Implicit(_) = bfty.ext { - let sig_span = self.sess.source_map().next_point(ty.span.shrink_to_lo()); - self.maybe_lint_missing_abi(sig_span, ty.id); + if let Extern::Implicit(extern_span) = bfty.ext { + self.maybe_lint_missing_abi(extern_span, ty.id); } } TyKind::TraitObject(bounds, ..) => { @@ -953,7 +952,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. } - ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => { + ItemKind::ForeignMod(ForeignMod { extern_span, abi, safety, .. }) => { self.with_in_extern_mod(*safety, |this| { let old_item = mem::replace(&mut this.extern_mod, Some(item.span)); this.visibility_not_permitted( @@ -977,7 +976,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } if abi.is_none() { - this.maybe_lint_missing_abi(item.span, item.id); + this.maybe_lint_missing_abi(*extern_span, item.id); } visit::walk_item(this, item); this.extern_mod = old_item; @@ -1350,13 +1349,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let FnKind::Fn( _, _, - FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. }, + FnSig { header: FnHeader { ext: Extern::Implicit(extern_span), .. }, .. }, _, _, _, ) = fk { - self.maybe_lint_missing_abi(*sig_span, id); + self.maybe_lint_missing_abi(*extern_span, id); } // Functions without bodies cannot have patterns. diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index 9ae5c9b3cec..f290fedcd8b 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start itertools = "0.12" rustc_ast = { path = "../rustc_ast" } +rustc_data_structures = { path = "../rustc_data_structures" } rustc_lexer = { path = "../rustc_lexer" } rustc_span = { path = "../rustc_span" } thin-vec = "0.2.12" diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 1e18f0779f0..de9f5187be7 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -21,6 +21,7 @@ use rustc_ast::{ GenericBound, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece, PatKind, RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr, }; +use rustc_data_structures::sync::Lrc; use rustc_span::edition::Edition; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{Ident, IdentPrinter, Symbol, kw, sym}; @@ -105,7 +106,7 @@ fn split_block_comment_into_lines(text: &str, col: CharPos) -> Vec<String> { fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comment> { let sm = SourceMap::new(sm.path_mapping().clone()); let source_file = sm.new_source_file(path, src); - let text = (*source_file.src.as_ref().unwrap()).clone(); + let text = Lrc::clone(&(*source_file.src.as_ref().unwrap())); let text: &str = text.as_str(); let start_bpos = source_file.start_pos; diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index c687be69b1a..511313cca6f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1489,6 +1489,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { &borrow_msg, &value_msg, ); + self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err); borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow); @@ -1524,7 +1525,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { matches!( adj.kind, ty::adjustment::Adjust::Borrow(ty::adjustment::AutoBorrow::Ref( - _, ty::adjustment::AutoBorrowMutability::Not | ty::adjustment::AutoBorrowMutability::Mut { allow_two_phase_borrow: ty::adjustment::AllowTwoPhase::No @@ -1561,6 +1561,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { borrow_span, &self.describe_any_place(borrow.borrowed_place.as_ref()), ); + self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err); + borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; let place = &borrow.borrowed_place; @@ -1820,6 +1822,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { unreachable!() } }; + self.note_due_to_edition_2024_opaque_capture_rules(issued_borrow, &mut err); if issued_spans == borrow_spans { borrow_spans.var_subdiag(&mut err, Some(gen_borrow_kind), |kind, var_span| { @@ -2860,7 +2863,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { debug!(?place_desc, ?explanation); - let err = match (place_desc, explanation) { + let mut err = match (place_desc, explanation) { // If the outlives constraint comes from inside the closure, // for example: // @@ -2939,6 +2942,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { explanation, ), }; + self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err); self.buffer_error(err); } @@ -3777,6 +3781,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place); + self.note_due_to_edition_2024_opaque_capture_rules(loan, &mut err); loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 801c7af2de7..3b600716036 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -48,6 +48,7 @@ mod conflict_errors; mod explain_borrow; mod move_errors; mod mutability_errors; +mod opaque_suggestions; mod region_errors; pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo}; diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs new file mode 100644 index 00000000000..bfd7e83501c --- /dev/null +++ b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs @@ -0,0 +1,224 @@ +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + +use std::ops::ControlFlow; + +use either::Either; +use rustc_data_structures::fx::FxIndexSet; +use rustc_errors::{Applicability, Diag}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_middle::mir::{self, ConstraintCategory, Location}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, +}; +use rustc_span::Symbol; + +use crate::MirBorrowckCtxt; +use crate::borrow_set::BorrowData; +use crate::consumers::RegionInferenceContext; +use crate::type_check::Locations; + +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { + /// Try to note when an opaque is involved in a borrowck error and that + /// opaque captures lifetimes due to edition 2024. + // FIXME: This code is otherwise somewhat general, and could easily be adapted + // to explain why other things overcapture... like async fn and RPITITs. + pub(crate) fn note_due_to_edition_2024_opaque_capture_rules( + &self, + borrow: &BorrowData<'tcx>, + diag: &mut Diag<'_>, + ) { + // We look at all the locals. Why locals? Because it's the best thing + // I could think of that's correlated with the *instantiated* higer-ranked + // binder for calls, since we don't really store those anywhere else. + for ty in self.body.local_decls.iter().map(|local| local.ty) { + if !ty.has_opaque_types() { + continue; + } + + let tcx = self.infcx.tcx; + let ControlFlow::Break((opaque_def_id, offending_region_idx, location)) = ty + .visit_with(&mut FindOpaqueRegion { + regioncx: &self.regioncx, + tcx, + borrow_region: borrow.region, + }) + else { + continue; + }; + + // If an opaque explicitly captures a lifetime, then no need to point it out. + // FIXME: We should be using a better heuristic for `use<>`. + if tcx.rendered_precise_capturing_args(opaque_def_id).is_some() { + continue; + } + + // If one of the opaque's bounds mentions the region, then no need to + // point it out, since it would've been captured on edition 2021 as well. + // + // Also, while we're at it, collect all the lifetimes that the opaque + // *does* mention. We'll use that for the `+ use<'a>` suggestion below. + let mut visitor = CheckExplicitRegionMentionAndCollectGenerics { + tcx, + offending_region_idx, + seen_opaques: [opaque_def_id].into_iter().collect(), + seen_lifetimes: Default::default(), + }; + if tcx + .explicit_item_bounds(opaque_def_id) + .skip_binder() + .visit_with(&mut visitor) + .is_break() + { + continue; + } + + // If we successfully located a terminator, then point it out + // and provide a suggestion if it's local. + match self.body.stmt_at(location) { + Either::Right(mir::Terminator { source_info, .. }) => { + diag.span_note( + source_info.span, + "this call may capture more lifetimes than intended, \ + because Rust 2024 has adjusted the `impl Trait` lifetime capture rules", + ); + let mut seen_generics: Vec<_> = + visitor.seen_lifetimes.iter().map(ToString::to_string).collect(); + // Capture all in-scope ty/const params. + seen_generics.extend( + ty::GenericArgs::identity_for_item(tcx, opaque_def_id) + .iter() + .filter(|arg| { + matches!( + arg.unpack(), + ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_) + ) + }) + .map(|arg| arg.to_string()), + ); + if opaque_def_id.is_local() { + diag.span_suggestion_verbose( + tcx.def_span(opaque_def_id).shrink_to_hi(), + "add a precise capturing bound to avoid overcapturing", + format!(" + use<{}>", seen_generics.join(", ")), + Applicability::MaybeIncorrect, + ); + } else { + diag.span_help( + tcx.def_span(opaque_def_id), + format!( + "if you can modify this crate, add a precise \ + capturing bound to avoid overcapturing: `+ use<{}>`", + seen_generics.join(", ") + ), + ); + } + return; + } + Either::Left(_) => {} + } + } + } +} + +/// This visitor contains the bulk of the logic for this lint. +struct FindOpaqueRegion<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + regioncx: &'a RegionInferenceContext<'tcx>, + borrow_region: ty::RegionVid, +} + +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindOpaqueRegion<'_, 'tcx> { + type Result = ControlFlow<(DefId, usize, Location), ()>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + // If we find an opaque in a local ty, then for each of its captured regions, + // try to find a path between that captured regions and our borrow region... + if let ty::Alias(ty::Opaque, opaque) = *ty.kind() + && let hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl: None } = + self.tcx.opaque_ty_origin(opaque.def_id) + { + let variances = self.tcx.variances_of(opaque.def_id); + for (idx, (arg, variance)) in std::iter::zip(opaque.args, variances).enumerate() { + // Skip uncaptured args. + if *variance == ty::Bivariant { + continue; + } + // We only care about regions. + let Some(opaque_region) = arg.as_region() else { + continue; + }; + // Don't try to convert a late-bound region, which shouldn't exist anyways (yet). + if opaque_region.is_bound() { + continue; + } + let opaque_region_vid = self.regioncx.to_region_vid(opaque_region); + + // Find a path between the borrow region and our opaque capture. + if let Some((path, _)) = + self.regioncx.find_constraint_paths_between_regions(self.borrow_region, |r| { + r == opaque_region_vid + }) + { + for constraint in path { + // If we find a call in this path, then check if it defines the opaque. + if let ConstraintCategory::CallArgument(Some(call_ty)) = constraint.category + && let ty::FnDef(call_def_id, _) = *call_ty.kind() + // This function defines the opaque :D + && call_def_id == parent + && let Locations::Single(location) = constraint.locations + { + return ControlFlow::Break((opaque.def_id, idx, location)); + } + } + } + } + } + + ty.super_visit_with(self) + } +} + +struct CheckExplicitRegionMentionAndCollectGenerics<'tcx> { + tcx: TyCtxt<'tcx>, + offending_region_idx: usize, + seen_opaques: FxIndexSet<DefId>, + seen_lifetimes: FxIndexSet<Symbol>, +} + +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGenerics<'tcx> { + type Result = ControlFlow<(), ()>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + match *ty.kind() { + ty::Alias(ty::Opaque, opaque) => { + if self.seen_opaques.insert(opaque.def_id) { + for (bound, _) in self + .tcx + .explicit_item_bounds(opaque.def_id) + .iter_instantiated_copied(self.tcx, opaque.args) + { + bound.visit_with(self)?; + } + } + ControlFlow::Continue(()) + } + _ => ty.super_visit_with(self), + } + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result { + match r.kind() { + ty::ReEarlyParam(param) => { + if param.index as usize == self.offending_region_idx { + ControlFlow::Break(()) + } else { + self.seen_lifetimes.insert(param.name); + ControlFlow::Continue(()) + } + } + _ => ControlFlow::Continue(()), + } + } +} diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index b4b8373ac97..6ca7251295d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -830,7 +830,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { /// /// [`OpaqueDef`]: hir::TyKind::OpaqueDef fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { - let hir::TyKind::OpaqueDef(opaque_ty, _) = hir_ty.kind else { + let hir::TyKind::OpaqueDef(opaque_ty) = hir_ty.kind else { span_bug!( hir_ty.span, "lowered return type of async fn is not OpaqueDef: {:?}", diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 698fdafc936..efcee2899c6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -34,7 +34,7 @@ use rustc_infer::infer::{ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::*; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt}; +use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::{ @@ -193,9 +193,7 @@ fn do_mir_borrowck<'tcx>( .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true))); let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, Some("borrowck")) .into_results_cursor(body); let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure(); @@ -243,18 +241,21 @@ fn do_mir_borrowck<'tcx>( // usage significantly on some benchmarks. drop(flow_inits); - let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint(); - let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint(); - let flow_ever_inits = EverInitializedPlaces::new(body, &move_data) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint(); + let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set).iterate_to_fixpoint( + tcx, + body, + Some("borrowck"), + ); + let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint( + tcx, + body, + Some("borrowck"), + ); + let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint( + tcx, + body, + Some("borrowck"), + ); let movable_coroutine = // The first argument is the coroutine type passed by value @@ -440,7 +441,7 @@ pub struct BorrowckInferCtxt<'tcx> { impl<'tcx> BorrowckInferCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { - let infcx = tcx.infer_ctxt().with_opaque_type_inference(def_id).build(); + let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id)); BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) } } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 3674053409b..f76603d5679 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -107,13 +107,13 @@ pub(crate) fn compute_regions<'a, 'tcx>( param_env, body, promoted, - universal_regions.clone(), + Rc::clone(&universal_regions), location_table, borrow_set, &mut all_facts, flow_inits, move_data, - elements.clone(), + Rc::clone(&elements), upvars, ); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index e85f529bf0e..d5c2796932e 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -733,7 +733,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Now take member constraints into account. - let member_constraints = self.member_constraints.clone(); + let member_constraints = Rc::clone(&self.member_constraints); for m_c_i in member_constraints.indices(scc_a) { self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i)); } @@ -1679,7 +1679,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx: &InferCtxt<'tcx>, errors_buffer: &mut RegionErrors<'tcx>, ) { - let member_constraints = self.member_constraints.clone(); + let member_constraints = Rc::clone(&self.member_constraints); for m_c_i in member_constraints.all_indices() { debug!(?m_c_i); let m_c = &member_constraints[m_c_i]; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index abce98265b3..3a2f5c35c72 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -9,6 +9,7 @@ use rustc_macros::extension; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ self, GenericArgKind, GenericArgs, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, + TypingMode, }; use rustc_span::Span; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -340,14 +341,13 @@ fn check_opaque_type_well_formed<'tcx>( parent_def_id = tcx.local_parent(parent_def_id); } - // FIXME(-Znext-solver): We probably should use `&[]` instead of - // and prepopulate this `InferCtxt` with known opaque values, rather than - // allowing opaque types to be defined and checking them after the fact. + // FIXME(#132279): This should eventually use the already defined hidden types + // instead. Alternatively we'll entirely remove this function given we also check + // the opaque in `check_opaque_meets_bounds` later. let infcx = tcx .infer_ctxt() .with_next_trait_solver(next_trait_solver) - .with_opaque_type_inference(parent_def_id) - .build(); + .build(TypingMode::analysis_in_body(tcx, parent_def_id)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let identity_args = GenericArgs::identity_for_item(tcx, def_id); @@ -502,7 +502,7 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> { } let &Self { tcx, def_id, .. } = self; - let origin = tcx.opaque_type_origin(def_id); + let origin = tcx.local_opaque_ty_origin(def_id); let parent = match origin { hir::OpaqueTyOrigin::FnReturn { parent, .. } | hir::OpaqueTyOrigin::AsyncFn { parent, .. } @@ -517,7 +517,9 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> { }, ); - let infcx = tcx.infer_ctxt().build(); + // FIXME(#132279): It feels wrong to use `non_body_analysis` here given that we're + // in a body here. + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new(&infcx); let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index a544d88e832..26919bfd488 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -134,7 +134,7 @@ pub(crate) fn type_check<'a, 'tcx>( let mut constraints = MirTypeckRegionConstraints { placeholder_indices: PlaceholderIndices::default(), placeholder_index_to_region: IndexVec::default(), - liveness_constraints: LivenessValues::with_specific_points(elements.clone()), + liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&elements)), outlives_constraints: OutlivesConstraintSet::default(), member_constraints: MemberConstraintSet::default(), type_tests: Vec::default(), @@ -150,7 +150,7 @@ pub(crate) fn type_check<'a, 'tcx>( infcx, param_env, implicit_region_bound, - universal_regions.clone(), + Rc::clone(&universal_regions), &mut constraints, ); diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 892ec3e9585..089b09d06ae 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -193,7 +193,7 @@ fn make_local_place<'tcx>( ); } let place = if is_ssa { - if let rustc_target::abi::Abi::ScalarPair(_, _) = layout.abi { + if let BackendRepr::ScalarPair(_, _) = layout.backend_repr { CPlace::new_var_pair(fx, local, layout) } else { CPlace::new_var(fx, local, layout) diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 38c322b5e04..ad0a13dc7e5 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -78,19 +78,19 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]> { match self.mode { PassMode::Ignore => smallvec![], - PassMode::Direct(attrs) => match self.layout.abi { - Abi::Scalar(scalar) => smallvec![apply_arg_attrs_to_abi_param( + PassMode::Direct(attrs) => match self.layout.backend_repr { + BackendRepr::Scalar(scalar) => smallvec![apply_arg_attrs_to_abi_param( AbiParam::new(scalar_to_clif_type(tcx, scalar)), attrs )], - Abi::Vector { .. } => { + BackendRepr::Vector { .. } => { let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout); smallvec![AbiParam::new(vector_ty)] } - _ => unreachable!("{:?}", self.layout.abi), + _ => unreachable!("{:?}", self.layout.backend_repr), }, - PassMode::Pair(attrs_a, attrs_b) => match self.layout.abi { - Abi::ScalarPair(a, b) => { + PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr { + BackendRepr::ScalarPair(a, b) => { let a = scalar_to_clif_type(tcx, a); let b = scalar_to_clif_type(tcx, b); smallvec![ @@ -98,7 +98,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b), ] } - _ => unreachable!("{:?}", self.layout.abi), + _ => unreachable!("{:?}", self.layout.backend_repr), }, PassMode::Cast { ref cast, pad_i32 } => { assert!(!pad_i32, "padding support not yet implemented"); @@ -130,23 +130,23 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>) { match self.mode { PassMode::Ignore => (None, vec![]), - PassMode::Direct(_) => match self.layout.abi { - Abi::Scalar(scalar) => { + PassMode::Direct(_) => match self.layout.backend_repr { + BackendRepr::Scalar(scalar) => { (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))]) } - Abi::Vector { .. } => { + BackendRepr::Vector { .. } => { let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout); (None, vec![AbiParam::new(vector_ty)]) } - _ => unreachable!("{:?}", self.layout.abi), + _ => unreachable!("{:?}", self.layout.backend_repr), }, - PassMode::Pair(_, _) => match self.layout.abi { - Abi::ScalarPair(a, b) => { + PassMode::Pair(_, _) => match self.layout.backend_repr { + BackendRepr::ScalarPair(a, b) => { let a = scalar_to_clif_type(tcx, a); let b = scalar_to_clif_type(tcx, b); (None, vec![AbiParam::new(a), AbiParam::new(b)]) } - _ => unreachable!("{:?}", self.layout.abi), + _ => unreachable!("{:?}", self.layout.backend_repr), }, PassMode::Cast { ref cast, .. } => { (None, cast_target_to_abi_params(cast).into_iter().collect()) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index a681e6d9f3c..99e39971b74 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -290,7 +290,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { let arg_uninhabited = fx .mir .args_iter() - .any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).abi.is_uninhabited()); + .any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).is_uninhabited()); if arg_uninhabited { fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]); fx.bcx.switch_to_block(fx.block_map[START_BLOCK]); @@ -644,9 +644,9 @@ fn codegen_stmt<'tcx>( _ => unreachable!("un op Neg for {:?}", layout.ty), } } - UnOp::PtrMetadata => match layout.abi { - Abi::Scalar(_) => CValue::zst(dest_layout), - Abi::ScalarPair(_, _) => { + UnOp::PtrMetadata => match layout.backend_repr { + BackendRepr::Scalar(_) => CValue::zst(dest_layout), + BackendRepr::ScalarPair(_, _) => { CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout) } _ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"), diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index d462dcd63a9..45794a42665 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -14,7 +14,7 @@ pub(crate) fn codegen_set_discriminant<'tcx>( variant_index: VariantIdx, ) { let layout = place.layout(); - if layout.for_variant(fx, variant_index).abi.is_uninhabited() { + if layout.for_variant(fx, variant_index).is_uninhabited() { return; } match layout.variants { @@ -80,7 +80,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>( ) { let layout = value.layout(); - if layout.abi.is_uninhabited() { + if layout.is_uninhabited() { return; } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 35f0ccff3f9..aae6794891d 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -51,8 +51,8 @@ fn report_atomic_type_validation_error<'tcx>( } pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Type { - let (element, count) = match layout.abi { - Abi::Vector { element, count } => (element, count), + let (element, count) = match layout.backend_repr { + BackendRepr::Vector { element, count } => (element, count), _ => unreachable!(), }; @@ -505,7 +505,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = fx.layout_of(generic_args.type_at(0)); // Note: Can't use is_unsized here as truly unsized types need to take the fixed size // branch - let meta = if let Abi::ScalarPair(_, _) = ptr.layout().abi { + let meta = if let BackendRepr::ScalarPair(_, _) = ptr.layout().backend_repr { Some(ptr.load_scalar_pair(fx).1) } else { None @@ -519,7 +519,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = fx.layout_of(generic_args.type_at(0)); // Note: Can't use is_unsized here as truly unsized types need to take the fixed size // branch - let meta = if let Abi::ScalarPair(_, _) = ptr.layout().abi { + let meta = if let BackendRepr::ScalarPair(_, _) = ptr.layout().backend_repr { Some(ptr.load_scalar_pair(fx).1) } else { None @@ -693,7 +693,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = fx.layout_of(ty); let msg_str = with_no_visible_paths!({ with_no_trimmed_paths!({ - if layout.abi.is_uninhabited() { + if layout.is_uninhabited() { // Use this error even for the other intrinsics as it is more precise. format!("attempted to instantiate uninhabited type `{}`", ty) } else if intrinsic == sym::assert_zero_valid { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index b6f9ce8fc29..602b1b98200 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -92,6 +92,7 @@ mod prelude { StackSlotData, StackSlotKind, TrapCode, Type, Value, types, }; pub(crate) use cranelift_module::{self, DataDescription, FuncId, Linkage, Module}; + pub(crate) use rustc_abi::{BackendRepr, FIRST_VARIANT, FieldIdx, Scalar, Size, VariantIdx}; pub(crate) use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE}; pub(crate) use rustc_index::Idx; @@ -101,7 +102,6 @@ mod prelude { self, FloatTy, Instance, InstanceKind, IntTy, ParamEnv, Ty, TyCtxt, UintTy, }; pub(crate) use rustc_span::Span; - pub(crate) use rustc_target::abi::{Abi, FIRST_VARIANT, FieldIdx, Scalar, Size, VariantIdx}; pub(crate) use crate::abi::*; pub(crate) use crate::base::{codegen_operand, codegen_place}; diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index fd77502224e..900d7e69714 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -131,8 +131,8 @@ impl<'tcx> CValue<'tcx> { match self.0 { CValueInner::ByRef(ptr, None) => { - let (a_scalar, b_scalar) = match self.1.abi { - Abi::ScalarPair(a, b) => (a, b), + let (a_scalar, b_scalar) = match self.1.backend_repr { + BackendRepr::ScalarPair(a, b) => (a, b), _ => unreachable!("dyn_star_force_data_on_stack({:?})", self), }; let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); @@ -164,15 +164,15 @@ impl<'tcx> CValue<'tcx> { } } - /// Load a value with layout.abi of scalar + /// Load a value with layout.backend_repr of scalar #[track_caller] pub(crate) fn load_scalar(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> Value { let layout = self.1; match self.0 { CValueInner::ByRef(ptr, None) => { - let clif_ty = match layout.abi { - Abi::Scalar(scalar) => scalar_to_clif_type(fx.tcx, scalar), - Abi::Vector { element, count } => scalar_to_clif_type(fx.tcx, element) + let clif_ty = match layout.backend_repr { + BackendRepr::Scalar(scalar) => scalar_to_clif_type(fx.tcx, scalar), + BackendRepr::Vector { element, count } => scalar_to_clif_type(fx.tcx, element) .by(u32::try_from(count).unwrap()) .unwrap(), _ => unreachable!("{:?}", layout.ty), @@ -187,14 +187,14 @@ impl<'tcx> CValue<'tcx> { } } - /// Load a value pair with layout.abi of scalar pair + /// Load a value pair with layout.backend_repr of scalar pair #[track_caller] pub(crate) fn load_scalar_pair(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> (Value, Value) { let layout = self.1; match self.0 { CValueInner::ByRef(ptr, None) => { - let (a_scalar, b_scalar) = match layout.abi { - Abi::ScalarPair(a, b) => (a, b), + let (a_scalar, b_scalar) = match layout.backend_repr { + BackendRepr::ScalarPair(a, b) => (a, b), _ => unreachable!("load_scalar_pair({:?})", self), }; let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); @@ -222,8 +222,8 @@ impl<'tcx> CValue<'tcx> { let layout = self.1; match self.0 { CValueInner::ByVal(_) => unreachable!(), - CValueInner::ByValPair(val1, val2) => match layout.abi { - Abi::ScalarPair(_, _) => { + CValueInner::ByValPair(val1, val2) => match layout.backend_repr { + BackendRepr::ScalarPair(_, _) => { let val = match field.as_u32() { 0 => val1, 1 => val2, @@ -232,7 +232,7 @@ impl<'tcx> CValue<'tcx> { let field_layout = layout.field(&*fx, usize::from(field)); CValue::by_val(val, field_layout) } - _ => unreachable!("value_field for ByValPair with abi {:?}", layout.abi), + _ => unreachable!("value_field for ByValPair with abi {:?}", layout.backend_repr), }, CValueInner::ByRef(ptr, None) => { let (field_ptr, field_layout) = codegen_field(fx, ptr, None, layout, field); @@ -360,7 +360,7 @@ impl<'tcx> CValue<'tcx> { pub(crate) fn cast_pointer_to(self, layout: TyAndLayout<'tcx>) -> Self { assert!(matches!(self.layout().ty.kind(), ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..))); assert!(matches!(layout.ty.kind(), ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..))); - assert_eq!(self.layout().abi, layout.abi); + assert_eq!(self.layout().backend_repr, layout.backend_repr); CValue(self.0, layout) } } @@ -609,8 +609,8 @@ impl<'tcx> CPlace<'tcx> { let dst_layout = self.layout(); match self.inner { CPlaceInner::Var(_local, var) => { - let data = match from.1.abi { - Abi::Scalar(_) => CValue(from.0, dst_layout).load_scalar(fx), + let data = match from.1.backend_repr { + BackendRepr::Scalar(_) => CValue(from.0, dst_layout).load_scalar(fx), _ => { let (ptr, meta) = from.force_stack(fx); assert!(meta.is_none()); @@ -621,8 +621,10 @@ impl<'tcx> CPlace<'tcx> { transmute_scalar(fx, var, data, dst_ty); } CPlaceInner::VarPair(_local, var1, var2) => { - let (data1, data2) = match from.1.abi { - Abi::ScalarPair(_, _) => CValue(from.0, dst_layout).load_scalar_pair(fx), + let (data1, data2) = match from.1.backend_repr { + BackendRepr::ScalarPair(_, _) => { + CValue(from.0, dst_layout).load_scalar_pair(fx) + } _ => { let (ptr, meta) = from.force_stack(fx); assert!(meta.is_none()); @@ -635,7 +637,9 @@ impl<'tcx> CPlace<'tcx> { } CPlaceInner::Addr(_, Some(_)) => bug!("Can't write value to unsized place {:?}", self), CPlaceInner::Addr(to_ptr, None) => { - if dst_layout.size == Size::ZERO || dst_layout.abi == Abi::Uninhabited { + if dst_layout.size == Size::ZERO + || dst_layout.backend_repr == BackendRepr::Uninhabited + { return; } @@ -646,23 +650,28 @@ impl<'tcx> CPlace<'tcx> { CValueInner::ByVal(val) => { to_ptr.store(fx, val, flags); } - CValueInner::ByValPair(val1, val2) => match from.layout().abi { - Abi::ScalarPair(a_scalar, b_scalar) => { + CValueInner::ByValPair(val1, val2) => match from.layout().backend_repr { + BackendRepr::ScalarPair(a_scalar, b_scalar) => { let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); to_ptr.store(fx, val1, flags); to_ptr.offset(fx, b_offset).store(fx, val2, flags); } - _ => bug!("Non ScalarPair abi {:?} for ByValPair CValue", dst_layout.abi), + _ => { + bug!( + "Non ScalarPair repr {:?} for ByValPair CValue", + dst_layout.backend_repr + ) + } }, CValueInner::ByRef(from_ptr, None) => { - match from.layout().abi { - Abi::Scalar(_) => { + match from.layout().backend_repr { + BackendRepr::Scalar(_) => { let val = from.load_scalar(fx); to_ptr.store(fx, val, flags); return; } - Abi::ScalarPair(a_scalar, b_scalar) => { + BackendRepr::ScalarPair(a_scalar, b_scalar) => { let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); let (val1, val2) = from.load_scalar_pair(fx); diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 14c607ccad7..82b6178be9d 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -47,7 +47,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( idx: usize, ) -> (Pointer, Value) { let (ptr, vtable) = 'block: { - if let Abi::Scalar(_) = arg.layout().abi { + if let BackendRepr::Scalar(_) = arg.layout().backend_repr { while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() { let (idx, _) = arg .layout() @@ -68,7 +68,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( } } - if let Abi::ScalarPair(_, _) = arg.layout().abi { + if let BackendRepr::ScalarPair(_, _) = arg.layout().backend_repr { let (ptr, vtable) = arg.load_scalar_pair(fx); (Pointer::new(ptr), vtable) } else { diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 7c52cba096b..e6ae7cf174d 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1016,11 +1016,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { OperandValue::Ref(place.val) } else if place.layout.is_gcc_immediate() { let load = self.load(place.layout.gcc_type(self), place.val.llval, place.val.align); - if let abi::Abi::Scalar(ref scalar) = place.layout.abi { + if let abi::BackendRepr::Scalar(ref scalar) = place.layout.backend_repr { scalar_load_metadata(self, load, scalar); } OperandValue::Immediate(self.to_immediate(load, place.layout)) - } else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi { + } else if let abi::BackendRepr::ScalarPair(ref a, ref b) = place.layout.backend_repr { let b_offset = a.size(self).align_to(b.align(self).abi); let mut load = |i, scalar: &abi::Scalar, align| { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 972d6632140..b0298a35cb0 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -294,13 +294,13 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } sym::raw_eq => { - use rustc_target::abi::Abi::*; + use rustc_abi::BackendRepr::*; let tp_ty = fn_args.type_at(0); let layout = self.layout_of(tp_ty).layout; - let _use_integer_compare = match layout.abi() { + let _use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, Uninhabited | Vector { .. } => false, - Aggregate { .. } => { + Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), // so we re-use that same threshold here. diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index db874afe1ab..0efdf36da48 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -3,7 +3,7 @@ use std::fmt::Write; use gccjit::{Struct, Type}; use rustc_abi as abi; use rustc_abi::Primitive::*; -use rustc_abi::{Abi, FieldsShape, Integer, PointeeInfo, Size, Variants}; +use rustc_abi::{BackendRepr, FieldsShape, Integer, PointeeInfo, Size, Variants}; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, DerivedTypeCodegenMethods, LayoutTypeCodegenMethods, }; @@ -60,9 +60,9 @@ fn uncached_gcc_type<'gcc, 'tcx>( layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>, ) -> Type<'gcc> { - match layout.abi { - Abi::Scalar(_) => bug!("handled elsewhere"), - Abi::Vector { ref element, count } => { + match layout.backend_repr { + BackendRepr::Scalar(_) => bug!("handled elsewhere"), + BackendRepr::Vector { ref element, count } => { let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO); let element = // NOTE: gcc doesn't allow pointer types in vectors. @@ -74,7 +74,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( }; return cx.context.new_vector_type(element, count); } - Abi::ScalarPair(..) => { + BackendRepr::ScalarPair(..) => { return cx.type_struct( &[ layout.scalar_pair_element_gcc_type(cx, 0), @@ -83,7 +83,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( false, ); } - Abi::Uninhabited | Abi::Aggregate { .. } => {} + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => {} } let name = match *layout.ty.kind() { @@ -176,16 +176,21 @@ pub trait LayoutGccExt<'tcx> { impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_immediate(&self) -> bool { - match self.abi { - Abi::Scalar(_) | Abi::Vector { .. } => true, - Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, + match self.backend_repr { + BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => true, + BackendRepr::ScalarPair(..) | BackendRepr::Uninhabited | BackendRepr::Memory { .. } => { + false + } } } fn is_gcc_scalar_pair(&self) -> bool { - match self.abi { - Abi::ScalarPair(..) => true, - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false, + match self.backend_repr { + BackendRepr::ScalarPair(..) => true, + BackendRepr::Uninhabited + | BackendRepr::Scalar(_) + | BackendRepr::Vector { .. } + | BackendRepr::Memory { .. } => false, } } @@ -205,7 +210,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. - if let Abi::Scalar(ref scalar) = self.abi { + if let BackendRepr::Scalar(ref scalar) = self.backend_repr { // Use a different cache for scalars because pointers to DSTs // can be either wide or thin (data pointers of wide pointers). if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) { @@ -261,7 +266,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { } fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { - if let Abi::Scalar(ref scalar) = self.abi { + if let BackendRepr::Scalar(ref scalar) = self.backend_repr { if scalar.is_bool() { return cx.type_i1(); } @@ -299,8 +304,8 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. - let (a, b) = match self.abi { - Abi::ScalarPair(ref a, ref b) => (a, b), + let (a, b) = match self.backend_repr { + BackendRepr::ScalarPair(ref a, ref b) => (a, b), _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self), }; let scalar = [a, b][index]; diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 2fe5ed32daa..855ca010611 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -415,7 +415,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { instance: Option<ty::Instance<'tcx>>, ) { let mut func_attrs = SmallVec::<[_; 3]>::new(); - if self.ret.layout.abi.is_uninhabited() { + if self.ret.layout.is_uninhabited() { func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx)); } if !self.can_unwind { @@ -458,7 +458,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { match &self.ret.mode { PassMode::Direct(attrs) => { attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); - if let abi::Abi::Scalar(scalar) = self.ret.layout.abi { + if let abi::BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr { apply_range_attr(llvm::AttributePlace::ReturnValue, scalar); } } @@ -495,7 +495,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } PassMode::Direct(attrs) => { let i = apply(attrs); - if let abi::Abi::Scalar(scalar) = arg.layout.abi { + if let abi::BackendRepr::Scalar(scalar) = arg.layout.backend_repr { apply_range_attr(llvm::AttributePlace::Argument(i), scalar); } } @@ -510,7 +510,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Pair(a, b) => { let i = apply(a); let ii = apply(b); - if let abi::Abi::ScalarPair(scalar_a, scalar_b) = arg.layout.abi { + if let abi::BackendRepr::ScalarPair(scalar_a, scalar_b) = + arg.layout.backend_repr + { apply_range_attr(llvm::AttributePlace::Argument(i), scalar_a); apply_range_attr(llvm::AttributePlace::Argument(ii), scalar_b); } @@ -532,7 +534,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value) { let mut func_attrs = SmallVec::<[_; 2]>::new(); - if self.ret.layout.abi.is_uninhabited() { + if self.ret.layout.is_uninhabited() { func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(bx.cx.llcx)); } if !self.can_unwind { @@ -570,7 +572,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } if bx.cx.sess().opts.optimize != config::OptLevel::No && llvm_util::get_version() < (19, 0, 0) - && let abi::Abi::Scalar(scalar) = self.ret.layout.abi + && let abi::BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr && matches!(scalar.primitive(), Int(..)) // If the value is a boolean, the range is 0..2 and that ultimately // become 0..0 when the type becomes i1, which would be rejected diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 55ee6dcdf87..149ded28356 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -7,6 +7,7 @@ use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DebugInfo, OomStrategy}; +use crate::common::AsCCharPtr; use crate::llvm::{self, Context, False, Module, True, Type}; use crate::{ModuleLlvm, attributes, debuginfo}; @@ -76,14 +77,14 @@ pub(crate) unsafe fn codegen( unsafe { // __rust_alloc_error_handler_should_panic let name = OomStrategy::SYMBOL; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); + let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let val = tcx.sess.opts.unstable_opts.oom.should_panic(); let llval = llvm::LLVMConstInt(i8, val as u64, False); llvm::LLVMSetInitializer(ll_g, llval); let name = NO_ALLOC_SHIM_IS_UNSTABLE; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); + let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let llval = llvm::LLVMConstInt(i8, 0, False); llvm::LLVMSetInitializer(ll_g, llval); @@ -115,7 +116,7 @@ fn create_wrapper_function( ); let llfn = llvm::LLVMRustGetOrInsertFunction( llmod, - from_name.as_ptr().cast(), + from_name.as_c_char_ptr(), from_name.len(), ty, ); @@ -137,7 +138,7 @@ fn create_wrapper_function( } let callee = - llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_ptr().cast(), to_name.len(), ty); + llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_c_char_ptr(), to_name.len(), ty); if let Some(no_return) = no_return { // -> ! DIFlagNoReturn attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); @@ -153,7 +154,7 @@ fn create_wrapper_function( .enumerate() .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint)) .collect::<Vec<_>>(); - let ret = llvm::LLVMRustBuildCall( + let ret = llvm::LLVMBuildCallWithOperandBundles( llbuilder, ty, callee, @@ -161,6 +162,7 @@ fn create_wrapper_function( args.len() as c_uint, [].as_ptr(), 0 as c_uint, + c"".as_ptr(), ); llvm::LLVMSetTailCall(ret, True); if output.is_some() { diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index d1d7d0cf4ce..53758967552 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -15,7 +15,7 @@ use smallvec::SmallVec; use tracing::debug; use crate::builder::Builder; -use crate::common::Funclet; +use crate::common::{AsCCharPtr, Funclet}; use crate::context::CodegenCx; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; @@ -420,7 +420,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { unsafe { llvm::LLVMAppendModuleInlineAsm( self.llmod, - template_str.as_ptr().cast(), + template_str.as_c_char_ptr(), template_str.len(), ); } @@ -458,14 +458,14 @@ pub(crate) fn inline_asm_call<'ll>( let fty = bx.cx.type_func(&argtys, output); unsafe { // Ask LLVM to verify that the constraints are well-formed. - let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr().cast(), cons.len()); + let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()); debug!("constraint verification result: {:?}", constraints_ok); if constraints_ok { let v = llvm::LLVMRustInlineAsm( fty, - asm.as_ptr().cast(), + asm.as_c_char_ptr(), asm.len(), - cons.as_ptr().cast(), + cons.as_c_char_ptr(), cons.len(), volatile, alignstack, @@ -880,8 +880,8 @@ fn llvm_fixup_input<'ll, 'tcx>( ) -> &'ll Value { use InlineAsmRegClass::*; let dl = &bx.tcx.data_layout; - match (reg, layout.abi) { - (AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { + match (reg, layout.backend_repr) { + (AArch64(AArch64InlineAsmRegClass::vreg), BackendRepr::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.primitive() { let vec_ty = bx.cx.type_vector(bx.cx.type_i8(), 8); bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0)) @@ -889,7 +889,7 @@ fn llvm_fixup_input<'ll, 'tcx>( value } } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Scalar(s)) if s.primitive() != Primitive::Float(Float::F128) => { let elem_ty = llvm_asm_scalar_type(bx.cx, s); @@ -902,7 +902,7 @@ fn llvm_fixup_input<'ll, 'tcx>( } bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0)) } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Vector { element, count }) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Vector { element, count }) if layout.size.bytes() == 8 => { let elem_ty = llvm_asm_scalar_type(bx.cx, element); @@ -910,14 +910,14 @@ fn llvm_fixup_input<'ll, 'tcx>( let indices: Vec<_> = (0..count * 2).map(|x| bx.const_i32(x as i32)).collect(); bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices)) } - (X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) + (X86(X86InlineAsmRegClass::reg_abcd), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F64) => { bx.bitcast(value, bx.cx.type_i64()) } ( X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), - Abi::Vector { .. }, + BackendRepr::Vector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, bx.cx.type_vector(bx.cx.type_f64(), 8)), ( X86( @@ -925,7 +925,7 @@ fn llvm_fixup_input<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) if bx.sess().asm_arch == Some(InlineAsmArch::X86) && s.primitive() == Primitive::Float(Float::F128) => { @@ -937,7 +937,7 @@ fn llvm_fixup_input<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) if s.primitive() == Primitive::Float(Float::F16) => { let value = bx.insert_element( bx.const_undef(bx.type_vector(bx.type_f16(), 8)), @@ -952,11 +952,14 @@ fn llvm_fixup_input<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Vector { element, count: count @ (8 | 16) }, + BackendRepr::Vector { element, count: count @ (8 | 16) }, ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) } - (Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s)) => { + ( + Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), + BackendRepr::Scalar(s), + ) => { if let Primitive::Int(Integer::I32, _) = s.primitive() { bx.bitcast(value, bx.cx.type_f32()) } else { @@ -969,7 +972,7 @@ fn llvm_fixup_input<'ll, 'tcx>( | ArmInlineAsmRegClass::dreg_low8 | ArmInlineAsmRegClass::dreg_low16, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) => { if let Primitive::Int(Integer::I64, _) = s.primitive() { bx.bitcast(value, bx.cx.type_f64()) @@ -986,11 +989,11 @@ fn llvm_fixup_input<'ll, 'tcx>( | ArmInlineAsmRegClass::qreg_low4 | ArmInlineAsmRegClass::qreg_low8, ), - Abi::Vector { element, count: count @ (4 | 8) }, + BackendRepr::Vector { element, count: count @ (4 | 8) }, ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) } - (Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { + (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()), @@ -999,7 +1002,7 @@ fn llvm_fixup_input<'ll, 'tcx>( _ => value, } } - (RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + (RiscV(RiscVInlineAsmRegClass::freg), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F16) && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) => { @@ -1022,15 +1025,15 @@ fn llvm_fixup_output<'ll, 'tcx>( instance: Instance<'_>, ) -> &'ll Value { use InlineAsmRegClass::*; - match (reg, layout.abi) { - (AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { + match (reg, layout.backend_repr) { + (AArch64(AArch64InlineAsmRegClass::vreg), BackendRepr::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.primitive() { bx.extract_element(value, bx.const_i32(0)) } else { value } } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Scalar(s)) if s.primitive() != Primitive::Float(Float::F128) => { value = bx.extract_element(value, bx.const_i32(0)); @@ -1039,7 +1042,7 @@ fn llvm_fixup_output<'ll, 'tcx>( } value } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Vector { element, count }) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Vector { element, count }) if layout.size.bytes() == 8 => { let elem_ty = llvm_asm_scalar_type(bx.cx, element); @@ -1047,14 +1050,14 @@ fn llvm_fixup_output<'ll, 'tcx>( let indices: Vec<_> = (0..count).map(|x| bx.const_i32(x as i32)).collect(); bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices)) } - (X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) + (X86(X86InlineAsmRegClass::reg_abcd), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F64) => { bx.bitcast(value, bx.cx.type_f64()) } ( X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), - Abi::Vector { .. }, + BackendRepr::Vector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, layout.llvm_type(bx.cx)), ( X86( @@ -1062,7 +1065,7 @@ fn llvm_fixup_output<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) if bx.sess().asm_arch == Some(InlineAsmArch::X86) && s.primitive() == Primitive::Float(Float::F128) => { @@ -1074,7 +1077,7 @@ fn llvm_fixup_output<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) if s.primitive() == Primitive::Float(Float::F16) => { let value = bx.bitcast(value, bx.type_vector(bx.type_f16(), 8)); bx.extract_element(value, bx.const_usize(0)) @@ -1085,11 +1088,14 @@ fn llvm_fixup_output<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Vector { element, count: count @ (8 | 16) }, + BackendRepr::Vector { element, count: count @ (8 | 16) }, ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) } - (Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s)) => { + ( + Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), + BackendRepr::Scalar(s), + ) => { if let Primitive::Int(Integer::I32, _) = s.primitive() { bx.bitcast(value, bx.cx.type_i32()) } else { @@ -1102,7 +1108,7 @@ fn llvm_fixup_output<'ll, 'tcx>( | ArmInlineAsmRegClass::dreg_low8 | ArmInlineAsmRegClass::dreg_low16, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) => { if let Primitive::Int(Integer::I64, _) = s.primitive() { bx.bitcast(value, bx.cx.type_i64()) @@ -1119,11 +1125,11 @@ fn llvm_fixup_output<'ll, 'tcx>( | ArmInlineAsmRegClass::qreg_low4 | ArmInlineAsmRegClass::qreg_low8, ), - Abi::Vector { element, count: count @ (4 | 8) }, + BackendRepr::Vector { element, count: count @ (4 | 8) }, ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) } - (Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { + (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()), @@ -1133,7 +1139,7 @@ fn llvm_fixup_output<'ll, 'tcx>( _ => value, } } - (RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + (RiscV(RiscVInlineAsmRegClass::freg), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F16) && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) => { @@ -1153,35 +1159,35 @@ fn llvm_fixup_output_type<'ll, 'tcx>( instance: Instance<'_>, ) -> &'ll Type { use InlineAsmRegClass::*; - match (reg, layout.abi) { - (AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { + match (reg, layout.backend_repr) { + (AArch64(AArch64InlineAsmRegClass::vreg), BackendRepr::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.primitive() { cx.type_vector(cx.type_i8(), 8) } else { layout.llvm_type(cx) } } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Scalar(s)) if s.primitive() != Primitive::Float(Float::F128) => { let elem_ty = llvm_asm_scalar_type(cx, s); let count = 16 / layout.size.bytes(); cx.type_vector(elem_ty, count) } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Vector { element, count }) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Vector { element, count }) if layout.size.bytes() == 8 => { let elem_ty = llvm_asm_scalar_type(cx, element); cx.type_vector(elem_ty, count * 2) } - (X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) + (X86(X86InlineAsmRegClass::reg_abcd), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F64) => { cx.type_i64() } ( X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), - Abi::Vector { .. }, + BackendRepr::Vector { .. }, ) if layout.size.bytes() == 64 => cx.type_vector(cx.type_f64(), 8), ( X86( @@ -1189,7 +1195,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) if cx.sess().asm_arch == Some(InlineAsmArch::X86) && s.primitive() == Primitive::Float(Float::F128) => { @@ -1201,7 +1207,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) if s.primitive() == Primitive::Float(Float::F16) => cx.type_vector(cx.type_i16(), 8), ( X86( @@ -1209,11 +1215,14 @@ fn llvm_fixup_output_type<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Vector { element, count: count @ (8 | 16) }, + BackendRepr::Vector { element, count: count @ (8 | 16) }, ) if element.primitive() == Primitive::Float(Float::F16) => { cx.type_vector(cx.type_i16(), count) } - (Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s)) => { + ( + Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), + BackendRepr::Scalar(s), + ) => { if let Primitive::Int(Integer::I32, _) = s.primitive() { cx.type_f32() } else { @@ -1226,7 +1235,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( | ArmInlineAsmRegClass::dreg_low8 | ArmInlineAsmRegClass::dreg_low16, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) => { if let Primitive::Int(Integer::I64, _) = s.primitive() { cx.type_f64() @@ -1243,11 +1252,11 @@ fn llvm_fixup_output_type<'ll, 'tcx>( | ArmInlineAsmRegClass::qreg_low4 | ArmInlineAsmRegClass::qreg_low8, ), - Abi::Vector { element, count: count @ (4 | 8) }, + BackendRepr::Vector { element, count: count @ (4 | 8) }, ) if element.primitive() == Primitive::Float(Float::F16) => { cx.type_vector(cx.type_i16(), count) } - (Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { + (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(), @@ -1256,7 +1265,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( _ => layout.llvm_type(cx), } } - (RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + (RiscV(RiscVInlineAsmRegClass::freg), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F16) && !any_target_feature_enabled(cx, instance, &[sym::zfhmin, sym::zfh]) => { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 1f7a923dd2c..48beb9be2b2 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -165,13 +165,14 @@ fn get_bitcode_slice_from_object_data<'a>( // We drop the "__LLVM," prefix here because on Apple platforms there's a notion of "segment // name" which in the public API for sections gets treated as part of the section name, but // internally in MachOObjectFile.cpp gets treated separately. - let section_name = bitcode_section_name(cgcx).trim_start_matches("__LLVM,"); + let section_name = bitcode_section_name(cgcx).to_str().unwrap().trim_start_matches("__LLVM,"); let mut len = 0; let data = unsafe { llvm::LLVMRustGetSliceFromObjectDataByName( obj.as_ptr(), obj.len(), section_name.as_ptr(), + section_name.len(), &mut len, ) }; @@ -502,9 +503,9 @@ fn thin_lto( // upstream... let data = llvm::LLVMRustCreateThinLTOData( thin_modules.as_ptr(), - thin_modules.len() as u32, + thin_modules.len(), symbols_below_threshold.as_ptr(), - symbols_below_threshold.len() as u32, + symbols_below_threshold.len(), ) .ok_or_else(|| write::llvm_err(dcx, LlvmError::PrepareThinLtoContext))?; @@ -569,7 +570,7 @@ fn thin_lto( info!(" - {}: re-compiled", module_name); opt_jobs.push(LtoModuleCodegen::Thin(ThinModule { - shared: shared.clone(), + shared: Arc::clone(&shared), idx: module_index, })); } @@ -601,23 +602,9 @@ pub(crate) fn run_pass_manager( // This code is based off the code found in llvm's LTO code generator: // llvm/lib/LTO/LTOCodeGenerator.cpp debug!("running the pass manager"); - unsafe { - if !llvm::LLVMRustHasModuleFlag( - module.module_llvm.llmod(), - "LTOPostLink".as_ptr().cast(), - 11, - ) { - llvm::LLVMRustAddModuleFlagU32( - module.module_llvm.llmod(), - llvm::LLVMModFlagBehavior::Error, - c"LTOPostLink".as_ptr(), - 1, - ); - } - let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO }; - let opt_level = config.opt_level.unwrap_or(config::OptLevel::No); - write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage)?; - } + let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO }; + let opt_level = config.opt_level.unwrap_or(config::OptLevel::No); + unsafe { write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) }?; debug!("lto done"); Ok(()) } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index bf77fc56d08..bfa9e8b82a0 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1,4 +1,4 @@ -use std::ffi::CString; +use std::ffi::{CStr, CString}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -34,6 +34,7 @@ use crate::back::owned_target_machine::OwnedTargetMachine; use crate::back::profiling::{ LlvmSelfProfiler, selfprofile_after_pass_callback, selfprofile_before_pass_callback, }; +use crate::common::AsCCharPtr; use crate::errors::{ CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression, WithLlvmError, WriteBytecode, @@ -596,9 +597,9 @@ pub(crate) unsafe fn llvm_optimize( llvm_selfprofiler, selfprofile_before_pass_callback, selfprofile_after_pass_callback, - extra_passes.as_ptr().cast(), + extra_passes.as_c_char_ptr(), extra_passes.len(), - llvm_plugins.as_ptr().cast(), + llvm_plugins.as_c_char_ptr(), llvm_plugins.len(), ) }; @@ -957,14 +958,13 @@ fn target_is_aix(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool { cgcx.opts.target_triple.triple().contains("-aix") } -//FIXME use c string literals here too -pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static str { +pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static CStr { if target_is_apple(cgcx) { - "__LLVM,__bitcode\0" + c"__LLVM,__bitcode" } else if target_is_aix(cgcx) { - ".ipa\0" + c".ipa" } else { - ".llvmbc\0" + c".llvmbc" } } @@ -1041,8 +1041,7 @@ unsafe fn embed_bitcode( ); llvm::LLVMSetInitializer(llglobal, llconst); - let section = bitcode_section_name(cgcx); - llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); + llvm::set_section(llglobal, bitcode_section_name(cgcx)); llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::LLVMSetGlobalConstant(llglobal, llvm::True); @@ -1060,15 +1059,15 @@ unsafe fn embed_bitcode( } else { c".llvmcmd" }; - llvm::LLVMSetSection(llglobal, section.as_ptr()); + llvm::set_section(llglobal, section); llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); } else { // We need custom section flags, so emit module-level inline assembly. let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); - llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len()); let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); - llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len()); } } } diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 0ba8d82406a..32793894794 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -145,10 +145,8 @@ pub(crate) fn compile_codegen_unit( pub(crate) fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) { let Some(sect) = attrs.link_section else { return }; - unsafe { - let buf = SmallCStr::new(sect.as_str()); - llvm::LLVMSetSection(llval, buf.as_ptr()); - } + let buf = SmallCStr::new(sect.as_str()); + llvm::set_section(llval, &buf); } pub(crate) fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 8702532c36e..15883c91053 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -239,7 +239,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let args = self.check_call("invoke", llty, llfn, args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); - let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { bundles.push(funclet_bundle); @@ -250,13 +249,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); - if let Some(kcfi_bundle) = kcfi_bundle { + if let Some(kcfi_bundle) = kcfi_bundle.as_deref() { bundles.push(kcfi_bundle); } let invoke = unsafe { - llvm::LLVMRustBuildInvoke( + llvm::LLVMBuildInvokeWithOperandBundles( self.llbuilder, llty, llfn, @@ -545,13 +543,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } let llval = const_llval.unwrap_or_else(|| { let load = self.load(llty, place.val.llval, place.val.align); - if let abi::Abi::Scalar(scalar) = place.layout.abi { + if let abi::BackendRepr::Scalar(scalar) = place.layout.backend_repr { scalar_load_metadata(self, load, scalar, place.layout, Size::ZERO); } load }); OperandValue::Immediate(self.to_immediate(llval, place.layout)) - } else if let abi::Abi::ScalarPair(a, b) = place.layout.abi { + } else if let abi::BackendRepr::ScalarPair(a, b) = place.layout.backend_repr { let b_offset = a.size(self).align_to(b.align(self).abi); let mut load = |i, scalar: abi::Scalar, layout, align, offset| { @@ -1179,7 +1177,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let args = self.check_call("call", llty, llfn, args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); - let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { bundles.push(funclet_bundle); @@ -1190,13 +1187,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); - if let Some(kcfi_bundle) = kcfi_bundle { + if let Some(kcfi_bundle) = kcfi_bundle.as_deref() { bundles.push(kcfi_bundle); } let call = unsafe { - llvm::LLVMRustBuildCall( + llvm::LLVMBuildCallWithOperandBundles( self.llbuilder, llty, llfn, @@ -1204,6 +1200,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { args.len() as c_uint, bundles.as_ptr(), bundles.len() as c_uint, + c"".as_ptr(), ) }; if let Some(fn_abi) = fn_abi { @@ -1509,7 +1506,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let args = self.check_call("callbr", llty, llfn, args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); - let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { bundles.push(funclet_bundle); @@ -1520,13 +1516,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); - if let Some(kcfi_bundle) = kcfi_bundle { + if let Some(kcfi_bundle) = kcfi_bundle.as_deref() { bundles.push(kcfi_bundle); } let callbr = unsafe { - llvm::LLVMRustBuildCallBr( + llvm::LLVMBuildCallBr( self.llbuilder, llty, llfn, @@ -1601,7 +1596,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, instance: Option<Instance<'tcx>>, llfn: &'ll Value, - ) -> Option<llvm::OperandBundleDef<'ll>> { + ) -> Option<llvm::OperandBundleOwned<'ll>> { let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) }; let kcfi_bundle = if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi @@ -1627,7 +1622,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { kcfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; - Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)])) + Some(llvm::OperandBundleOwned::new("kcfi", &[self.const_u32(kcfi_typeid)])) } else { None }; diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index ff47eb944dd..8852dec7d9f 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -17,7 +17,7 @@ use tracing::debug; use crate::consts::const_alloc_to_llvm; pub(crate) use crate::context::CodegenCx; -use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, OperandBundleDef, True}; +use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, True}; use crate::type_::Type; use crate::value::Value; @@ -63,19 +63,19 @@ use crate::value::Value; /// the `OperandBundleDef` value created for MSVC landing pads. pub(crate) struct Funclet<'ll> { cleanuppad: &'ll Value, - operand: OperandBundleDef<'ll>, + operand: llvm::OperandBundleOwned<'ll>, } impl<'ll> Funclet<'ll> { pub(crate) fn new(cleanuppad: &'ll Value) -> Self { - Funclet { cleanuppad, operand: OperandBundleDef::new("funclet", &[cleanuppad]) } + Funclet { cleanuppad, operand: llvm::OperandBundleOwned::new("funclet", &[cleanuppad]) } } pub(crate) fn cleanuppad(&self) -> &'ll Value { self.cleanuppad } - pub(crate) fn bundle(&self) -> &OperandBundleDef<'ll> { + pub(crate) fn bundle(&self) -> &llvm::OperandBundle<'ll> { &self.operand } } @@ -392,3 +392,21 @@ pub(crate) fn get_dllimport<'tcx>( tcx.native_library(id) .and_then(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name)) } + +/// Extension trait for explicit casts to `*const c_char`. +pub(crate) trait AsCCharPtr { + /// Equivalent to `self.as_ptr().cast()`, but only casts to `*const c_char`. + fn as_c_char_ptr(&self) -> *const c_char; +} + +impl AsCCharPtr for str { + fn as_c_char_ptr(&self) -> *const c_char { + self.as_ptr().cast() + } +} + +impl AsCCharPtr for [u8] { + fn as_c_char_ptr(&self) -> *const c_char { + self.as_ptr().cast() + } +} diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 1e3abcfd1af..21d996ef460 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -19,7 +19,7 @@ use rustc_target::abi::{ }; use tracing::{debug, instrument, trace}; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::errors::{ InvalidMinimumAlignmentNotPowerOfTwo, InvalidMinimumAlignmentTooLarge, SymbolAlreadyDefined, }; @@ -400,7 +400,7 @@ impl<'ll> CodegenCx<'ll, '_> { let new_g = llvm::LLVMRustGetOrInsertGlobal( self.llmod, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), val_llty, ); @@ -451,7 +451,7 @@ impl<'ll> CodegenCx<'ll, '_> { if let Some(section) = attrs.link_section { let section = llvm::LLVMMDStringInContext2( self.llcx, - section.as_str().as_ptr().cast(), + section.as_str().as_c_char_ptr(), section.as_str().len(), ); assert!(alloc.provenance().ptrs().is_empty()); @@ -462,7 +462,7 @@ impl<'ll> CodegenCx<'ll, '_> { let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); let alloc = - llvm::LLVMMDStringInContext2(self.llcx, bytes.as_ptr().cast(), bytes.len()); + llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()); let data = [section, alloc]; let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()); let val = llvm::LLVMMetadataAsValue(self.llcx, meta); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 067028a16ff..13428b109d9 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -29,6 +29,7 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; +use crate::common::AsCCharPtr; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; use crate::llvm::{Metadata, MetadataType}; use crate::type_::Type; @@ -147,6 +148,11 @@ pub(crate) unsafe fn create_module<'ll>( target_data_layout = target_data_layout.replace("-p270:32:32-p271:32:32-p272:64:64", ""); } + if sess.target.arch.starts_with("sparc") { + // LLVM 20 updates the sparc layout to correctly align 128 bit integers to 128 bit. + // See https://github.com/llvm/llvm-project/pull/106951 + target_data_layout = target_data_layout.replace("-i128:128", ""); + } } // Ensure the data-layout values hardcoded remain the defaults. @@ -209,133 +215,111 @@ pub(crate) unsafe fn create_module<'ll>( // If skipping the PLT is enabled, we need to add some module metadata // to ensure intrinsic calls don't use it. if !sess.needs_plt() { - let avoid_plt = c"RtLibUseGOT".as_ptr(); - unsafe { - llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); - } + llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Warning, "RtLibUseGOT", 1); } // Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.) if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() { - let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr(); - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - canonical_jump_tables, - 1, - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "CFI Canonical Jump Tables", + 1, + ); } // If we're normalizing integers with CFI, ensure LLVM generated functions do the same. // See https://github.com/llvm/llvm-project/pull/104826 if sess.is_sanitizer_cfi_normalize_integers_enabled() { - let cfi_normalize_integers = c"cfi-normalize-integers".as_ptr().cast(); - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - cfi_normalize_integers, - 1, - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "cfi-normalize-integers", + 1, + ); } // Enable LTO unit splitting if specified or if CFI is enabled. (See // https://reviews.llvm.org/D53891.) if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() { - let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr(); - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - enable_split_lto_unit, - 1, - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "EnableSplitLTOUnit", + 1, + ); } // Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.) if sess.is_sanitizer_kcfi_enabled() { - let kcfi = c"kcfi".as_ptr(); - unsafe { - llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); - } + llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Override, "kcfi", 1); // Add "kcfi-offset" module flag with -Z patchable-function-entry (See // https://reviews.llvm.org/D141172). let pfe = PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry); if pfe.prefix() > 0 { - let kcfi_offset = c"kcfi-offset".as_ptr().cast(); - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - kcfi_offset, - pfe.prefix().into(), - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "kcfi-offset", + pfe.prefix().into(), + ); } } // Control Flow Guard is currently only supported by the MSVC linker on Windows. if sess.target.is_like_msvc { - unsafe { - match sess.opts.cg.control_flow_guard { - CFGuard::Disabled => {} - CFGuard::NoChecks => { - // Set `cfguard=1` module flag to emit metadata only. - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"cfguard".as_ptr() as *const _, - 1, - ) - } - CFGuard::Checks => { - // Set `cfguard=2` module flag to emit metadata and checks. - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"cfguard".as_ptr() as *const _, - 2, - ) - } + match sess.opts.cg.control_flow_guard { + CFGuard::Disabled => {} + CFGuard::NoChecks => { + // Set `cfguard=1` module flag to emit metadata only. + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Warning, + "cfguard", + 1, + ); + } + CFGuard::Checks => { + // Set `cfguard=2` module flag to emit metadata and checks. + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Warning, + "cfguard", + 2, + ); } } } if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection { if sess.target.arch == "aarch64" { - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"branch-target-enforcement".as_ptr(), - bti.into(), - ); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"sign-return-address".as_ptr(), - pac_ret.is_some().into(), - ); - let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"sign-return-address-all".as_ptr(), - pac_opts.leaf.into(), - ); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"sign-return-address-with-bkey".as_ptr(), - u32::from(pac_opts.key == PAuthKey::B), - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Min, + "branch-target-enforcement", + bti.into(), + ); + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Min, + "sign-return-address", + pac_ret.is_some().into(), + ); + let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Min, + "sign-return-address-all", + pac_opts.leaf.into(), + ); + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Min, + "sign-return-address-with-bkey", + u32::from(pac_opts.key == PAuthKey::B), + ); } else { bug!( "branch-protection used on non-AArch64 target; \ @@ -346,59 +330,46 @@ pub(crate) unsafe fn create_module<'ll>( // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang). if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection { - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - c"cf-protection-branch".as_ptr(), - 1, - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "cf-protection-branch", + 1, + ); } if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection { - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - c"cf-protection-return".as_ptr(), - 1, - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "cf-protection-return", + 1, + ); } if sess.opts.unstable_opts.virtual_function_elimination { - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Error, - c"Virtual Function Elim".as_ptr(), - 1, - ); - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Error, + "Virtual Function Elim", + 1, + ); } // Set module flag to enable Windows EHCont Guard (/guard:ehcont). if sess.opts.unstable_opts.ehcont_guard { - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"ehcontguard".as_ptr() as *const _, - 1, - ) - } + llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Warning, "ehcontguard", 1); } match sess.opts.unstable_opts.function_return { FunctionReturn::Keep => {} - FunctionReturn::ThunkExtern => unsafe { - llvm::LLVMRustAddModuleFlagU32( + FunctionReturn::ThunkExtern => { + llvm::add_module_flag_u32( llmod, - llvm::LLVMModFlagBehavior::Override, - c"function_return_thunk_extern".as_ptr(), + llvm::ModuleFlagMergeBehavior::Override, + "function_return_thunk_extern", 1, - ) - }, + ); + } } match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support()) @@ -406,15 +377,12 @@ pub(crate) unsafe fn create_module<'ll>( // Set up the small-data optimization limit for architectures that use // an LLVM module flag to control this. (Some(threshold), SmallDataThresholdSupport::LlvmModuleFlag(flag)) => { - let flag = SmallCStr::new(flag.as_ref()); - unsafe { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Error, - flag.as_c_str().as_ptr(), - threshold as u32, - ) - } + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Error, + &flag, + threshold as u32, + ); } _ => (), }; @@ -429,7 +397,7 @@ pub(crate) unsafe fn create_module<'ll>( let name_metadata = unsafe { llvm::LLVMMDStringInContext2( llcx, - rustc_producer.as_ptr().cast(), + rustc_producer.as_c_char_ptr(), rustc_producer.as_bytes().len(), ) }; @@ -448,33 +416,29 @@ pub(crate) unsafe fn create_module<'ll>( // If llvm_abiname is empty, emit nothing. let llvm_abiname = &sess.target.options.llvm_abiname; if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() { - unsafe { - llvm::LLVMRustAddModuleFlagString( - llmod, - llvm::LLVMModFlagBehavior::Error, - c"target-abi".as_ptr(), - llvm_abiname.as_ptr().cast(), - llvm_abiname.len(), - ); - } + llvm::add_module_flag_str( + llmod, + llvm::ModuleFlagMergeBehavior::Error, + "target-abi", + llvm_abiname, + ); } // Add module flags specified via -Z llvm_module_flag - for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag { - let key = format!("{key}\0"); - let behavior = match behavior.as_str() { - "error" => llvm::LLVMModFlagBehavior::Error, - "warning" => llvm::LLVMModFlagBehavior::Warning, - "require" => llvm::LLVMModFlagBehavior::Require, - "override" => llvm::LLVMModFlagBehavior::Override, - "append" => llvm::LLVMModFlagBehavior::Append, - "appendunique" => llvm::LLVMModFlagBehavior::AppendUnique, - "max" => llvm::LLVMModFlagBehavior::Max, - "min" => llvm::LLVMModFlagBehavior::Min, + for (key, value, merge_behavior) in &sess.opts.unstable_opts.llvm_module_flag { + let merge_behavior = match merge_behavior.as_str() { + "error" => llvm::ModuleFlagMergeBehavior::Error, + "warning" => llvm::ModuleFlagMergeBehavior::Warning, + "require" => llvm::ModuleFlagMergeBehavior::Require, + "override" => llvm::ModuleFlagMergeBehavior::Override, + "append" => llvm::ModuleFlagMergeBehavior::Append, + "appendunique" => llvm::ModuleFlagMergeBehavior::AppendUnique, + "max" => llvm::ModuleFlagMergeBehavior::Max, + "min" => llvm::ModuleFlagMergeBehavior::Min, // We already checked this during option parsing _ => unreachable!(), }; - unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) } + llvm::add_module_flag_u32(llmod, merge_behavior, key, *value); } llmod @@ -595,6 +559,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// Extra state that is only available when coverage instrumentation is enabled. #[inline] + #[track_caller] pub(crate) fn coverage_cx(&self) -> &coverageinfo::CrateCoverageContext<'ll, 'tcx> { self.coverage_cx.as_ref().expect("only called when coverage instrumentation is enabled") } @@ -606,7 +571,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr()); llvm::LLVMSetInitializer(g, array); llvm::set_linkage(g, llvm::Linkage::AppendingLinkage); - llvm::LLVMSetSection(g, c"llvm.metadata".as_ptr()); + llvm::set_section(g, c"llvm.metadata"); } } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 8edd788ee36..f6378199fe2 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -54,7 +54,11 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { add_unused_functions(cx); } - let function_coverage_map = cx.coverage_cx().take_function_coverage_map(); + // FIXME(#132395): Can this be none even when coverage is enabled? + let function_coverage_map = match cx.coverage_cx { + Some(ref cx) => cx.take_function_coverage_map(), + None => return, + }; if function_coverage_map.is_empty() { // This module has no functions with coverage instrumentation return; diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index c6b2a623ea6..e4ff50816b9 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -14,7 +14,7 @@ use rustc_target::abi::Size; use tracing::{debug, instrument}; use crate::builder::Builder; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::coverageinfo::map_data::FunctionCoverageCollector; use crate::llvm; @@ -152,7 +152,12 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { return; }; - let mut coverage_map = bx.coverage_cx().function_coverage_map.borrow_mut(); + // FIXME(#132395): Unwrapping `coverage_cx` here has led to ICEs in the + // wild, so keep this early-return until we understand why. + let mut coverage_map = match bx.coverage_cx { + Some(ref cx) => cx.function_coverage_map.borrow_mut(), + None => return, + }; let func_coverage = coverage_map .entry(instance) .or_insert_with(|| FunctionCoverageCollector::new(instance, function_coverage_info)); @@ -236,7 +241,7 @@ fn create_pgo_func_name_var<'ll, 'tcx>( unsafe { llvm::LLVMRustCoverageCreatePGOFuncNameVar( llfn, - mangled_fn_name.as_ptr().cast(), + mangled_fn_name.as_c_char_ptr(), mangled_fn_name.len(), ) } @@ -248,7 +253,7 @@ pub(crate) fn write_filenames_section_to_buffer<'a>( ) { let (pointers, lengths) = filenames .into_iter() - .map(|s: &str| (s.as_ptr().cast(), s.len())) + .map(|s: &str| (s.as_c_char_ptr(), s.len())) .unzip::<_, _, Vec<_>, Vec<_>>(); unsafe { @@ -291,7 +296,7 @@ pub(crate) fn write_mapping_to_buffer( } pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 { - unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_ptr().cast(), bytes.len()) } + unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_c_char_ptr(), bytes.len()) } } pub(crate) fn mapping_version() -> u32 { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 7947c9c8c8e..aef8642f199 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -72,7 +72,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( let section_var = cx .define_global(section_var_name, llvm_type) .unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name)); - llvm::LLVMSetSection(section_var, c".debug_gdb_scripts".as_ptr()); + llvm::set_section(section_var, c".debug_gdb_scripts"); llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 15d441a986d..9064cfaeb29 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -32,7 +32,7 @@ use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_na use super::utils::{ DIB, create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, }; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::metadata::type_map::build_type_with_children; use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind}; use crate::llvm::debuginfo::{ @@ -190,7 +190,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( data_layout.pointer_size.bits(), data_layout.pointer_align.abi.bits() as u32, 0, // Ignore DWARF address space. - ptr_type_debuginfo_name.as_ptr().cast(), + ptr_type_debuginfo_name.as_c_char_ptr(), ptr_type_debuginfo_name.len(), ) }; @@ -348,7 +348,7 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( size, align, 0, // Ignore DWARF address space. - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), ) }; @@ -518,7 +518,7 @@ fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll D let name = "<recur_type>"; llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), cx.tcx.data_layout.pointer_size.bits(), DW_ATE_unsigned, @@ -640,14 +640,14 @@ pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFi unsafe { llvm::LLVMRustDIBuilderCreateFile( DIB(cx), - file_name.as_ptr().cast(), + file_name.as_c_char_ptr(), file_name.len(), - directory.as_ptr().cast(), + directory.as_c_char_ptr(), directory.len(), hash_kind, - hash_value.as_ptr().cast(), + hash_value.as_c_char_ptr(), hash_value.len(), - source.map_or(ptr::null(), |x| x.as_ptr().cast()), + source.map_or(ptr::null(), |x| x.as_c_char_ptr()), source.map_or(0, |x| x.len()), ) } @@ -662,12 +662,12 @@ fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile { llvm::LLVMRustDIBuilderCreateFile( DIB(cx), - file_name.as_ptr().cast(), + file_name.as_c_char_ptr(), file_name.len(), - directory.as_ptr().cast(), + directory.as_c_char_ptr(), directory.len(), llvm::ChecksumKind::None, - hash_value.as_ptr().cast(), + hash_value.as_c_char_ptr(), hash_value.len(), ptr::null(), 0, @@ -788,7 +788,7 @@ fn build_basic_type_di_node<'ll, 'tcx>( let ty_di_node = unsafe { llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), cx.size_of(t).bits(), encoding, @@ -810,7 +810,7 @@ fn build_basic_type_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateTypedef( DIB(cx), ty_di_node, - typedef_name.as_ptr().cast(), + typedef_name.as_c_char_ptr(), typedef_name.len(), unknown_file_metadata(cx), 0, @@ -861,7 +861,7 @@ fn build_param_type_di_node<'ll, 'tcx>( di_node: unsafe { llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), Size::ZERO.bits(), DW_ATE_unsigned, @@ -948,9 +948,9 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( unsafe { let compile_unit_file = llvm::LLVMRustDIBuilderCreateFile( debug_context.builder, - name_in_debuginfo.as_ptr().cast(), + name_in_debuginfo.as_c_char_ptr(), name_in_debuginfo.len(), - work_dir.as_ptr().cast(), + work_dir.as_c_char_ptr(), work_dir.len(), llvm::ChecksumKind::None, ptr::null(), @@ -963,7 +963,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( debug_context.builder, DW_LANG_RUST, compile_unit_file, - producer.as_ptr().cast(), + producer.as_c_char_ptr(), producer.len(), tcx.sess.opts.optimize != config::OptLevel::No, c"".as_ptr(), @@ -971,7 +971,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( // NB: this doesn't actually have any perceptible effect, it seems. LLVM will instead // put the path supplied to `MCSplitDwarfFile` into the debug info of the final // output(s). - split_name.as_ptr().cast(), + split_name.as_c_char_ptr(), split_name.len(), kind, 0, @@ -1022,7 +1022,7 @@ fn build_field_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), owner, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -1306,7 +1306,7 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), actual_type_di_node, ) @@ -1382,9 +1382,9 @@ pub(crate) fn build_global_var_di_node<'ll>( llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), Some(var_scope), - var_name.as_ptr().cast(), + var_name.as_c_char_ptr(), var_name.len(), - linkage_name.as_ptr().cast(), + linkage_name.as_c_char_ptr(), linkage_name.len(), file_metadata, line_number, @@ -1602,9 +1602,9 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), NO_SCOPE_METADATA, - vtable_name.as_ptr().cast(), + vtable_name.as_c_char_ptr(), vtable_name.len(), - linkage_name.as_ptr().cast(), + linkage_name.as_c_char_ptr(), linkage_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index 966788cf32f..5385d3a9212 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty}; use rustc_target::abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants}; use smallvec::smallvec; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::metadata::enums::DiscrResult; use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId}; use crate::debuginfo::metadata::{ @@ -359,7 +359,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateStaticMemberType( DIB(cx), enum_type_di_node, - TAG_FIELD_NAME.as_ptr().cast(), + TAG_FIELD_NAME.as_c_char_ptr(), TAG_FIELD_NAME.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -537,7 +537,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateStaticMemberType( DIB(cx), wrapper_struct_type_di_node, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -785,7 +785,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), enum_type_di_node, - field_name.as_ptr().cast(), + field_name.as_c_char_ptr(), field_name.len(), file_di_node, line_number, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index fe1634146ff..4c848027b55 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -13,7 +13,7 @@ use rustc_target::abi::{FieldIdx, TagEncoding, VariantIdx, Variants}; use super::type_map::{DINodeCreationResult, UniqueTypeId}; use super::{SmallVec, size_and_align_of}; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::metadata::type_map::{self, Stub}; use crate::debuginfo::metadata::{ UNKNOWN_LINE_NUMBER, build_field_di_node, build_generic_type_param_di_nodes, type_di_node, @@ -106,7 +106,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( let value = [value as u64, (value >> 64) as u64]; Some(llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), value.as_ptr(), size.bits() as libc::c_uint, @@ -119,7 +119,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateEnumerationType( DIB(cx), containing_scope, - type_name.as_ptr().cast(), + type_name.as_c_char_ptr(), type_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, 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 5e7dbdd921a..b7400c5aeb2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::{self}; use rustc_target::abi::{Size, TagEncoding, VariantIdx, Variants}; use smallvec::smallvec; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::metadata::type_map::{self, Stub, StubInfo, UniqueTypeId}; use crate::debuginfo::metadata::{ DINodeCreationResult, NO_GENERICS, SmallVec, UNKNOWN_LINE_NUMBER, file_metadata, @@ -244,7 +244,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateVariantPart( DIB(cx), enum_type_di_node, - variant_part_name.as_ptr().cast(), + variant_part_name.as_c_char_ptr(), variant_part_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -253,7 +253,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>( DIFlags::FlagZero, tag_member_di_node, create_DIArray(DIB(cx), &[]), - variant_part_unique_type_id_str.as_ptr().cast(), + variant_part_unique_type_id_str.as_c_char_ptr(), variant_part_unique_type_id_str.len(), ) }, @@ -327,7 +327,7 @@ fn build_discr_member_di_node<'ll, 'tcx>( Some(llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), containing_scope, - tag_name.as_ptr().cast(), + tag_name.as_c_char_ptr(), tag_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -399,7 +399,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateVariantMemberType( DIB(cx), variant_part_di_node, - variant_member_info.variant_name.as_ptr().cast(), + variant_member_info.variant_name.as_c_char_ptr(), variant_member_info.variant_name.len(), file_di_node, line_number, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 714e3c0b145..d050dc9b406 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_target::abi::{Align, Size, VariantIdx}; use super::{SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata}; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::utils::{DIB, create_DIArray, debug_context}; use crate::llvm::debuginfo::{DIFlags, DIScope, DIType}; use crate::llvm::{self}; @@ -191,7 +191,7 @@ pub(super) fn stub<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateStructType( DIB(cx), containing_scope, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -202,7 +202,7 @@ pub(super) fn stub<'ll, 'tcx>( empty_array, 0, vtable_holder, - unique_type_id_str.as_ptr().cast(), + unique_type_id_str.as_c_char_ptr(), unique_type_id_str.len(), ) } @@ -211,7 +211,7 @@ pub(super) fn stub<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), containing_scope, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, @@ -220,7 +220,7 @@ pub(super) fn stub<'ll, 'tcx>( flags, Some(empty_array), 0, - unique_type_id_str.as_ptr().cast(), + unique_type_id_str.as_c_char_ptr(), unique_type_id_str.len(), ) }, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 3de4ca77e7d..72e723aa849 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -31,7 +31,7 @@ use self::namespace::mangled_name_of_instance; use self::utils::{DIB, create_DIArray, is_node_local_to_unit}; use crate::abi::FnAbi; use crate::builder::Builder; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::llvm; use crate::llvm::debuginfo::{ DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType, @@ -91,45 +91,39 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { } pub(crate) fn finalize(&self, sess: &Session) { - unsafe { - llvm::LLVMRustDIBuilderFinalize(self.builder); - - if !sess.target.is_like_msvc { - // Debuginfo generation in LLVM by default uses a higher - // version of dwarf than macOS currently understands. We can - // instruct LLVM to emit an older version of dwarf, however, - // for macOS to understand. For more info see #11352 - // This can be overridden using --llvm-opts -dwarf-version,N. - // Android has the same issue (#22398) - let dwarf_version = sess - .opts - .unstable_opts - .dwarf_version - .unwrap_or(sess.target.default_dwarf_version); - llvm::LLVMRustAddModuleFlagU32( - self.llmod, - llvm::LLVMModFlagBehavior::Warning, - c"Dwarf Version".as_ptr(), - dwarf_version, - ); - } else { - // Indicate that we want CodeView debug information on MSVC - llvm::LLVMRustAddModuleFlagU32( - self.llmod, - llvm::LLVMModFlagBehavior::Warning, - c"CodeView".as_ptr(), - 1, - ) - } - - // Prevent bitcode readers from deleting the debug info. - llvm::LLVMRustAddModuleFlagU32( + unsafe { llvm::LLVMRustDIBuilderFinalize(self.builder) }; + if !sess.target.is_like_msvc { + // Debuginfo generation in LLVM by default uses a higher + // version of dwarf than macOS currently understands. We can + // instruct LLVM to emit an older version of dwarf, however, + // for macOS to understand. For more info see #11352 + // This can be overridden using --llvm-opts -dwarf-version,N. + // Android has the same issue (#22398) + let dwarf_version = + sess.opts.unstable_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version); + llvm::add_module_flag_u32( self.llmod, - llvm::LLVMModFlagBehavior::Warning, - c"Debug Info Version".as_ptr(), - llvm::LLVMRustDebugMetadataVersion(), + llvm::ModuleFlagMergeBehavior::Warning, + "Dwarf Version", + dwarf_version, + ); + } else { + // Indicate that we want CodeView debug information on MSVC + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Warning, + "CodeView", + 1, ); } + + // Prevent bitcode readers from deleting the debug info. + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Warning, + "Debug Info Version", + unsafe { llvm::LLVMRustDebugMetadataVersion() }, + ); } } @@ -364,7 +358,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let mut flags = DIFlags::FlagPrototyped; - if fn_abi.ret.layout.abi.is_uninhabited() { + if fn_abi.ret.layout.is_uninhabited() { flags |= DIFlags::FlagNoReturn; } @@ -389,9 +383,9 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMRustDIBuilderCreateMethod( DIB(self), containing_scope, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), - linkage_name.as_ptr().cast(), + linkage_name.as_c_char_ptr(), linkage_name.len(), file_metadata, loc.line, @@ -406,9 +400,9 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMRustDIBuilderCreateFunction( DIB(self), containing_scope, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), - linkage_name.as_ptr().cast(), + linkage_name.as_c_char_ptr(), linkage_name.len(), file_metadata, loc.line, @@ -494,7 +488,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), actual_type_metadata, )) @@ -635,7 +629,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { DIB(self), dwarf_tag, scope_metadata, - name.as_ptr().cast(), + name.as_c_char_ptr(), name.len(), file_metadata, loc.line, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index 3578755aae0..33d9bc23890 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, Instance}; use super::utils::{DIB, debug_context}; -use crate::common::CodegenCx; +use crate::common::{AsCCharPtr, CodegenCx}; use crate::llvm; use crate::llvm::debuginfo::DIScope; @@ -36,7 +36,7 @@ pub(crate) fn item_namespace<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'l llvm::LLVMRustDIBuilderCreateNameSpace( DIB(cx), parent_scope, - namespace_name_string.as_ptr().cast(), + namespace_name_string.as_c_char_ptr(), namespace_name_string.len(), false, // ExportSymbols (only relevant for C++ anonymous namespaces) ) diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 33258cb46fa..d338c848754 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -20,6 +20,7 @@ use smallvec::SmallVec; use tracing::debug; use crate::abi::{FnAbi, FnAbiLlvmExt}; +use crate::common::AsCCharPtr; use crate::context::CodegenCx; use crate::llvm::AttributePlace::Function; use crate::llvm::Visibility; @@ -41,7 +42,7 @@ fn declare_raw_fn<'ll>( ) -> &'ll Value { debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty); let llfn = unsafe { - llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_ptr().cast(), name.len(), ty) + llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_c_char_ptr(), name.len(), ty) }; llvm::SetFunctionCallConv(llfn, callconv); @@ -68,7 +69,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// return its Value instead. pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { debug!("declare_global(name={:?})", name); - unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_ptr().cast(), name.len(), ty) } + unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_c_char_ptr(), name.len(), ty) } } /// Declare a C ABI function. @@ -209,7 +210,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// Gets declared value by name. pub(crate) fn get_declared_value(&self, name: &str) -> Option<&'ll Value> { debug!("get_declared_value(name={:?})", name); - unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_ptr().cast(), name.len()) } + unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_c_char_ptr(), name.len()) } } /// Gets defined or externally defined (AvailableExternally linkage) value by diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index d04b5257619..c77e00aed9a 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -258,8 +258,8 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.call_intrinsic("llvm.va_copy", &[args[0].immediate(), args[1].immediate()]) } sym::va_arg => { - match fn_abi.ret.layout.abi { - abi::Abi::Scalar(scalar) => { + match fn_abi.ret.layout.backend_repr { + abi::BackendRepr::Scalar(scalar) => { match scalar.primitive() { Primitive::Int(..) => { if self.cx().size_of(ret_ty).bytes() < 4 { @@ -436,13 +436,13 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } sym::raw_eq => { - use abi::Abi::*; + use abi::BackendRepr::*; let tp_ty = fn_args.type_at(0); let layout = self.layout_of(tp_ty).layout; - let use_integer_compare = match layout.abi() { + let use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, Uninhabited | Vector { .. } => false, - Aggregate { .. } => { + Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), // so we re-use that same threshold here. @@ -549,7 +549,8 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } let llret_ty = if ret_ty.is_simd() - && let abi::Abi::Aggregate { .. } = self.layout_of(ret_ty).layout.abi + && let abi::BackendRepr::Memory { .. } = + self.layout_of(ret_ty).layout.backend_repr { let (size, elem_ty) = ret_ty.simd_size_and_type(self.tcx()); let elem_ll_ty = match elem_ty.kind() { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index acc66076833..8fc586d2c8f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -3,6 +3,7 @@ use std::fmt::Debug; use std::marker::PhantomData; +use std::ptr; use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t}; use rustc_macros::TryFromU32; @@ -85,7 +86,7 @@ pub enum LLVMMachineType { ARM = 0x01c0, } -/// LLVM's Module::ModFlagBehavior, defined in llvm/include/llvm/IR/Module.h. +/// Must match the layout of `LLVMRustModuleFlagMergeBehavior`. /// /// When merging modules (e.g. during LTO), their metadata flags are combined. Conflicts are /// resolved according to the merge behaviors specified here. Flags differing only in merge @@ -93,9 +94,13 @@ pub enum LLVMMachineType { /// /// In order for Rust-C LTO to work, we must specify behaviors compatible with Clang. Notably, /// 'Error' and 'Warning' cannot be mixed for a given flag. +/// +/// There is a stable LLVM-C version of this enum (`LLVMModuleFlagBehavior`), +/// but as of LLVM 19 it does not support all of the enum values in the unstable +/// C++ API. #[derive(Copy, Clone, PartialEq)] #[repr(C)] -pub enum LLVMModFlagBehavior { +pub enum ModuleFlagMergeBehavior { Error = 1, Warning = 2, Require = 3, @@ -704,8 +709,9 @@ unsafe extern "C" { } #[repr(C)] pub struct RustArchiveMember<'a>(InvariantOpaque<'a>); +/// Opaque pointee of `LLVMOperandBundleRef`. #[repr(C)] -pub struct OperandBundleDef<'a>(InvariantOpaque<'a>); +pub(crate) struct OperandBundle<'a>(InvariantOpaque<'a>); #[repr(C)] pub struct Linker<'a>(InvariantOpaque<'a>); @@ -1534,6 +1540,50 @@ unsafe extern "C" { pub fn LLVMGetOrInsertComdat(M: &Module, Name: *const c_char) -> &Comdat; pub fn LLVMSetComdat(V: &Value, C: &Comdat); + + pub(crate) fn LLVMCreateOperandBundle( + Tag: *const c_char, + TagLen: size_t, + Args: *const &'_ Value, + NumArgs: c_uint, + ) -> *mut OperandBundle<'_>; + pub(crate) fn LLVMDisposeOperandBundle(Bundle: ptr::NonNull<OperandBundle<'_>>); + + pub(crate) fn LLVMBuildCallWithOperandBundles<'a>( + B: &Builder<'a>, + Ty: &'a Type, + Fn: &'a Value, + Args: *const &'a Value, + NumArgs: c_uint, + Bundles: *const &OperandBundle<'a>, + NumBundles: c_uint, + Name: *const c_char, + ) -> &'a Value; + pub(crate) fn LLVMBuildInvokeWithOperandBundles<'a>( + B: &Builder<'a>, + Ty: &'a Type, + Fn: &'a Value, + Args: *const &'a Value, + NumArgs: c_uint, + Then: &'a BasicBlock, + Catch: &'a BasicBlock, + Bundles: *const &OperandBundle<'a>, + NumBundles: c_uint, + Name: *const c_char, + ) -> &'a Value; + pub(crate) fn LLVMBuildCallBr<'a>( + B: &Builder<'a>, + Ty: &'a Type, + Fn: &'a Value, + DefaultDest: &'a BasicBlock, + IndirectDests: *const &'a BasicBlock, + NumIndirectDests: c_uint, + Args: *const &'a Value, + NumArgs: c_uint, + Bundles: *const &OperandBundle<'a>, + NumBundles: c_uint, + Name: *const c_char, + ) -> &'a Value; } #[link(name = "llvm-wrapper", kind = "static")] @@ -1619,47 +1669,11 @@ unsafe extern "C" { AttrsLen: size_t, ); - pub fn LLVMRustBuildInvoke<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Fn: &'a Value, - Args: *const &'a Value, - NumArgs: c_uint, - Then: &'a BasicBlock, - Catch: &'a BasicBlock, - OpBundles: *const &OperandBundleDef<'a>, - NumOpBundles: c_uint, - Name: *const c_char, - ) -> &'a Value; - - pub fn LLVMRustBuildCallBr<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Fn: &'a Value, - DefaultDest: &'a BasicBlock, - IndirectDests: *const &'a BasicBlock, - NumIndirectDests: c_uint, - Args: *const &'a Value, - NumArgs: c_uint, - OpBundles: *const &OperandBundleDef<'a>, - NumOpBundles: c_uint, - Name: *const c_char, - ) -> &'a Value; - pub fn LLVMRustSetFastMath(Instr: &Value); pub fn LLVMRustSetAlgebraicMath(Instr: &Value); pub fn LLVMRustSetAllowReassoc(Instr: &Value); // Miscellaneous instructions - pub fn LLVMRustBuildCall<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Fn: &'a Value, - Args: *const &'a Value, - NumArgs: c_uint, - OpBundles: *const &OperandBundleDef<'a>, - NumOpBundles: c_uint, - ) -> &'a Value; pub fn LLVMRustBuildMemCpy<'a>( B: &Builder<'a>, Dst: &'a Value, @@ -1829,21 +1843,21 @@ unsafe extern "C" { /// "compatible" means depends on the merge behaviors involved. pub fn LLVMRustAddModuleFlagU32( M: &Module, - merge_behavior: LLVMModFlagBehavior, - name: *const c_char, - value: u32, + MergeBehavior: ModuleFlagMergeBehavior, + Name: *const c_char, + NameLen: size_t, + Value: u32, ); pub fn LLVMRustAddModuleFlagString( M: &Module, - merge_behavior: LLVMModFlagBehavior, - name: *const c_char, - value: *const c_char, - value_len: size_t, + MergeBehavior: ModuleFlagMergeBehavior, + Name: *const c_char, + NameLen: size_t, + Value: *const c_char, + ValueLen: size_t, ); - pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool; - pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>; pub fn LLVMRustDIBuilderDispose<'a>(Builder: &'a mut DIBuilder<'a>); @@ -2353,13 +2367,6 @@ unsafe extern "C" { pub fn LLVMRustSetDataLayoutFromTargetMachine<'a>(M: &'a Module, TM: &'a TargetMachine); - pub fn LLVMRustBuildOperandBundleDef( - Name: *const c_char, - Inputs: *const &'_ Value, - NumInputs: c_uint, - ) -> &mut OperandBundleDef<'_>; - pub fn LLVMRustFreeOperandBundleDef<'a>(Bundle: &'a mut OperandBundleDef<'a>); - pub fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock); pub fn LLVMRustSetModulePICLevel(M: &Module); @@ -2385,9 +2392,9 @@ unsafe extern "C" { pub fn LLVMRustThinLTOBufferThinLinkDataLen(M: &ThinLTOBuffer) -> size_t; pub fn LLVMRustCreateThinLTOData( Modules: *const ThinLTOModule, - NumModules: c_uint, + NumModules: size_t, PreservedSymbols: *const *const c_char, - PreservedSymbolsLen: c_uint, + PreservedSymbolsLen: size_t, ) -> Option<&'static mut ThinLTOData>; pub fn LLVMRustPrepareThinLTORename( Data: &ThinLTOData, @@ -2412,6 +2419,7 @@ unsafe extern "C" { data: *const u8, len: usize, name: *const u8, + name_len: usize, out_len: &mut usize, ) -> *const u8; diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 6aac2eea81d..00a5cd3b859 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -2,11 +2,12 @@ use std::cell::RefCell; use std::ffi::{CStr, CString}; +use std::ops::Deref; +use std::ptr; use std::str::FromStr; use std::string::FromUtf8Error; use libc::c_uint; -use rustc_data_structures::small_c_str::SmallCStr; use rustc_llvm::RustString; use rustc_target::abi::{Align, Size, WrappingRange}; @@ -17,13 +18,13 @@ pub use self::IntPredicate::*; pub use self::Linkage::*; pub use self::MetadataType::*; pub use self::RealPredicate::*; +pub use self::ffi::*; +use crate::common::AsCCharPtr; pub mod archive_ro; pub mod diagnostic; mod ffi; -pub use self::ffi::*; - impl LLVMRustResult { pub fn into_result(self) -> Result<(), ()> { match self { @@ -53,9 +54,9 @@ pub fn CreateAttrStringValue<'ll>(llcx: &'ll Context, attr: &str, value: &str) - unsafe { LLVMCreateStringAttribute( llcx, - attr.as_ptr().cast(), + attr.as_c_char_ptr(), attr.len().try_into().unwrap(), - value.as_ptr().cast(), + value.as_c_char_ptr(), value.len().try_into().unwrap(), ) } @@ -65,7 +66,7 @@ pub fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &str) -> &'ll Attribute { unsafe { LLVMCreateStringAttribute( llcx, - attr.as_ptr().cast(), + attr.as_c_char_ptr(), attr.len().try_into().unwrap(), std::ptr::null(), 0, @@ -294,7 +295,7 @@ pub fn get_value_name(value: &Value) -> &[u8] { /// Safe wrapper for `LLVMSetValueName2` from a byte slice pub fn set_value_name(value: &Value, name: &[u8]) { unsafe { - let data = name.as_ptr().cast(); + let data = name.as_c_char_ptr(); LLVMSetValueName2(value, data, name.len()); } } @@ -331,24 +332,68 @@ pub fn last_error() -> Option<String> { } } -pub struct OperandBundleDef<'a> { - pub raw: &'a mut ffi::OperandBundleDef<'a>, +/// Owns an [`OperandBundle`], and will dispose of it when dropped. +pub(crate) struct OperandBundleOwned<'a> { + raw: ptr::NonNull<OperandBundle<'a>>, } -impl<'a> OperandBundleDef<'a> { - pub fn new(name: &str, vals: &[&'a Value]) -> Self { - let name = SmallCStr::new(name); - let def = unsafe { - LLVMRustBuildOperandBundleDef(name.as_ptr(), vals.as_ptr(), vals.len() as c_uint) +impl<'a> OperandBundleOwned<'a> { + pub(crate) fn new(name: &str, vals: &[&'a Value]) -> Self { + let raw = unsafe { + LLVMCreateOperandBundle( + name.as_c_char_ptr(), + name.len(), + vals.as_ptr(), + vals.len() as c_uint, + ) }; - OperandBundleDef { raw: def } + OperandBundleOwned { raw: ptr::NonNull::new(raw).unwrap() } } } -impl Drop for OperandBundleDef<'_> { +impl Drop for OperandBundleOwned<'_> { fn drop(&mut self) { unsafe { - LLVMRustFreeOperandBundleDef(&mut *(self.raw as *mut _)); + LLVMDisposeOperandBundle(self.raw); } } } + +impl<'a> Deref for OperandBundleOwned<'a> { + type Target = OperandBundle<'a>; + + fn deref(&self) -> &Self::Target { + // SAFETY: The returned reference is opaque and can only used for FFI. + // It is valid for as long as `&self` is. + unsafe { self.raw.as_ref() } + } +} + +pub(crate) fn add_module_flag_u32( + module: &Module, + merge_behavior: ModuleFlagMergeBehavior, + key: &str, + value: u32, +) { + unsafe { + LLVMRustAddModuleFlagU32(module, merge_behavior, key.as_c_char_ptr(), key.len(), value); + } +} + +pub(crate) fn add_module_flag_str( + module: &Module, + merge_behavior: ModuleFlagMergeBehavior, + key: &str, + value: &str, +) { + unsafe { + LLVMRustAddModuleFlagString( + module, + merge_behavior, + key.as_c_char_ptr(), + key.len(), + value.as_c_char_ptr(), + value.len(), + ); + } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index aa38c02289d..9adb1299b3d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -698,12 +698,9 @@ fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> { let feature = s .strip_prefix(&['+', '-'][..]) .unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s })); - if s.is_empty() { - return None; - } // Rustc-specific feature requests like `+crt-static` or `-crt-static` // are not passed down to LLVM. - if RUSTC_SPECIFIC_FEATURES.contains(&feature) { + if s.is_empty() || RUSTC_SPECIFIC_FEATURES.contains(&feature) { return None; } Some(feature) diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 6be4c3f034f..2b05e24a7ba 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -1,7 +1,7 @@ use std::fmt::Write; use rustc_abi::Primitive::{Float, Int, Pointer}; -use rustc_abi::{Abi, Align, FieldsShape, Scalar, Size, Variants}; +use rustc_abi::{Align, BackendRepr, FieldsShape, Scalar, Size, Variants}; use rustc_codegen_ssa::traits::*; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; @@ -17,13 +17,13 @@ fn uncached_llvm_type<'a, 'tcx>( layout: TyAndLayout<'tcx>, defer: &mut Option<(&'a Type, TyAndLayout<'tcx>)>, ) -> &'a Type { - match layout.abi { - Abi::Scalar(_) => bug!("handled elsewhere"), - Abi::Vector { element, count } => { + match layout.backend_repr { + BackendRepr::Scalar(_) => bug!("handled elsewhere"), + BackendRepr::Vector { element, count } => { let element = layout.scalar_llvm_type_at(cx, element); return cx.type_vector(element, count); } - Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalarPair(..) => {} + BackendRepr::Uninhabited | BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {} } let name = match layout.ty.kind() { @@ -170,16 +170,21 @@ pub(crate) trait LayoutLlvmExt<'tcx> { impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn is_llvm_immediate(&self) -> bool { - match self.abi { - Abi::Scalar(_) | Abi::Vector { .. } => true, - Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, + match self.backend_repr { + BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => true, + BackendRepr::ScalarPair(..) | BackendRepr::Uninhabited | BackendRepr::Memory { .. } => { + false + } } } fn is_llvm_scalar_pair(&self) -> bool { - match self.abi { - Abi::ScalarPair(..) => true, - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false, + match self.backend_repr { + BackendRepr::ScalarPair(..) => true, + BackendRepr::Uninhabited + | BackendRepr::Scalar(_) + | BackendRepr::Vector { .. } + | BackendRepr::Memory { .. } => false, } } @@ -198,7 +203,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. - if let Abi::Scalar(scalar) = self.abi { + if let BackendRepr::Scalar(scalar) = self.backend_repr { // Use a different cache for scalars because pointers to DSTs // can be either wide or thin (data pointers of wide pointers). if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { @@ -248,13 +253,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { } fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { - match self.abi { - Abi::Scalar(scalar) => { + match self.backend_repr { + BackendRepr::Scalar(scalar) => { if scalar.is_bool() { return cx.type_i1(); } } - Abi::ScalarPair(..) => { + BackendRepr::ScalarPair(..) => { // An immediate pair always contains just the two elements, without any padding // filler, as it should never be stored to memory. return cx.type_struct( @@ -287,7 +292,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. - let Abi::ScalarPair(a, b) = self.abi else { + let BackendRepr::ScalarPair(a, b) = self.backend_repr else { bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self); }; let scalar = [a, b][index]; diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 8857fda1e97..796acb6796f 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -322,10 +322,11 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static // Set the appropriate flag based on ABI // This needs to match LLVM `RISCVELFStreamer.cpp` match &*sess.target.llvm_abiname { - "" | "ilp32" | "lp64" => (), + "ilp32" | "lp64" => (), "ilp32f" | "lp64f" => e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE, "ilp32d" | "lp64d" => e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE, - "ilp32e" => e_flags |= elf::EF_RISCV_RVE, + // Note that the `lp64e` is still unstable as it's not (yet) part of the ELF psABI. + "ilp32e" | "lp64e" => e_flags |= elf::EF_RISCV_RVE, _ => bug!("unknown RISC-V ABI name"), } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index e3d11cfaf4f..8445d16befb 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -514,7 +514,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( future: Some(coordinator_thread), phantom: PhantomData, }, - output_filenames: tcx.output_filenames(()).clone(), + output_filenames: Arc::clone(tcx.output_filenames(())), } } @@ -1203,7 +1203,7 @@ fn start_executing_work<B: ExtraBackendMethods>( coordinator_send, expanded_args: tcx.sess.expanded_args.clone(), diag_emitter: shared_emitter.clone(), - output_filenames: tcx.output_filenames(()).clone(), + output_filenames: Arc::clone(tcx.output_filenames(())), regular_module_config: regular_config, metadata_module_config: metadata_config, allocator_module_config: allocator_config, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index a726ee73aaa..cb4c9c078b1 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -7,7 +7,7 @@ use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_n use rustc_attr as attr; 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::par_map; +use rustc_data_structures::sync::{Lrc, par_map}; use rustc_data_structures::unord::UnordMap; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; @@ -21,7 +21,7 @@ use rustc_middle::mir::BinOp; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypingMode}; use rustc_session::Session; use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_span::symbol::sym; @@ -119,7 +119,7 @@ pub fn validate_trivial_unsize<'tcx>( ) -> bool { match (source_data.principal(), target_data.principal()) { (Some(hr_source_principal), Some(hr_target_principal)) => { - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); let universe = infcx.universe(); let ocx = ObligationCtxt::new(&infcx); infcx.enter_forall(hr_target_principal, |target_principal| { @@ -923,7 +923,7 @@ impl CrateInfo { crate_name: UnordMap::with_capacity(n_crates), used_crates, used_crate_source: UnordMap::with_capacity(n_crates), - dependency_formats: tcx.dependency_formats(()).clone(), + dependency_formats: Lrc::clone(tcx.dependency_formats(())), windows_subsystem, natvis_debugger_visualizers: Default::default(), }; @@ -936,7 +936,7 @@ impl CrateInfo { info.crate_name.insert(cnum, tcx.crate_name(cnum)); let used_crate_source = tcx.used_crate_source(cnum); - info.used_crate_source.insert(cnum, used_crate_source.clone()); + info.used_crate_source.insert(cnum, Lrc::clone(used_crate_source)); if tcx.is_profiler_runtime(cnum) { info.profiler_runtime = Some(cnum); } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e3553dc03e1..283740fa664 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -438,7 +438,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => bug!("C-variadic function must have a `VaList` place"), } } - if self.fn_abi.ret.layout.abi.is_uninhabited() { + if self.fn_abi.ret.layout.is_uninhabited() { // Functions with uninhabited return values are marked `noreturn`, // so we should make sure that we never actually do. // We play it safe by using a well-defined `abort`, but we could go for immediate UB @@ -774,7 +774,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(if do_panic { let msg_str = with_no_visible_paths!({ with_no_trimmed_paths!({ - if layout.abi.is_uninhabited() { + if layout.is_uninhabited() { // Use this error even for the other intrinsics as it is more precise. format!("attempted to instantiate uninhabited type `{ty}`") } else if requirement == ValidityRequirement::Zero { @@ -1532,7 +1532,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // the load would just produce `OperandValue::Ref` instead // of the `OperandValue::Immediate` we need for the call. llval = bx.load(bx.backend_type(arg.layout), llval, align); - if let abi::Abi::Scalar(scalar) = arg.layout.abi { + if let abi::BackendRepr::Scalar(scalar) = arg.layout.backend_repr { if scalar.is_bool() { bx.range_metadata(llval, WrappingRange { start: 0, end: 1 }); } diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 15f45b226f5..54b9c9cc89f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -1,8 +1,8 @@ +use rustc_abi::BackendRepr; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, mir, span_bug}; -use rustc_target::abi::Abi; use super::FunctionCx; use crate::errors; @@ -86,7 +86,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .map(|field| { if let Some(prim) = field.try_to_scalar() { let layout = bx.layout_of(field_ty); - let Abi::Scalar(scalar) = layout.abi else { + let BackendRepr::Scalar(scalar) = layout.backend_repr else { bug!("from_const: invalid ByVal layout: {:#?}", layout); }; bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout)) diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 146f55f95c2..21d20475408 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -2,6 +2,7 @@ use std::collections::hash_map::Entry; use std::marker::PhantomData; use std::ops::Range; +use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, Size, VariantIdx}; use rustc_data_structures::fx::FxHashMap; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -11,7 +12,6 @@ use rustc_middle::{bug, mir, ty}; use rustc_session::config::DebugInfo; use rustc_span::symbol::{Symbol, kw}; use rustc_span::{BytePos, Span, hygiene}; -use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx}; use super::operand::{OperandRef, OperandValue}; use super::place::{PlaceRef, PlaceValue}; @@ -510,7 +510,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // be marked as a `LocalVariable` for MSVC debuggers to visualize // their data correctly. (See #81894 & #88625) let var_ty_layout = self.cx.layout_of(var_ty); - if let Abi::ScalarPair(_, _) = var_ty_layout.abi { + if let BackendRepr::ScalarPair(_, _) = var_ty_layout.backend_repr { VariableKind::LocalVariable } else { VariableKind::ArgumentVariable(arg_index) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 88ceff327d0..19101ec2d1b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -4,7 +4,7 @@ use std::fmt; use arrayvec::ArrayVec; use either::Either; use rustc_abi as abi; -use rustc_abi::{Abi, Align, Size}; +use rustc_abi::{Align, BackendRepr, Size}; use rustc_middle::bug; use rustc_middle::mir::interpret::{Pointer, Scalar, alloc_range}; use rustc_middle::mir::{self, ConstValue}; @@ -163,7 +163,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let val = match val { ConstValue::Scalar(x) => { - let Abi::Scalar(scalar) = layout.abi else { + let BackendRepr::Scalar(scalar) = layout.backend_repr else { bug!("from_const: invalid ByVal layout: {:#?}", layout); }; let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); @@ -171,7 +171,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } ConstValue::ZeroSized => return OperandRef::zero_sized(layout), ConstValue::Slice { data, meta } => { - let Abi::ScalarPair(a_scalar, _) = layout.abi else { + let BackendRepr::ScalarPair(a_scalar, _) = layout.backend_repr else { bug!("from_const: invalid ScalarPair layout: {:#?}", layout); }; let a = Scalar::from_pointer( @@ -221,14 +221,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { // case where some of the bytes are initialized and others are not. So, we need an extra // check that walks over the type of `mplace` to make sure it is truly correct to treat this // like a `Scalar` (or `ScalarPair`). - match layout.abi { - Abi::Scalar(s @ abi::Scalar::Initialized { .. }) => { + match layout.backend_repr { + BackendRepr::Scalar(s @ abi::Scalar::Initialized { .. }) => { let size = s.size(bx); assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout)); OperandRef { val: OperandValue::Immediate(val), layout } } - Abi::ScalarPair( + BackendRepr::ScalarPair( a @ abi::Scalar::Initialized { .. }, b @ abi::Scalar::Initialized { .. }, ) => { @@ -322,7 +322,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { llval: V, layout: TyAndLayout<'tcx>, ) -> Self { - let val = if let Abi::ScalarPair(..) = layout.abi { + let val = if let BackendRepr::ScalarPair(..) = layout.backend_repr { debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout); // Deconstruct the immediate aggregate. @@ -343,7 +343,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let field = self.layout.field(bx.cx(), i); let offset = self.layout.fields.offset(i); - let mut val = match (self.val, self.layout.abi) { + let mut val = match (self.val, self.layout.backend_repr) { // If the field is ZST, it has no data. _ if field.is_zst() => OperandValue::ZeroSized, @@ -356,7 +356,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } // Extract a scalar component from a pair. - (OperandValue::Pair(a_llval, b_llval), Abi::ScalarPair(a, b)) => { + (OperandValue::Pair(a_llval, b_llval), BackendRepr::ScalarPair(a, b)) => { if offset.bytes() == 0 { assert_eq!(field.size, a.size(bx.cx())); OperandValue::Immediate(a_llval) @@ -368,30 +368,30 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } // `#[repr(simd)]` types are also immediate. - (OperandValue::Immediate(llval), Abi::Vector { .. }) => { + (OperandValue::Immediate(llval), BackendRepr::Vector { .. }) => { OperandValue::Immediate(bx.extract_element(llval, bx.cx().const_usize(i as u64))) } _ => bug!("OperandRef::extract_field({:?}): not applicable", self), }; - match (&mut val, field.abi) { + match (&mut val, field.backend_repr) { (OperandValue::ZeroSized, _) => {} ( OperandValue::Immediate(llval), - Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. }, + BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) | BackendRepr::Vector { .. }, ) => { // Bools in union fields needs to be truncated. *llval = bx.to_immediate(*llval, field); } - (OperandValue::Pair(a, b), Abi::ScalarPair(a_abi, b_abi)) => { + (OperandValue::Pair(a, b), BackendRepr::ScalarPair(a_abi, b_abi)) => { // Bools in union fields needs to be truncated. *a = bx.to_immediate_scalar(*a, a_abi); *b = bx.to_immediate_scalar(*b, b_abi); } // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]); - (OperandValue::Immediate(llval), Abi::Aggregate { sized: true }) => { - assert_matches!(self.layout.abi, Abi::Vector { .. }); + (OperandValue::Immediate(llval), BackendRepr::Memory { sized: true }) => { + assert_matches!(self.layout.backend_repr, BackendRepr::Vector { .. }); let llfield_ty = bx.cx().backend_type(field); @@ -400,7 +400,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { bx.store(*llval, llptr, field.align.abi); *llval = bx.load(llfield_ty, llptr, field.align.abi); } - (OperandValue::Immediate(_), Abi::Uninhabited | Abi::Aggregate { sized: false }) => { + ( + OperandValue::Immediate(_), + BackendRepr::Uninhabited | BackendRepr::Memory { sized: false }, + ) => { bug!() } (OperandValue::Pair(..), _) => bug!(), @@ -494,7 +497,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> { bx.store_with_flags(val, dest.val.llval, dest.val.align, flags); } OperandValue::Pair(a, b) => { - let Abi::ScalarPair(a_scalar, b_scalar) = dest.layout.abi else { + let BackendRepr::ScalarPair(a_scalar, b_scalar) = dest.layout.backend_repr else { bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout); }; let b_offset = a_scalar.size(bx).align_to(b_scalar.align(bx).abi); @@ -645,7 +648,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // However, some SIMD types do not actually use the vector ABI // (in particular, packed SIMD types do not). Ensure we exclude those. let layout = bx.layout_of(constant_ty); - if let Abi::Vector { .. } = layout.abi { + if let BackendRepr::Vector { .. } = layout.backend_repr { let (llval, ty) = self.immediate_const_vector(bx, constant); return OperandRef { val: OperandValue::Immediate(llval), diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index a7d5541481a..15c8e534461 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -55,7 +55,7 @@ impl<V: CodegenObject> PlaceValue<V> { /// Creates a `PlaceRef` to this location with the given type. pub fn with_type<'tcx>(self, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> { assert!( - layout.is_unsized() || layout.abi.is_uninhabited() || self.llextra.is_none(), + layout.is_unsized() || layout.is_uninhabited() || self.llextra.is_none(), "Had pointer metadata {:?} for sized type {layout:?}", self.llextra, ); @@ -239,7 +239,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let dl = &bx.tcx().data_layout; let cast_to_layout = bx.cx().layout_of(cast_to); let cast_to = bx.cx().immediate_backend_type(cast_to_layout); - if self.layout.abi.is_uninhabited() { + if self.layout.is_uninhabited() { return bx.cx().const_poison(cast_to); } let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { @@ -358,7 +358,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, variant_index: VariantIdx, ) { - if self.layout.for_variant(bx.cx(), variant_index).abi.is_uninhabited() { + if self.layout.for_variant(bx.cx(), variant_index).is_uninhabited() { // We play it safe by using a well-defined `abort`, but we could go for immediate UB // if that turns out to be helpful. bx.abort(); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 82fea4c58e1..86cf0f9614d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -203,10 +203,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Option<OperandValue<Bx::Value>> { // Check for transmutes that are always UB. if operand.layout.size != cast.size - || operand.layout.abi.is_uninhabited() - || cast.abi.is_uninhabited() + || operand.layout.is_uninhabited() + || cast.is_uninhabited() { - if !operand.layout.abi.is_uninhabited() { + if !operand.layout.is_uninhabited() { // Since this is known statically and the input could have existed // without already having hit UB, might as well trap for it. bx.abort(); @@ -555,7 +555,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { assert!(bx.cx().is_backend_immediate(cast)); let to_backend_ty = bx.cx().immediate_backend_type(cast); - if operand.layout.abi.is_uninhabited() { + if operand.layout.is_uninhabited() { let val = OperandValue::Immediate(bx.cx().const_poison(to_backend_ty)); return OperandRef { val, layout: cast }; } @@ -1136,17 +1136,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValueKind::ZeroSized } else if self.cx.is_backend_immediate(layout) { assert!(!self.cx.is_backend_scalar_pair(layout)); - OperandValueKind::Immediate(match layout.abi { - abi::Abi::Scalar(s) => s, - abi::Abi::Vector { element, .. } => element, + OperandValueKind::Immediate(match layout.backend_repr { + abi::BackendRepr::Scalar(s) => s, + abi::BackendRepr::Vector { element, .. } => element, x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"), }) } else if self.cx.is_backend_scalar_pair(layout) { - let abi::Abi::ScalarPair(s1, s2) = layout.abi else { + let abi::BackendRepr::ScalarPair(s1, s2) = layout.backend_repr else { span_bug!( self.mir.span, "Couldn't translate {:?} as backend scalar pair", - layout.abi, + layout.backend_repr, ); }; OperandValueKind::Pair(s1, s2) diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 50a51714146..768a0439ab5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -1,13 +1,13 @@ use std::assert_matches::assert_matches; use std::ops::Deref; +use rustc_abi::{Align, BackendRepr, Scalar, Size, WrappingRange}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::{Instance, Ty}; use rustc_session::config::OptLevel; use rustc_span::Span; use rustc_target::abi::call::FnAbi; -use rustc_target::abi::{Abi, Align, Scalar, Size, WrappingRange}; use super::abi::AbiBuilderMethods; use super::asm::AsmBuilderMethods; @@ -162,7 +162,7 @@ pub trait BuilderMethods<'a, 'tcx>: fn from_immediate(&mut self, val: Self::Value) -> Self::Value; fn to_immediate(&mut self, val: Self::Value, layout: TyAndLayout<'_>) -> Self::Value { - if let Abi::Scalar(scalar) = layout.abi { + if let BackendRepr::Scalar(scalar) = layout.backend_repr { self.to_immediate_scalar(val, scalar) } else { val diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 004fb12419f..b6c227638a1 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -64,8 +64,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let ConstCx { tcx, body, .. } = *ccx; FlowSensitiveAnalysis::new(NeedsDrop, ccx) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -94,8 +93,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let ConstCx { tcx, body, .. } = *ccx; FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -124,8 +122,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let ConstCx { tcx, body, .. } = *ccx; FlowSensitiveAnalysis::new(HasMutInterior, ccx) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -240,8 +237,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { let always_live_locals = &always_storage_live_locals(&ccx.body); let mut maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) - .into_engine(ccx.tcx, &ccx.body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(ccx.tcx, &ccx.body, None) .into_results_cursor(&ccx.body); // And then check all `Return` in the MIR, and if a local is "maybe live" at a @@ -593,7 +589,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Typeck only does a "non-const" check since it operates on HIR and cannot distinguish // which path expressions are getting called on and which path expressions are only used // as function pointers. This is required for correctness. - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(body.typing_mode(tcx)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args); diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 56da6791847..dcdaafaecc2 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -32,14 +32,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self { let def_id = body.source.def_id().expect_local(); let param_env = tcx.param_env(def_id); - Self::new_with_param_env(tcx, body, param_env) - } - pub fn new_with_param_env( - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local()); ConstCx { body, tcx, param_env, const_kind } } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 3ac06ae6491..961a27ae9ba 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -116,7 +116,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(body.typing_mode(tcx)); let mut selcx = SelectionContext::new(&infcx); let implsrc = selcx.select(&obligation); diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 547030a1854..e8637ba45cf 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -114,11 +114,11 @@ impl Qualif for HasMutInterior { ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]), ); - let infcx = cx - .tcx - .infer_ctxt() - .with_opaque_type_inference(cx.body.source.def_id().expect_local()) - .build(); + // FIXME(#132279): This should eventually use the already defined hidden types. + let infcx = cx.tcx.infer_ctxt().build(ty::TypingMode::analysis_in_body( + cx.tcx, + cx.body.source.def_id().expect_local(), + )); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index 743924faa21..bc2661c4fc7 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -131,7 +131,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { interp_ok(match bin_op { Eq | Ne | Lt | Le | Gt | Ge => { // Types can differ, e.g. fn ptrs with different `for`. - assert_eq!(left.layout.abi, right.layout.abi); + assert_eq!(left.layout.backend_repr, right.layout.backend_repr); let size = ecx.pointer_size(); // Just compare the bits. ScalarPairs are compared lexicographically. // We thus always compare pairs and simply fill scalars up with 0. diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 7319c251bbd..81b9d73b952 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -1,6 +1,7 @@ use std::sync::atomic::Ordering::Relaxed; use either::{Left, Right}; +use rustc_abi::{self as abi, BackendRepr}; use rustc_hir::def::DefKind; use rustc_middle::bug; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo}; @@ -12,7 +13,6 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::{DUMMY_SP, Span}; -use rustc_target::abi::{self, Abi}; use tracing::{debug, instrument, trace}; use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine}; @@ -174,8 +174,8 @@ pub(super) fn op_to_const<'tcx>( // type (it's used throughout the compiler and having it work just on literals is not enough) // and we want it to be fast (i.e., don't go to an `Allocation` and reconstruct the `Scalar` // from its byte-serialized form). - let force_as_immediate = match op.layout.abi { - Abi::Scalar(abi::Scalar::Initialized { .. }) => true, + let force_as_immediate = match op.layout.backend_repr { + BackendRepr::Scalar(abi::Scalar::Initialized { .. }) => true, // We don't *force* `ConstValue::Slice` for `ScalarPair`. This has the advantage that if the // input `op` is a place, then turning it into a `ConstValue` and back into a `OpTy` will // not have to generate any duplicate allocations (we preserve the original `AllocId` in diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index d54c5b750f0..5f0bc8539ee 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -395,7 +395,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { #[inline(always)] fn enforce_validity(ecx: &InterpCx<'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool { - ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited() + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.is_uninhabited() } fn load_mir( diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 9e80e666ba9..ea88b2ed22e 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,10 +1,10 @@ +use rustc_abi::{BackendRepr, VariantIdx}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::DUMMY_SP; -use rustc_target::abi::{Abi, VariantIdx}; use tracing::{debug, instrument, trace}; use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const}; @@ -117,7 +117,7 @@ fn const_to_valtree_inner<'tcx>( let val = ecx.read_immediate(place).unwrap(); // We could allow wide raw pointers where both sides are integers in the future, // but for now we reject them. - if matches!(val.layout.abi, Abi::ScalarPair(..)) { + if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) { return Err(ValTreeCreationError::NonSupportedType(ty)); } let val = val.to_scalar(); @@ -311,7 +311,7 @@ pub fn valtree_to_const_value<'tcx>( // Fast path to avoid some allocations. return mir::ConstValue::ZeroSized; } - if layout.abi.is_scalar() + if layout.backend_repr.is_scalar() && (matches!(ty.kind(), ty::Tuple(_)) || matches!(ty.kind(), ty::Adt(def, _) if def.is_struct())) { diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 85d99900c6c..1915bf75c95 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -172,8 +172,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // must be compatible. So we just accept everything with Pointer ABI as compatible, // even if this will accept some code that is not stably guaranteed to work. // This also handles function pointers. - let thin_pointer = |layout: TyAndLayout<'tcx>| match layout.abi { - abi::Abi::Scalar(s) => match s.primitive() { + let thin_pointer = |layout: TyAndLayout<'tcx>| match layout.backend_repr { + abi::BackendRepr::Scalar(s) => match s.primitive() { abi::Primitive::Pointer(addr_space) => Some(addr_space), _ => None, }, diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 64b15611316..60d5e904bd9 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -274,7 +274,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Scalar<M::Provenance>> { // Let's make sure v is sign-extended *if* it has a signed type. - let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`. + let signed = src_layout.backend_repr.is_signed(); // Also asserts that abi is `Scalar`. let v = match src_layout.ty.kind() { Uint(_) | RawPtr(..) | FnPtr(..) => scalar.to_uint(src_layout.size)?, diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 81e0b1e12ca..bb4ac9556ea 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -27,7 +27,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // discriminant, so we cannot do anything here. // When evaluating we will always error before even getting here, but ConstProp 'executes' // dead code, so we cannot ICE here. - if dest.layout().for_variant(self, variant_index).abi.is_uninhabited() { + if dest.layout().for_variant(self, variant_index).is_uninhabited() { throw_ub!(UninhabitedEnumVariantWritten(variant_index)) } @@ -86,7 +86,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // For consistency with `write_discriminant`, and to make sure that // `project_downcast` cannot fail due to strange layouts, we declare immediate UB // for uninhabited variants. - if op.layout().for_variant(self, index).abi.is_uninhabited() { + if op.layout().for_variant(self, index).is_uninhabited() { throw_ub!(UninhabitedEnumVariantRead(index)) } } @@ -112,7 +112,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Read tag and sanity-check `tag_layout`. let tag_val = self.read_immediate(&self.project_field(op, tag_field)?)?; assert_eq!(tag_layout.size, tag_val.layout.size); - assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed()); + assert_eq!(tag_layout.backend_repr.is_signed(), tag_val.layout.backend_repr.is_signed()); trace!("tag value: {}", tag_val); // Figure out which discriminant and variant this corresponds to. @@ -203,7 +203,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Reading the discriminant of an uninhabited variant is UB. This is the basis for the // `uninhabited_enum_branching` MIR pass. It also ensures consistency with // `write_discriminant`. - if op.layout().for_variant(self, index).abi.is_uninhabited() { + if op.layout().for_variant(self, index).is_uninhabited() { throw_ub!(UninhabitedEnumVariantRead(index)) } interp_ok(index) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index a1c773a4b80..9043bd3e28e 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -3,13 +3,15 @@ use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::at::ToTrace; -use rustc_infer::traits::ObligationCause; +use rustc_infer::traits::{ObligationCause, Reveal}; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout, }; -use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance}; +use rustc_middle::ty::{ + self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypingMode, Variance, +}; use rustc_middle::{mir, span_bug}; use rustc_session::Limit; use rustc_span::Span; @@ -114,6 +116,7 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { /// This test should be symmetric, as it is primarily about layout compatibility. pub(super) fn mir_assign_valid_types<'tcx>( tcx: TyCtxt<'tcx>, + typing_mode: TypingMode<'tcx>, param_env: ParamEnv<'tcx>, src: TyAndLayout<'tcx>, dest: TyAndLayout<'tcx>, @@ -122,7 +125,7 @@ pub(super) fn mir_assign_valid_types<'tcx>( // all normal lifetimes are erased, higher-ranked types with their // late-bound lifetimes are still around and can lead to type // differences. - if util::relate_types(tcx, param_env, Variance::Covariant, src.ty, dest.ty) { + if util::relate_types(tcx, typing_mode, param_env, Variance::Covariant, src.ty, dest.ty) { // Make sure the layout is equal, too -- just to be safe. Miri really // needs layout equality. For performance reason we skip this check when // the types are equal. Equal types *can* have different layouts when @@ -142,6 +145,7 @@ pub(super) fn mir_assign_valid_types<'tcx>( #[cfg_attr(not(debug_assertions), inline(always))] pub(super) fn from_known_layout<'tcx>( tcx: TyCtxtAt<'tcx>, + typing_mode: TypingMode<'tcx>, param_env: ParamEnv<'tcx>, known_layout: Option<TyAndLayout<'tcx>>, compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>, @@ -151,7 +155,13 @@ pub(super) fn from_known_layout<'tcx>( Some(known_layout) => { if cfg!(debug_assertions) { let check_layout = compute()?; - if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) { + if !mir_assign_valid_types( + tcx.tcx, + typing_mode, + param_env, + check_layout, + known_layout, + ) { span_bug!( tcx.span, "expected type differs from actual type.\nexpected: {}\nactual: {}", @@ -201,6 +211,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } + pub fn typing_mode(&self) -> TypingMode<'tcx> { + debug_assert_eq!(self.param_env.reveal(), Reveal::All); + TypingMode::PostAnalysis + } + /// Returns the span of the currently executed statement/terminator. /// This is the span typically used for error reporting. #[inline(always)] @@ -325,7 +340,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return true; } // Slow path: spin up an inference context to check if these traits are sufficiently equal. - let infcx = self.tcx.infer_ctxt().build(); + let infcx = self.tcx.infer_ctxt().build(self.typing_mode()); let ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy_with_span(self.cur_span()); // equate the two trait refs after normalization diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 4e603f57c56..80e14ee887c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -364,7 +364,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let msg = match requirement { // For *all* intrinsics we first check `is_uninhabited` to give a more specific // error message. - _ if layout.abi.is_uninhabited() => format!( + _ if layout.is_uninhabited() => format!( "aborted execution: attempted to instantiate uninhabited type `{ty}`" ), ValidityRequirement::Inhabited => bug!("handled earlier"), @@ -563,7 +563,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.binary_op(mir_op.wrapping_to_overflowing().unwrap(), l, r)?.to_scalar_pair(); interp_ok(if overflowed.to_bool()? { let size = l.layout.size; - if l.layout.abi.is_signed() { + if l.layout.backend_repr.is_signed() { // For signed ints the saturated value depends on the sign of the first // term since the sign of the second term can be inferred from this and // the fact that the operation has overflowed (if either is 0 no diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index cd5e2aeca85..a130ae89bcb 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -5,7 +5,7 @@ use std::assert_matches::assert_matches; use either::{Either, Left, Right}; use rustc_abi as abi; -use rustc_abi::{Abi, HasDataLayout, Size}; +use rustc_abi::{BackendRepr, HasDataLayout, Size}; use rustc_hir::def::Namespace; use rustc_middle::mir::interpret::ScalarSizeMismatch; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutOf, TyAndLayout}; @@ -114,9 +114,9 @@ impl<Prov: Provenance> Immediate<Prov> { } /// Assert that this immediate is a valid value for the given ABI. - pub fn assert_matches_abi(self, abi: Abi, msg: &str, cx: &impl HasDataLayout) { + pub fn assert_matches_abi(self, abi: BackendRepr, msg: &str, cx: &impl HasDataLayout) { match (self, abi) { - (Immediate::Scalar(scalar), Abi::Scalar(s)) => { + (Immediate::Scalar(scalar), BackendRepr::Scalar(s)) => { assert_eq!(scalar.size(), s.size(cx), "{msg}: scalar value has wrong size"); if !matches!(s.primitive(), abi::Primitive::Pointer(..)) { // This is not a pointer, it should not carry provenance. @@ -126,7 +126,7 @@ impl<Prov: Provenance> Immediate<Prov> { ); } } - (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { + (Immediate::ScalarPair(a_val, b_val), BackendRepr::ScalarPair(a, b)) => { assert_eq!( a_val.size(), a.size(cx), @@ -244,7 +244,7 @@ impl<'tcx, Prov: Provenance> std::ops::Deref for ImmTy<'tcx, Prov> { impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_scalar(val: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self { - debug_assert!(layout.abi.is_scalar(), "`ImmTy::from_scalar` on non-scalar layout"); + debug_assert!(layout.backend_repr.is_scalar(), "`ImmTy::from_scalar` on non-scalar layout"); debug_assert_eq!(val.size(), layout.size); ImmTy { imm: val.into(), layout } } @@ -252,7 +252,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_scalar_pair(a: Scalar<Prov>, b: Scalar<Prov>, layout: TyAndLayout<'tcx>) -> Self { debug_assert!( - matches!(layout.abi, Abi::ScalarPair(..)), + matches!(layout.backend_repr, BackendRepr::ScalarPair(..)), "`ImmTy::from_scalar_pair` on non-scalar-pair layout" ); let imm = Immediate::ScalarPair(a, b); @@ -263,9 +263,9 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { pub fn from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Self { // Without a `cx` we cannot call `assert_matches_abi`. debug_assert!( - match (imm, layout.abi) { - (Immediate::Scalar(..), Abi::Scalar(..)) => true, - (Immediate::ScalarPair(..), Abi::ScalarPair(..)) => true, + match (imm, layout.backend_repr) { + (Immediate::Scalar(..), BackendRepr::Scalar(..)) => true, + (Immediate::ScalarPair(..), BackendRepr::ScalarPair(..)) => true, (Immediate::Uninit, _) if layout.is_sized() => true, _ => false, }, @@ -356,7 +356,11 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { fn offset_(&self, offset: Size, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self { // Verify that the input matches its type. if cfg!(debug_assertions) { - self.assert_matches_abi(self.layout.abi, "invalid input to Immediate::offset", cx); + self.assert_matches_abi( + self.layout.backend_repr, + "invalid input to Immediate::offset", + cx, + ); } // `ImmTy` have already been checked to be in-bounds, so we can just check directly if this // remains in-bounds. This cannot actually be violated since projections are type-checked @@ -370,19 +374,19 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { ); // This makes several assumptions about what layouts we will encounter; we match what // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`). - let inner_val: Immediate<_> = match (**self, self.layout.abi) { + let inner_val: Immediate<_> = match (**self, self.layout.backend_repr) { // If the entire value is uninit, then so is the field (can happen in ConstProp). (Immediate::Uninit, _) => Immediate::Uninit, // If the field is uninhabited, we can forget the data (can happen in ConstProp). // `enum S { A(!), B, C }` is an example of an enum with Scalar layout that // has an `Uninhabited` variant, which means this case is possible. - _ if layout.abi.is_uninhabited() => Immediate::Uninit, + _ if layout.is_uninhabited() => Immediate::Uninit, // the field contains no information, can be left uninit // (Scalar/ScalarPair can contain even aligned ZST, not just 1-ZST) _ if layout.is_zst() => Immediate::Uninit, // some fieldless enum variants can have non-zero size but still `Aggregate` ABI... try // to detect those here and also give them no data - _ if matches!(layout.abi, Abi::Aggregate { .. }) + _ if matches!(layout.backend_repr, BackendRepr::Memory { .. }) && matches!(layout.variants, abi::Variants::Single { .. }) && matches!(&layout.fields, abi::FieldsShape::Arbitrary { offsets, .. } if offsets.len() == 0) => { @@ -394,7 +398,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { **self } // extract fields from types with `ScalarPair` ABI - (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { + (Immediate::ScalarPair(a_val, b_val), BackendRepr::ScalarPair(a, b)) => { Immediate::from(if offset.bytes() == 0 { a_val } else { @@ -411,7 +415,11 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { ), }; // Ensure the new layout matches the new value. - inner_val.assert_matches_abi(layout.abi, "invalid field type in Immediate::offset", cx); + inner_val.assert_matches_abi( + layout.backend_repr, + "invalid field type in Immediate::offset", + cx, + ); ImmTy::from_immediate(inner_val, layout) } @@ -567,8 +575,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // case where some of the bytes are initialized and others are not. So, we need an extra // check that walks over the type of `mplace` to make sure it is truly correct to treat this // like a `Scalar` (or `ScalarPair`). - interp_ok(match mplace.layout.abi { - Abi::Scalar(abi::Scalar::Initialized { value: s, .. }) => { + interp_ok(match mplace.layout.backend_repr { + BackendRepr::Scalar(abi::Scalar::Initialized { value: s, .. }) => { let size = s.size(self); assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); let scalar = alloc.read_scalar( @@ -577,7 +585,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { )?; Some(ImmTy::from_scalar(scalar, mplace.layout)) } - Abi::ScalarPair( + BackendRepr::ScalarPair( abi::Scalar::Initialized { value: a, .. }, abi::Scalar::Initialized { value: b, .. }, ) => { @@ -637,9 +645,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { op: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { if !matches!( - op.layout().abi, - Abi::Scalar(abi::Scalar::Initialized { .. }) - | Abi::ScalarPair(abi::Scalar::Initialized { .. }, abi::Scalar::Initialized { .. }) + op.layout().backend_repr, + BackendRepr::Scalar(abi::Scalar::Initialized { .. }) + | BackendRepr::ScalarPair( + abi::Scalar::Initialized { .. }, + abi::Scalar::Initialized { .. } + ) ) { span_bug!(self.cur_span(), "primitive read not possible for type: {}", op.layout().ty); } @@ -762,6 +773,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { )?; if !mir_assign_valid_types( *self.tcx, + self.typing_mode(), self.param_env, self.layout_of(normalized_place_ty)?, op.layout, @@ -821,7 +833,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }) }; let layout = - from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty).into())?; + from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || { + self.layout_of(ty).into() + })?; let imm = match val_val { mir::ConstValue::Indirect { alloc_id, offset } => { // This is const data, no mutation allowed. diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index b28ac68ac54..cf280e0c1ae 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -114,7 +114,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let l_bits = left.layout.size.bits(); // Compute the equivalent shift modulo `size` that is in the range `0..size`. (This is // the one MIR operator that does *not* directly map to a single LLVM operation.) - let (shift_amount, overflow) = if right.layout.abi.is_signed() { + let (shift_amount, overflow) = if right.layout.backend_repr.is_signed() { let shift_amount = r_signed(); let rem = shift_amount.rem_euclid(l_bits.into()); // `rem` is guaranteed positive, so the `unwrap` cannot fail @@ -126,7 +126,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; let shift_amount = u32::try_from(shift_amount).unwrap(); // we brought this in the range `0..size` so this will always fit // Compute the shifted result. - let result = if left.layout.abi.is_signed() { + let result = if left.layout.backend_repr.is_signed() { let l = l_signed(); let result = match bin_op { Shl | ShlUnchecked => l.checked_shl(shift_amount).unwrap(), @@ -147,7 +147,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if overflow && let Some(intrinsic) = throw_ub_on_overflow { throw_ub!(ShiftOverflow { intrinsic, - shift_amount: if right.layout.abi.is_signed() { + shift_amount: if right.layout.backend_repr.is_signed() { Either::Right(r_signed()) } else { Either::Left(r_unsigned()) @@ -171,7 +171,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let size = left.layout.size; // Operations that need special treatment for signed integers - if left.layout.abi.is_signed() { + if left.layout.backend_repr.is_signed() { let op: Option<fn(&i128, &i128) -> bool> = match bin_op { Lt => Some(i128::lt), Le => Some(i128::le), @@ -250,7 +250,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { BitXor => ImmTy::from_uint(l ^ r, left.layout), _ => { - assert!(!left.layout.abi.is_signed()); + assert!(!left.layout.backend_repr.is_signed()); let op: fn(u128, u128) -> (u128, bool) = match bin_op { Add | AddUnchecked | AddWithOverflow => u128::overflowing_add, Sub | SubUnchecked | SubWithOverflow => u128::overflowing_sub, @@ -315,7 +315,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ptr = left.to_scalar().to_pointer(self)?; let pointee_ty = left.layout.ty.builtin_deref(true).unwrap(); let pointee_layout = self.layout_of(pointee_ty)?; - assert!(pointee_layout.abi.is_sized()); + assert!(pointee_layout.is_sized()); // The size always fits in `i64` as it can be at most `isize::MAX`. let pointee_size = i64::try_from(pointee_layout.size.bytes()).unwrap(); @@ -332,7 +332,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } let offset_bytes = val.to_target_isize(self)?; - if !right.layout.abi.is_signed() && offset_bytes < 0 { + if !right.layout.backend_repr.is_signed() && offset_bytes < 0 { // We were supposed to do an unsigned offset but the result is negative -- this // can only mean that the cast wrapped around. throw_ub!(PointerArithOverflow) @@ -518,14 +518,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(match null_op { SizeOf => { - if !layout.abi.is_sized() { + if !layout.is_sized() { span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`"); } let val = layout.size.bytes(); ImmTy::from_uint(val, usize_layout()) } AlignOf => { - if !layout.abi.is_sized() { + if !layout.is_sized() { span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`"); } let val = layout.align.abi.bytes(); diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 81b926a1b65..cc8d1db6cfb 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -5,11 +5,11 @@ use std::assert_matches::assert_matches; use either::{Either, Left, Right}; +use rustc_abi::{Align, BackendRepr, HasDataLayout, Size}; use rustc_ast::Mutability; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::{bug, mir, span_bug}; -use rustc_target::abi::{Abi, Align, HasDataLayout, Size}; use tracing::{instrument, trace}; use super::{ @@ -540,6 +540,7 @@ where )?; if !mir_assign_valid_types( *self.tcx, + self.typing_mode(), self.param_env, self.layout_of(normalized_place_ty)?, place.layout, @@ -659,7 +660,7 @@ where // Unfortunately this is too expensive to do in release builds. if cfg!(debug_assertions) { src.assert_matches_abi( - local_layout.abi, + local_layout.backend_repr, "invalid immediate for given destination place", self, ); @@ -683,7 +684,11 @@ where ) -> InterpResult<'tcx> { // We use the sizes from `value` below. // Ensure that matches the type of the place it is written to. - value.assert_matches_abi(layout.abi, "invalid immediate for given destination place", self); + value.assert_matches_abi( + layout.backend_repr, + "invalid immediate for given destination place", + self, + ); // Note that it is really important that the type here is the right one, and matches the // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here // to handle padding properly, which is only correct if we never look at this data with the @@ -700,7 +705,7 @@ where alloc.write_scalar(alloc_range(Size::ZERO, scalar.size()), scalar) } Immediate::ScalarPair(a_val, b_val) => { - let Abi::ScalarPair(a, b) = layout.abi else { + let BackendRepr::ScalarPair(a, b) = layout.backend_repr else { span_bug!( self.cur_span(), "write_immediate_to_mplace: invalid ScalarPair layout: {:#?}", @@ -866,8 +871,13 @@ where ) -> InterpResult<'tcx> { // We do NOT compare the types for equality, because well-typed code can // actually "transmute" `&mut T` to `&T` in an assignment without a cast. - let layout_compat = - mir_assign_valid_types(*self.tcx, self.param_env, src.layout(), dest.layout()); + let layout_compat = mir_assign_valid_types( + *self.tcx, + self.typing_mode(), + self.param_env, + src.layout(), + dest.layout(), + ); if !allow_transmute && !layout_compat { span_bug!( self.cur_span(), diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 3bc9f46aea0..50c0446b3cd 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -596,12 +596,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return interp_ok(layout); } - let layout = from_known_layout(self.tcx, self.param_env, layout, || { - let local_ty = frame.body.local_decls[local].ty; - let local_ty = - self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?; - self.layout_of(local_ty).into() - })?; + let layout = + from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || { + let local_ty = frame.body.local_decls[local].ty; + let local_ty = + self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?; + self.layout_of(local_ty).into() + })?; // Layouts of locals are requested a lot, so we cache them. state.layout.set(Some(layout)); diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index b6120ce82fe..cd2c1ef3613 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -11,6 +11,10 @@ use std::num::NonZero; use either::{Left, Right}; use hir::def::DefKind; +use rustc_abi::{ + BackendRepr, FieldIdx, FieldsShape, Scalar as ScalarAbi, Size, VariantIdx, Variants, + WrappingRange, +}; use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -23,9 +27,6 @@ use rustc_middle::mir::interpret::{ use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::{Symbol, sym}; -use rustc_target::abi::{ - Abi, FieldIdx, FieldsShape, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange, -}; use tracing::trace; use super::machine::AllocMap; @@ -422,7 +423,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // Reset provenance: ensure slice tail metadata does not preserve provenance, // and ensure all pointers do not preserve partial provenance. if self.reset_provenance_and_padding { - if matches!(imm.layout.abi, Abi::Scalar(..)) { + if matches!(imm.layout.backend_repr, BackendRepr::Scalar(..)) { // A thin pointer. If it has provenance, we don't have to do anything. // If it does not, ensure we clear the provenance in memory. if matches!(imm.to_scalar(), Scalar::Int(..)) { @@ -542,7 +543,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { throw_validation_failure!(self.path, NullPtr { ptr_kind }) } // Do not allow references to uninhabited types. - if place.layout.abi.is_uninhabited() { + if place.layout.is_uninhabited() { let ty = place.layout.ty; throw_validation_failure!(self.path, PtrToUninhabited { ptr_kind, ty }) } @@ -867,7 +868,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { /// Add the entire given place to the "data" range of this visit. fn add_data_range_place(&mut self, place: &PlaceTy<'tcx, M::Provenance>) { // Only sized places can be added this way. - debug_assert!(place.layout.abi.is_sized()); + debug_assert!(place.layout.is_sized()); if let Some(data_bytes) = self.data_bytes.as_mut() { let offset = Self::data_range_offset(self.ecx, place); data_bytes.add_range(offset, place.layout.size); @@ -945,7 +946,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { layout: TyAndLayout<'tcx>, ) -> Cow<'e, RangeSet> { assert!(layout.ty.is_union()); - assert!(layout.abi.is_sized(), "there are no unsized unions"); + assert!(layout.is_sized(), "there are no unsized unions"); let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env); return M::cached_union_data_range(ecx, layout.ty, || { let mut out = RangeSet(Vec::new()); @@ -981,7 +982,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { let elem = layout.field(cx, 0); // Fast-path for large arrays of simple types that do not contain any padding. - if elem.abi.is_scalar() { + if elem.backend_repr.is_scalar() { out.add_range(base_offset, elem.size * count); } else { for idx in 0..count { @@ -1299,19 +1300,19 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // FIXME: We could avoid some redundant checks here. For newtypes wrapping // scalars, we do the same check on every "level" (e.g., first we check // MyNewtype and then the scalar in there). - match val.layout.abi { - Abi::Uninhabited => { + match val.layout.backend_repr { + BackendRepr::Uninhabited => { let ty = val.layout.ty; throw_validation_failure!(self.path, UninhabitedVal { ty }); } - Abi::Scalar(scalar_layout) => { + BackendRepr::Scalar(scalar_layout) => { if !scalar_layout.is_uninit_valid() { // There is something to check here. let scalar = self.read_scalar(val, ExpectedKind::InitScalar)?; self.visit_scalar(scalar, scalar_layout)?; } } - Abi::ScalarPair(a_layout, b_layout) => { + BackendRepr::ScalarPair(a_layout, b_layout) => { // We can only proceed if *both* scalars need to be initialized. // FIXME: find a way to also check ScalarPair when one side can be uninit but // the other must be init. @@ -1322,12 +1323,12 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, self.visit_scalar(b, b_layout)?; } } - Abi::Vector { .. } => { + BackendRepr::Vector { .. } => { // No checks here, we assume layout computation gets this right. // (This is harder to check since Miri does not represent these as `Immediate`. We // also cannot use field projections since this might be a newtype around a vector.) } - Abi::Aggregate { .. } => { + BackendRepr::Memory { .. } => { // Nothing to do. } } 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 649179d5b1e..f743525f359 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -1,9 +1,9 @@ +use rustc_abi::{BackendRepr, FieldsShape, Scalar, Variants}; use rustc_middle::bug; use rustc_middle::ty::layout::{ HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement, }; use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; -use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants}; use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine}; use crate::interpret::{InterpCx, MemoryKind}; @@ -29,7 +29,7 @@ pub fn check_validity_requirement<'tcx>( // There is nothing strict or lax about inhabitedness. if kind == ValidityRequirement::Inhabited { - return Ok(!layout.abi.is_uninhabited()); + return Ok(!layout.is_uninhabited()); } let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env); @@ -111,12 +111,12 @@ fn check_validity_requirement_lax<'tcx>( }; // Check the ABI. - let valid = match this.abi { - Abi::Uninhabited => false, // definitely UB - Abi::Scalar(s) => scalar_allows_raw_init(s), - Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), - Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s), - Abi::Aggregate { .. } => true, // Fields are checked below. + let valid = match this.backend_repr { + BackendRepr::Uninhabited => false, // definitely UB + BackendRepr::Scalar(s) => scalar_allows_raw_init(s), + BackendRepr::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), + BackendRepr::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s), + BackendRepr::Memory { .. } => true, // Fields are checked below. }; if !valid { // This is definitely not okay. diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index 3ea54146fc7..0cf27d30c36 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -5,27 +5,18 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Variance}; +use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, TypingMode, Variance}; use rustc_trait_selection::traits::ObligationCtxt; -/// Returns whether the two types are equal up to subtyping. -/// -/// This is used in case we don't know the expected subtyping direction -/// and still want to check whether anything is broken. -pub fn is_equal_up_to_subtyping<'tcx>( +/// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`. +pub fn sub_types<'tcx>( tcx: TyCtxt<'tcx>, + typing_mode: TypingMode<'tcx>, param_env: ParamEnv<'tcx>, src: Ty<'tcx>, dest: Ty<'tcx>, ) -> bool { - // Fast path. - if src == dest { - return true; - } - - // Check for subtyping in either direction. - relate_types(tcx, param_env, Variance::Covariant, src, dest) - || relate_types(tcx, param_env, Variance::Covariant, dest, src) + relate_types(tcx, typing_mode, param_env, Variance::Covariant, src, dest) } /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`. @@ -35,6 +26,7 @@ pub fn is_equal_up_to_subtyping<'tcx>( /// because we want to check for type equality. pub fn relate_types<'tcx>( tcx: TyCtxt<'tcx>, + typing_mode: TypingMode<'tcx>, param_env: ParamEnv<'tcx>, variance: Variance, src: Ty<'tcx>, @@ -45,7 +37,7 @@ pub fn relate_types<'tcx>( } let mut builder = tcx.infer_ctxt().ignoring_regions(); - let infcx = builder.build(); + let infcx = builder.build(typing_mode); let ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy(); let src = ocx.normalize(&cause, param_env, src); diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index 66a1addfb52..25a9dbb2c11 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -8,7 +8,7 @@ mod type_name; pub use self::alignment::{is_disaligned, is_within_packed}; pub use self::check_validity_requirement::check_validity_requirement; -pub use self::compare_types::{is_equal_up_to_subtyping, relate_types}; +pub use self::compare_types::{relate_types, sub_types}; pub use self::type_name::type_name; /// Classify whether an operator is "left-homogeneous", i.e., the LHS has the diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index a59dea557bb..e2585c02388 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1395,7 +1395,7 @@ pub fn install_ice_hook( } let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default()); - let using_internal_features_hook = using_internal_features.clone(); + let using_internal_features_hook = Arc::clone(&using_internal_features); panic::update_hook(Box::new( move |default_hook: &(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static), info: &PanicHookInfo<'_>| { diff --git a/compiler/rustc_error_codes/src/error_codes/E0801.md b/compiler/rustc_error_codes/src/error_codes/E0801.md new file mode 100644 index 00000000000..c89feb9b308 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0801.md @@ -0,0 +1,51 @@ +The `self` parameter in a method has an invalid generic "receiver type". + +Erroneous code example: + +```compile_fail,E0801 +struct Foo; + +impl Foo { + fn foo<R: std::ops::Deref<Target=Self>>(self: R) {} +} +``` + +or alternatively, + +```compile_fail,E0801 +struct Foo; + +impl Foo { + fn foo(self: impl std::ops::Deref<Target=Self>) {} +} +``` + +Methods take a special first parameter, termed `self`. It's normal to +use `self`, `&self` or `&mut self`, which are syntactic sugar for +`self: Self`, `self: &Self`, and `self: &mut Self` respectively. +But it's also possible to use more sophisticated types of `self` +parameter, for instance `std::rc::Rc<Self>`. The set of allowable +`Self` types is extensible using the nightly feature +[Arbitrary self types][AST]. +This will extend the valid set of `Self` types to anything which implements +`std::ops::Deref<Target=Self>`, for example `Rc<Self>`, `Box<Self>`, or +your own smart pointers that do the same. + +However, even with that feature, the `self` type must be concrete. +Generic `self` types are not permitted. Specifically, a `self` type will +be rejected if it is a type parameter defined on the method. + +These are OK: + +``` +struct Foo; + +impl Foo { + fn foo(self) {} + fn foo2(self: std::rc::Rc<Self>) {} // or some other similar + // smart pointer if you enable arbitrary self types and + // the pointer implements Deref<Target=Self> +} +``` + +[AST]: https://doc.rust-lang.org/unstable-book/language-features/arbitrary-self-types.html diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 27a34d6003d..29f3277d399 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -540,6 +540,7 @@ E0797: 0797, E0798: 0798, E0799: 0799, E0800: 0800, +E0801: 0801, ); ) } diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 00eaf4d5a86..41ebe4ae267 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start annotate-snippets = "0.11" derive_setters = "0.1.6" +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 335432c9cfe..b4a651b10b1 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -173,7 +173,7 @@ impl AnnotateSnippetEmitter { source_map.ensure_source_file_source_present(&file); ( format!("{}", source_map.filename_for_diagnostics(&file.name)), - source_string(file.clone(), &line), + source_string(Lrc::clone(&file), &line), line.line_index, line.annotations, ) diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 19529f06ef1..09a608dda7b 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -5,12 +5,12 @@ use std::num::ParseIntError; use std::path::{Path, PathBuf}; use std::process::ExitStatus; +use rustc_abi::TargetDataLayoutErrors; use rustc_ast_pretty::pprust; use rustc_macros::Subdiagnostic; use rustc_span::Span; use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; -use rustc_target::abi::TargetDataLayoutErrors; use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; use rustc_type_ir::{ClosureKind, FloatTy}; use {rustc_ast as ast, rustc_hir as hir}; diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 0ccc71ae06c..6552cf224ea 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1555,7 +1555,7 @@ impl HumanEmitter { // Get the left-side margin to remove it let mut whitespace_margin = usize::MAX; for line_idx in 0..annotated_file.lines.len() { - let file = annotated_file.file.clone(); + let file = Lrc::clone(&annotated_file.file); let line = &annotated_file.lines[line_idx]; if let Some(source_string) = line.line_index.checked_sub(1).and_then(|l| file.get_line(l)) @@ -1646,7 +1646,7 @@ impl HumanEmitter { let depths = self.render_source_line( &mut buffer, - annotated_file.file.clone(), + Lrc::clone(&annotated_file.file), &annotated_file.lines[line_idx], width_offset, code_offset, @@ -2529,7 +2529,12 @@ impl FileWithAnnotatedLines { // | | | // | |______foo // | baz - add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start()); + add_annotation_to_file( + &mut output, + Lrc::clone(&file), + ann.line_start, + ann.as_start(), + ); // 4 is the minimum vertical length of a multiline span when presented: two lines // of code and two lines of underline. This is not true for the special case where // the beginning doesn't have an underline, but the current logic seems to be @@ -2545,11 +2550,11 @@ impl FileWithAnnotatedLines { .unwrap_or(ann.line_start); for line in ann.line_start + 1..until { // Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`). - add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); + add_annotation_to_file(&mut output, Lrc::clone(&file), line, ann.as_line()); } let line_end = ann.line_end - 1; if middle < line_end { - add_annotation_to_file(&mut output, file.clone(), line_end, ann.as_line()); + add_annotation_to_file(&mut output, Lrc::clone(&file), line_end, ann.as_line()); } } else { end_ann.annotation_type = AnnotationType::Singleline; diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 1534e256520..91e2b9996cd 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -367,9 +367,9 @@ impl Diagnostic { ColorConfig::Always | ColorConfig::Auto => dst = Box::new(termcolor::Ansi::new(dst)), ColorConfig::Never => {} } - HumanEmitter::new(dst, je.fallback_bundle.clone()) + HumanEmitter::new(dst, Lrc::clone(&je.fallback_bundle)) .short_message(short) - .sm(Some(je.sm.clone())) + .sm(Some(Lrc::clone(&je.sm))) .fluent_bundle(je.fluent_bundle.clone()) .diagnostic_width(je.diagnostic_width) .macro_backtrace(je.macro_backtrace) diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index fcf3352bfc5..f26c7c1ba0b 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -74,7 +74,7 @@ expand_helper_attribute_name_invalid = `{$name}` cannot be a name of derive helper attribute expand_incomplete_parse = - macro expansion ignores token `{$token}` and any following + macro expansion ignores {$descr} and any tokens following .label = caused by the macro expansion here .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context .suggestion_add_semi = you might be missing a semicolon here diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 5682c574552..7bd7c305539 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -275,7 +275,7 @@ pub(crate) struct UnsupportedKeyValue { pub(crate) struct IncompleteParse<'a> { #[primary_span] pub span: Span, - pub token: Cow<'a, str>, + pub descr: String, #[label] pub label_span: Span, pub macro_path: &'a ast::Path, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 5ffafcaa542..04ac7891023 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -21,6 +21,7 @@ use rustc_errors::PResult; use rustc_feature::Features; use rustc_parse::parser::{ AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma, + token_descr, }; use rustc_parse::validate_attr; use rustc_session::lint::BuiltinLintDiag; @@ -1013,7 +1014,7 @@ pub(crate) fn ensure_complete_parse<'a>( span: Span, ) { if parser.token != token::Eof { - let token = pprust::token_to_string(&parser.token); + let descr = token_descr(&parser.token); // Avoid emitting backtrace info twice. let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root()); @@ -1029,7 +1030,7 @@ pub(crate) fn ensure_complete_parse<'a>( parser.dcx().emit_err(IncompleteParse { span: def_site_span, - token, + descr, label_span: span, macro_path, kind_name, diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 103bbb05e7f..ffcce1e52f6 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -2,10 +2,9 @@ use std::borrow::Cow; use rustc_ast::token::{self, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage}; use rustc_macros::Subdiagnostic; -use rustc_parse::parser::{Parser, Recovery}; +use rustc_parse::parser::{Parser, Recovery, token_descr}; use rustc_session::parse::ParseSess; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Ident; @@ -336,17 +335,11 @@ pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Spa /// other tokens, this is "unexpected token...". pub(super) fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> { if let Some(expected_token) = expected_token { - Cow::from(format!( - "expected `{}`, found `{}`", - pprust::token_to_string(expected_token), - pprust::token_to_string(tok), - )) + Cow::from(format!("expected {}, found {}", token_descr(expected_token), token_descr(tok))) } else { match tok.kind { token::Eof => Cow::from("unexpected end of macro invocation"), - _ => { - Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok))) - } + _ => Cow::from(format!("no rules expected {}", token_descr(tok))), } } } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 3903203da3d..2a8dddc1e00 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -78,11 +78,10 @@ use std::rc::Rc; pub(crate) use NamedMatch::*; pub(crate) use ParseResult::*; use rustc_ast::token::{self, DocComment, NonterminalKind, Token}; -use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_lint_defs::pluralize; -use rustc_parse::parser::{ParseNtResult, Parser}; +use rustc_parse::parser::{ParseNtResult, Parser, token_descr}; use rustc_span::Span; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; @@ -150,7 +149,7 @@ impl Display for MatcherLoc { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { MatcherLoc::Token { token } | MatcherLoc::SequenceSep { separator: token } => { - write!(f, "`{}`", pprust::token_to_string(token)) + write!(f, "{}", token_descr(token)) } MatcherLoc::MetaVarDecl { bind, kind, .. } => { write!(f, "meta-variable `${bind}")?; @@ -622,7 +621,7 @@ impl TtParser { // possible next positions into `next_mps`. After some post-processing, the contents of // `next_mps` replenish `cur_mps` and we start over again. self.cur_mps.clear(); - self.cur_mps.push(MatcherPos { idx: 0, matches: self.empty_matches.clone() }); + self.cur_mps.push(MatcherPos { idx: 0, matches: Rc::clone(&self.empty_matches) }); loop { self.next_mps.clear(); diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 34811ca2b35..b77d02e630a 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -5,6 +5,7 @@ use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, LitKind, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Lrc; use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize}; use rustc_parse::lexer::nfc_normalize; use rustc_parse::parser::ParseNtResult; @@ -293,7 +294,7 @@ pub(super) fn transcribe<'a>( // `Delimiter::Invisible` to maintain parsing priorities. // `Interpolated` is currently used for such groups in rustc parser. marker.visit_span(&mut sp); - TokenTree::token_alone(token::Interpolated(nt.clone()), sp) + TokenTree::token_alone(token::Interpolated(Lrc::clone(nt)), sp) } MatchedSeq(..) => { // We were unable to descend far enough. This is an error. diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index ac922f184dd..e910415c345 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -224,6 +224,8 @@ declare_features! ( (accepted, i128_type, "1.26.0", Some(35118)), /// Allows the use of `if let` expressions. (accepted, if_let, "1.0.0", None), + /// Rescoping temporaries in `if let` to align with Rust 2024. + (accepted, if_let_rescope, "CURRENT_RUSTC_VERSION", Some(124085)), /// Allows top level or-patterns (`p | q`) in `if let` and `while let`. (accepted, if_while_or_patterns, "1.33.0", Some(48215)), /// Allows lifetime elision in `impl` headers. For example: diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 93047d420ad..a99d9048886 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -505,8 +505,6 @@ declare_features! ( (unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)), /// Allows `if let` guard in match arms. (unstable, if_let_guard, "1.47.0", Some(51114)), - /// Rescoping temporaries in `if let` to align with Rust 2024. - (unstable, if_let_rescope, "1.83.0", Some(124085)), /// Allows `impl Trait` to be used inside associated types (RFC 2515). (unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063)), /// Allows `impl Trait` as output type in `Fn` traits in return position of functions. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1c268c8bbe0..fa76f8652ea 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2627,7 +2627,6 @@ impl<'hir> Ty<'hir> { } TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty), TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(), - TyKind::OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args), TyKind::Path(QPath::TypeRelative(ty, segment)) => { ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args) } @@ -2746,19 +2745,8 @@ pub struct BareFnTy<'hir> { pub struct OpaqueTy<'hir> { pub hir_id: HirId, pub def_id: LocalDefId, - pub generics: &'hir Generics<'hir>, pub bounds: GenericBounds<'hir>, - pub origin: OpaqueTyOrigin, - /// Return-position impl traits (and async futures) must "reify" any late-bound - /// lifetimes that are captured from the function signature they originate from. - /// - /// This is done by generating a new early-bound lifetime parameter local to the - /// opaque which is instantiated in the function signature with the late-bound - /// lifetime. - /// - /// This mapping associated a captured lifetime (first parameter) with the new - /// early-bound lifetime that was generated for the opaque. - pub lifetime_mapping: &'hir [(&'hir Lifetime, LocalDefId)], + pub origin: OpaqueTyOrigin<LocalDefId>, pub span: Span, } @@ -2796,33 +2784,35 @@ pub struct PreciseCapturingNonLifetimeArg { pub res: Res, } -#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(HashStable_Generic, Encodable, Decodable)] pub enum RpitContext { Trait, TraitImpl, } /// From whence the opaque type came. -#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)] -pub enum OpaqueTyOrigin { +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(HashStable_Generic, Encodable, Decodable)] +pub enum OpaqueTyOrigin<D> { /// `-> impl Trait` FnReturn { /// The defining function. - parent: LocalDefId, + parent: D, // Whether this is an RPITIT (return position impl trait in trait) in_trait_or_impl: Option<RpitContext>, }, /// `async fn` AsyncFn { /// The defining function. - parent: LocalDefId, + parent: D, // Whether this is an AFIT (async fn in trait) in_trait_or_impl: Option<RpitContext>, }, /// type aliases: `type Foo = impl Trait;` TyAlias { /// The type alias or associated type parent of the TAIT/ATPIT - parent: LocalDefId, + parent: D, /// associated types in impl blocks for traits. in_assoc_ty: bool, }, @@ -2861,12 +2851,7 @@ pub enum TyKind<'hir> { /// Type parameters may be stored in each `PathSegment`. Path(QPath<'hir>), /// An opaque type definition itself. This is only used for `impl Trait`. - /// - /// The generic argument list contains the lifetimes (and in the future - /// possibly parameters) that are actually bound on the `impl Trait`. - /// - /// The last parameter specifies whether this opaque appears in a trait definition. - OpaqueDef(&'hir OpaqueTy<'hir>, &'hir [GenericArg<'hir>]), + OpaqueDef(&'hir OpaqueTy<'hir>), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax), @@ -3991,7 +3976,6 @@ impl<'hir> Node<'hir> { | Node::TraitItem(TraitItem { generics, .. }) | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), Node::Item(item) => item.kind.generics(), - Node::OpaqueTy(opaque) => Some(opaque.generics), _ => None, } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 322f8e2a517..a453af3f7fd 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -896,9 +896,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul TyKind::Path(ref qpath) => { try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span)); } - TyKind::OpaqueDef(opaque, lifetimes) => { + TyKind::OpaqueDef(opaque) => { try_visit!(visitor.visit_opaque_ty(opaque)); - walk_list!(visitor, visit_generic_arg, lifetimes); } TyKind::Array(ref ty, ref length) => { try_visit!(visitor.visit_ty(ty)); @@ -1188,10 +1187,8 @@ pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>( } pub fn walk_opaque_ty<'v, V: Visitor<'v>>(visitor: &mut V, opaque: &'v OpaqueTy<'v>) -> V::Result { - let &OpaqueTy { hir_id, def_id: _, generics, bounds, origin: _, lifetime_mapping: _, span: _ } = - opaque; + let &OpaqueTy { hir_id, def_id: _, bounds, origin: _, span: _ } = opaque; try_visit!(visitor.visit_id(hir_id)); - try_visit!(walk_generics(visitor, generics)); walk_list!(visitor, visit_param_bound, bounds); V::Result::output() } diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 04ca7f123d3..3c8887f08bc 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -10,6 +10,7 @@ doctest = false [dependencies] # tidy-alphabetical-start itertools = "0.12" +rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 507297ce162..38b11aa4017 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -149,10 +149,6 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice .label = parameter captured again here -hir_analysis_effects_without_next_solver = using `#![feature(effects)]` without enabling next trait solver globally - .note = the next trait solver must be enabled globally for the effects feature to work correctly - .help = use `-Znext-solver` to enable - hir_analysis_empty_specialization = specialization impl does not specialize any associated items .note = impl is a specialization of this impl @@ -238,6 +234,12 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a .help = consider moving this inherent impl into the crate defining the type if possible .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items +hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}` + .note = type of `self` must not be a method generic parameter type + +hir_analysis_invalid_generic_receiver_ty_help = + use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty}` .note = type of `self` must be `Self` or a type that dereferences to it diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 09ddc6ca9de..9b02651a8bd 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -84,11 +84,11 @@ impl<'tcx> Bounds<'tcx> { &mut self, tcx: TyCtxt<'tcx>, bound_trait_ref: ty::PolyTraitRef<'tcx>, - host: ty::HostPolarity, + constness: ty::BoundConstness, span: Span, ) { if tcx.is_const_trait(bound_trait_ref.def_id()) { - self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, host), span)); + self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, constness), span)); } else { tcx.dcx().span_delayed_bug(span, "tried to lower {host:?} bound for non-const trait"); } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 97f3f1c8ef2..476814c261e 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1,6 +1,7 @@ use std::cell::LazyCell; use std::ops::ControlFlow; +use rustc_abi::FieldIdx; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::MultiSpan; use rustc_errors::codes::*; @@ -23,13 +24,13 @@ use rustc_middle::ty::{ TypeVisitableExt, }; use rustc_session::lint::builtin::UNINHABITED_STATIC; -use rustc_target::abi::FieldIdx; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_type_ir::fold::TypeFoldable; use tracing::{debug, instrument}; +use ty::TypingMode; use {rustc_attr as attr, rustc_hir as hir}; use super::compare_impl_item::{check_type_bounds, compare_impl_method, compare_impl_ty}; @@ -172,7 +173,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { return; } }; - if layout.abi.is_uninhabited() { + if layout.is_uninhabited() { tcx.node_span_lint( UNINHABITED_STATIC, tcx.local_def_id_to_hir_id(def_id), @@ -267,7 +268,7 @@ fn check_opaque_meets_bounds<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span, - origin: &hir::OpaqueTyOrigin, + origin: &hir::OpaqueTyOrigin<LocalDefId>, ) -> Result<(), ErrorGuaranteed> { let defining_use_anchor = match *origin { hir::OpaqueTyOrigin::FnReturn { parent, .. } @@ -276,7 +277,8 @@ fn check_opaque_meets_bounds<'tcx>( }; let param_env = tcx.param_env(defining_use_anchor); - let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build(); + // FIXME(#132279): This should eventually use the already defined hidden types. + let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, defining_use_anchor)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let args = match *origin { @@ -675,7 +677,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { DefKind::OpaqueTy => { check_opaque_precise_captures(tcx, def_id); - let origin = tcx.opaque_type_origin(def_id); + let origin = tcx.local_opaque_ty_origin(def_id); if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } = origin && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id) @@ -819,8 +821,7 @@ pub(super) fn check_specialization_validity<'tcx>( let result = opt_result.unwrap_or(Ok(())); if let Err(parent_impl) = result { - // FIXME(effects) the associated type from effects could be specialized - if !tcx.is_impl_trait_in_trait(impl_item) && !tcx.is_effects_desugared_assoc_ty(impl_item) { + if !tcx.is_impl_trait_in_trait(impl_item) { report_forbidden_specialization(tcx, impl_item, parent_impl); } else { tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default")); @@ -1675,8 +1676,8 @@ pub(super) fn check_coroutine_obligations( // typeck writeback gives us predicates with their regions erased. // As borrowck already has checked lifetimes, we do not need to do it again. .ignoring_regions() - .with_opaque_type_inference(def_id) - .build(); + // FIXME(#132279): This should eventually use the already defined hidden types. + .build(TypingMode::analysis_in_body(tcx, def_id)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for (predicate, cause) in &typeck_results.coroutine_stalled_predicates { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 9de96b7ba77..0b7d3f8b085 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; use rustc_middle::ty::{ self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitableExt, Upcast, + TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_span::Span; @@ -218,7 +218,7 @@ fn compare_method_predicate_entailment<'tcx>( tcx.const_conditions(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args), ) .map(|(trait_ref, _)| { - trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe) + trait_ref.to_host_effect_clause(tcx, ty::BoundConstness::Maybe) }), ); } @@ -228,7 +228,7 @@ fn compare_method_predicate_entailment<'tcx>( let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); debug!(caller_bounds=?param_env.caller_bounds()); - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); // Create obligations for each predicate declared by the impl @@ -272,7 +272,7 @@ fn compare_method_predicate_entailment<'tcx>( tcx, cause, param_env, - const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + const_condition.to_host_effect_clause(tcx, ty::BoundConstness::Maybe), )); } } @@ -516,7 +516,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ObligationCause::misc(tcx.def_span(impl_m_def_id), impl_m_def_id), ); - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); // Normalize the impl signature with fresh variables for lifetime inference. @@ -1196,7 +1196,7 @@ fn compare_self_type<'tcx>( let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().input(0); let param_env = ty::ParamEnv::reveal_all(); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty); let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty); match ExplicitSelf::determine(self_arg_ty, can_eq_self) { @@ -1801,7 +1801,7 @@ fn compare_const_predicate_entailment<'tcx>( ObligationCause::misc(impl_ct_span, impl_ct_def_id), ); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let impl_ct_own_bounds = impl_ct_predicates.instantiate_own_identity(); @@ -1942,7 +1942,7 @@ fn compare_type_predicate_entailment<'tcx>( tcx.const_conditions(trait_ty.def_id).instantiate_own(tcx, trait_to_impl_args), ) .map(|(trait_ref, _)| { - trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe) + trait_ref.to_host_effect_clause(tcx, ty::BoundConstness::Maybe) }), ); } @@ -1951,7 +1951,7 @@ fn compare_type_predicate_entailment<'tcx>( let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); debug!(caller_bounds=?param_env.caller_bounds()); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for (predicate, span) in impl_ty_own_bounds { @@ -1985,7 +1985,7 @@ fn compare_type_predicate_entailment<'tcx>( tcx, cause, param_env, - const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + const_condition.to_host_effect_clause(tcx, ty::BoundConstness::Maybe), )); } } @@ -2036,13 +2036,13 @@ pub(super) fn check_type_bounds<'tcx>( let impl_ty_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id); let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); // A synthetic impl Trait for RPITIT desugaring or assoc type for effects desugaring has no HIR, // which we currently use to get the span for an impl's associated type. Instead, for these, // use the def_span for the synthesized associated type. - let impl_ty_span = if impl_ty.is_impl_trait_in_trait() || impl_ty.is_effects_desugaring { + let impl_ty_span = if impl_ty.is_impl_trait_in_trait() { tcx.def_span(impl_ty_def_id) } else { match tcx.hir_node_by_def_id(impl_ty_def_id) { @@ -2091,7 +2091,7 @@ pub(super) fn check_type_bounds<'tcx>( tcx, mk_cause(span), param_env, - c.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + c.to_host_effect_clause(tcx, ty::BoundConstness::Maybe), ) }), ); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 2d6b9813271..646c104f1f5 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -8,7 +8,7 @@ use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, Reveal}; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, + TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_span::Span; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -132,7 +132,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing); let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy()); - let ref infcx = tcx.infer_ctxt().build(); + let ref infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new(infcx); // Normalize the bounds. This has two purposes: diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 97a29b32c01..1c9bbe627fb 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -9,7 +9,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::util::CheckRegions; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode}; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -124,7 +124,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( adt_def_id: LocalDefId, adt_to_impl_args: GenericArgsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let impl_span = tcx.def_span(drop_impl_def_id.to_def_id()); diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 7da2cd93d4e..0beb1f98d56 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -4,7 +4,7 @@ use rustc_hir as hir; use rustc_hir::Node; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::span_bug; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_session::config::EntryFnType; use rustc_span::Span; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; @@ -128,7 +128,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span }); return; }; - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = traits::ObligationCause::new( return_ty_span, main_diagnostics_def_id, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index bbff00cd3b3..e95669c9d40 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -1,5 +1,6 @@ use std::assert_matches::debug_assert_matches; +use rustc_abi::FieldIdx; use rustc_ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxIndexSet; use rustc_hir::{self as hir, LangItem}; @@ -8,7 +9,6 @@ use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintT use rustc_session::lint; use rustc_span::Symbol; use rustc_span::def_id::LocalDefId; -use rustc_target::abi::FieldIdx; use rustc_target::asm::{ InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo, }; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 58210aaa066..e9eea36a0e6 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -74,6 +74,7 @@ pub mod wfcheck; use std::num::NonZero; pub use check::{check_abi, check_abi_fn_ptr}; +use rustc_abi::VariantIdx; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -84,13 +85,12 @@ use rustc_infer::infer::{self, TyCtxtInferExt as _}; use rustc_infer::traits::ObligationCause; use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::{BytePos, DUMMY_SP, Span, Symbol}; -use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _; @@ -530,7 +530,7 @@ fn suggestion_signature<'tcx>( let ty = tcx.type_of(assoc.def_id).instantiate_identity(); let val = tcx .infer_ctxt() - .build() + .build(TypingMode::non_body_analysis()) .err_ctxt() .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty) .unwrap_or_else(|| "value".to_string()); @@ -620,7 +620,7 @@ pub fn check_function_signature<'tcx>( let param_env = ty::ParamEnv::empty(); - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); let actual_sig = tcx.fn_sig(fn_id).instantiate_identity(); diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index bfa088fdefc..679f6ccb816 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -464,8 +464,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h hir::ExprKind::If(cond, then, Some(otherwise)) => { let expr_cx = visitor.cx; - let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope() - { + let data = if expr.span.at_least_rust_2024() { ScopeData::IfThenRescope } else { ScopeData::IfThen @@ -480,8 +479,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h hir::ExprKind::If(cond, then, None) => { let expr_cx = visitor.cx; - let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope() - { + let data = if expr.span.at_least_rust_2024() { ScopeData::IfThenRescope } else { ScopeData::IfThen diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 499e42d31c9..d01c3784ade 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; @@ -106,7 +106,7 @@ where F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> Result<(), ErrorGuaranteed>, { let param_env = tcx.param_env(body_def_id); - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env }; @@ -765,7 +765,7 @@ fn test_region_obligations<'tcx>( // Unfortunately, we have to use a new `InferCtxt` each call, because // region constraints get added and solved there and we need to test each // call individually. - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); add_constraints(&infcx); @@ -904,7 +904,6 @@ fn check_impl_item<'tcx>( hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span), _ => (None, impl_item.span), }; - check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig) } @@ -1389,7 +1388,7 @@ fn check_impl<'tcx>( ObligationCauseCode::WellFormed(None), ), wfcx.param_env, - bound.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + bound.to_host_effect_clause(tcx, ty::BoundConstness::Maybe), )) } } @@ -1725,8 +1724,11 @@ fn check_method_receiver<'tcx>( } else { None }; + let generics = tcx.generics_of(method.def_id); - if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) { + let receiver_validity = + receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level, generics); + if let Err(receiver_validity_err) = receiver_validity { return Err(match arbitrary_self_types_level { // Wherever possible, emit a message advising folks that the features // `arbitrary_self_types` or `arbitrary_self_types_pointers` might @@ -1737,7 +1739,9 @@ fn check_method_receiver<'tcx>( receiver_ty, self_ty, Some(ArbitrarySelfTypesLevel::Basic), - ) => + generics, + ) + .is_ok() => { // Report error; would have worked with `arbitrary_self_types`. feature_err( @@ -1759,7 +1763,9 @@ fn check_method_receiver<'tcx>( receiver_ty, self_ty, Some(ArbitrarySelfTypesLevel::WithPointers), - ) => + generics, + ) + .is_ok() => { // Report error; would have worked with `arbitrary_self_types_pointers`. feature_err( @@ -1777,13 +1783,45 @@ fn check_method_receiver<'tcx>( _ => // Report error; would not have worked with `arbitrary_self_types[_pointers]`. { - tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }) + match receiver_validity_err { + ReceiverValidityError::DoesNotDeref => { + tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }) + } + ReceiverValidityError::MethodGenericParamUsed => { + tcx.dcx().emit_err(errors::InvalidGenericReceiverTy { span, receiver_ty }) + } + } } }); } Ok(()) } +/// Error cases which may be returned from `receiver_is_valid`. These error +/// cases are generated in this function as they may be unearthed as we explore +/// the `autoderef` chain, but they're converted to diagnostics in the caller. +enum ReceiverValidityError { + /// The self type does not get to the receiver type by following the + /// autoderef chain. + DoesNotDeref, + /// A type was found which is a method type parameter, and that's not allowed. + MethodGenericParamUsed, +} + +/// Confirms that a type is not a type parameter referring to one of the +/// method's type params. +fn confirm_type_is_not_a_method_generic_param( + ty: Ty<'_>, + method_generics: &ty::Generics, +) -> Result<(), ReceiverValidityError> { + if let ty::Param(param) = ty.kind() { + if (param.index as usize) >= method_generics.parent_count { + return Err(ReceiverValidityError::MethodGenericParamUsed); + } + } + Ok(()) +} + /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If /// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly /// through a `*const/mut T` raw pointer if `arbitrary_self_types_pointers` is also enabled. @@ -1799,7 +1837,8 @@ fn receiver_is_valid<'tcx>( receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, arbitrary_self_types_enabled: Option<ArbitrarySelfTypesLevel>, -) -> bool { + method_generics: &ty::Generics, +) -> Result<(), ReceiverValidityError> { let infcx = wfcx.infcx; let tcx = wfcx.tcx(); let cause = @@ -1811,9 +1850,11 @@ fn receiver_is_valid<'tcx>( ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?; if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } }) { - return true; + return Ok(()); } + confirm_type_is_not_a_method_generic_param(receiver_ty, method_generics)?; + let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty); // The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`. @@ -1830,6 +1871,8 @@ fn receiver_is_valid<'tcx>( potential_self_ty, self_ty ); + confirm_type_is_not_a_method_generic_param(potential_self_ty, method_generics)?; + // Check if the self type unifies. If it does, then commit the result // since it may have region side-effects. if let Ok(()) = wfcx.infcx.commit_if_ok(|_| { @@ -1838,7 +1881,7 @@ fn receiver_is_valid<'tcx>( if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } }) { wfcx.register_obligations(autoderef.into_obligations()); - return true; + return Ok(()); } // Without `feature(arbitrary_self_types)`, we require that each step in the @@ -1865,7 +1908,7 @@ fn receiver_is_valid<'tcx>( } debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); - false + Err(ReceiverValidityError::DoesNotDeref) } fn receiver_is_implemented<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index b4f6b5a9dd2..5ff52376837 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -15,7 +15,9 @@ use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, suggest_constraining_type_params}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params, +}; use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::misc::{ @@ -213,7 +215,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() let param_env = tcx.param_env(impl_did); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = ObligationCause::misc(span, impl_did); // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw @@ -354,7 +356,7 @@ pub(crate) fn coerce_unsized_info<'tcx>( debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = ObligationCause::misc(span, impl_did); let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>, diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 04770469132..8a1a887766c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -7,7 +7,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{DefId, LocalDefId}; @@ -302,7 +302,7 @@ fn orphan_check<'tcx>( } // (1) Instantiate all generic params with fresh inference vars. - let infcx = tcx.infer_ctxt().intercrate(true).build(); + let infcx = tcx.infer_ctxt().build(TypingMode::Coherence); let cause = traits::ObligationCause::dummy(); let args = infcx.fresh_args_for_item(cause.span, impl_def_id.to_def_id()); let trait_ref = trait_ref.instantiate(tcx, args); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 3add801cf56..3f6198dbd31 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -34,7 +34,7 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, Span}; @@ -86,7 +86,7 @@ pub fn provide(providers: &mut Providers) { impl_trait_header, coroutine_kind, coroutine_for_closure, - is_type_alias_impl_trait, + opaque_ty_origin, rendered_precise_capturing_args, ..*providers }; @@ -1302,7 +1302,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { } } -#[instrument(level = "debug", skip(tcx))] +#[instrument(level = "debug", skip(tcx), ret)] fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFnSig<'_>> { use rustc_hir::Node::*; use rustc_hir::*; @@ -1438,9 +1438,11 @@ fn infer_return_ty_for_fn_sig<'tcx>( Applicability::MachineApplicable, ); recovered_ret_ty = Some(suggestable_ret_ty); - } else if let Some(sugg) = - suggest_impl_trait(&tcx.infer_ctxt().build(), tcx.param_env(def_id), ret_ty) - { + } else if let Some(sugg) = suggest_impl_trait( + &tcx.infer_ctxt().build(TypingMode::non_body_analysis()), + tcx.param_env(def_id), + ret_ty, + ) { diag.span_suggestion( ty.span, "replace with an appropriate return type", @@ -1757,9 +1759,18 @@ fn coroutine_for_closure(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DefId { def_id.to_def_id() } -fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { - let opaque = tcx.hir().expect_opaque_ty(def_id); - matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }) +fn opaque_ty_origin<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> hir::OpaqueTyOrigin<DefId> { + match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin { + hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl } => { + hir::OpaqueTyOrigin::FnReturn { parent: parent.to_def_id(), in_trait_or_impl } + } + hir::OpaqueTyOrigin::AsyncFn { parent, in_trait_or_impl } => { + hir::OpaqueTyOrigin::AsyncFn { parent: parent.to_def_id(), in_trait_or_impl } + } + hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty } => { + hir::OpaqueTyOrigin::TyAlias { parent: parent.to_def_id(), in_assoc_ty } + } + } } fn rendered_precise_capturing_args<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 3eec0e12665..c31bff28fd3 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -426,6 +426,21 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { }); } + if let Node::OpaqueTy(&hir::OpaqueTy { .. }) = node { + assert!(own_params.is_empty()); + + let lifetimes = tcx.opaque_captured_lifetimes(def_id); + debug!(?lifetimes); + + own_params.extend(lifetimes.iter().map(|&(_, param)| ty::GenericParamDef { + name: tcx.item_name(param.to_def_id()), + index: next_index(), + def_id: param.to_def_id(), + pure_wrt_drop: false, + kind: ty::GenericParamDefKind::Lifetime, + })) + } + let param_def_id_to_index = own_params.iter().map(|param| (param.def_id, param.index)).collect(); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index b2ad42be6c7..da779a16569 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -367,20 +367,8 @@ pub(super) fn explicit_item_bounds_with_filter( // a projection self type. Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { let opaque_ty = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_opaque_ty(); - let item_ty = Ty::new_projection_from_args( - tcx, - def_id.to_def_id(), - ty::GenericArgs::identity_for_item(tcx, def_id), - ); - let bounds = opaque_type_bounds( - tcx, - opaque_def_id.expect_local(), - opaque_ty.bounds, - item_ty, - opaque_ty.span, - filter, - ); - assert_only_contains_predicates_from(filter, bounds, item_ty); + let bounds = + associated_type_bounds(tcx, def_id, opaque_ty.bounds, opaque_ty.span, filter); return ty::EarlyBinder::bind(bounds); } Some(ty::ImplTraitInTraitData::Impl { .. }) => span_bug!( @@ -391,9 +379,6 @@ pub(super) fn explicit_item_bounds_with_filter( } let bounds = match tcx.hir_node_by_def_id(def_id) { - _ if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) => { - associated_type_bounds(tcx, def_id, &[], tcx.def_span(def_id), filter) - } hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), span, diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 644ff0c667c..efe84e0006f 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -329,13 +329,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We create bi-directional Outlives predicates between the original // and the duplicated parameter, to ensure that they do not get out of sync. if let Node::OpaqueTy(..) = node { - let opaque_ty_node = tcx.parent_hir_node(hir_id); - let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes), .. }) = opaque_ty_node - else { - bug!("unexpected {opaque_ty_node:?}") - }; - debug!(?lifetimes); - compute_bidirectional_outlives_predicates(tcx, &generics.own_params, &mut predicates); debug!(?predicates); } @@ -716,7 +709,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( match clause.kind().skip_binder() { ty::ClauseKind::HostEffect(ty::HostEffectPredicate { trait_ref: _, - host: ty::HostPolarity::Maybe, + constness: ty::BoundConstness::Maybe, }) => {} _ => { bug!( @@ -732,8 +725,8 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( match clause.kind().skip_binder() { ty::ClauseKind::HostEffect(pred) => { assert_eq!( - pred.host, - ty::HostPolarity::Maybe, + pred.constness, + ty::BoundConstness::Maybe, "expected `~const` predicate when computing `{filter:?}` \ implied bounds: {clause:?}", ); @@ -764,6 +757,16 @@ pub(super) fn type_param_predicates<'tcx>( tcx: TyCtxt<'tcx>, (item_def_id, def_id, assoc_name): (LocalDefId, LocalDefId, Ident), ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> { + match tcx.opt_rpitit_info(item_def_id.to_def_id()) { + Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { + return tcx.type_param_predicates((opaque_def_id.expect_local(), def_id, assoc_name)); + } + Some(ty::ImplTraitInTraitData::Impl { .. }) => { + unreachable!("should not be lowering bounds on RPITIT in impl") + } + None => {} + } + use rustc_hir::*; use rustc_middle::ty::Ty; @@ -943,7 +946,7 @@ pub(super) fn const_conditions<'tcx>( bounds.push_const_bound( tcx, ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())), - ty::HostPolarity::Maybe, + ty::BoundConstness::Maybe, DUMMY_SP, ); @@ -963,7 +966,7 @@ pub(super) fn const_conditions<'tcx>( clause.kind().map_bound(|clause| match clause { ty::ClauseKind::HostEffect(ty::HostEffectPredicate { trait_ref, - host: ty::HostPolarity::Maybe, + constness: ty::BoundConstness::Maybe, }) => trait_ref, _ => bug!("converted {clause:?}"), }), @@ -1001,7 +1004,7 @@ pub(super) fn implied_const_bounds<'tcx>( clause.kind().map_bound(|clause| match clause { ty::ClauseKind::HostEffect(ty::HostEffectPredicate { trait_ref, - host: ty::HostPolarity::Maybe, + constness: ty::BoundConstness::Maybe, }) => trait_ref, _ => bug!("converted {clause:?}"), }), diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index f7daef3e80c..9483439ae4e 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -6,12 +6,14 @@ //! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file //! is also responsible for assigning their semantics to implicit lifetimes in trait objects. -use core::ops::ControlFlow; +use std::cell::RefCell; use std::fmt; +use std::ops::ControlFlow; use rustc_ast::visit::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; +use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{self, Visitor}; @@ -25,7 +27,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_span::symbol::{Ident, sym}; use tracing::{debug, debug_span, instrument}; @@ -80,6 +82,9 @@ struct NamedVarMap { // - trait refs // - bound types (like `T` in `for<'a> T<'a>: Foo`) late_bound_vars: ItemLocalMap<Vec<ty::BoundVariableKind>>, + + // List captured variables for each opaque type. + opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>, } struct BoundVarContext<'a, 'tcx> { @@ -147,6 +152,23 @@ enum Scope<'a> { s: ScopeRef<'a>, }, + /// Remap lifetimes that appear in opaque types to fresh lifetime parameters. Given: + /// `fn foo<'a>() -> impl MyTrait<'a> { ... }` + /// + /// HIR tells us that `'a` refer to the lifetime bound on `foo`. + /// However, typeck and borrowck for opaques work based on using a new generic type. + /// `type MyAnonTy<'b> = impl MyTrait<'b>;` + /// + /// This scope collects the mapping `'a -> 'b`. + Opaque { + /// The opaque type we are traversing. + def_id: LocalDefId, + /// Mapping from each captured lifetime `'a` to the duplicate generic parameter `'b`. + captures: &'a RefCell<FxIndexMap<ResolvedArg, LocalDefId>>, + + s: ScopeRef<'a>, + }, + /// Disallows capturing late-bound vars from parent scopes. /// /// This is necessary for something like `for<T> [(); { /* references T */ }]:`, @@ -192,6 +214,12 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("where_bound_origin", where_bound_origin) .field("s", &"..") .finish(), + Scope::Opaque { captures, def_id, s: _ } => f + .debug_struct("Opaque") + .field("def_id", def_id) + .field("captures", &captures.borrow()) + .field("s", &"..") + .finish(), Scope::Body { id, s: _ } => { f.debug_struct("Body").field("id", id).field("s", &"..").finish() } @@ -226,6 +254,12 @@ pub(crate) fn provide(providers: &mut Providers) { is_late_bound_map, object_lifetime_default, late_bound_vars_map: |tcx, id| &tcx.resolve_bound_vars(id).late_bound_vars, + opaque_captured_lifetimes: |tcx, id| { + &tcx.resolve_bound_vars(tcx.local_def_id_to_hir_id(id).owner) + .opaque_captured_lifetimes + .get(&id) + .map_or(&[][..], |x| &x[..]) + }, ..*providers }; @@ -236,8 +270,11 @@ pub(crate) fn provide(providers: &mut Providers) { /// `named_variable_map`, `is_late_bound_map`, etc. #[instrument(level = "debug", skip(tcx))] fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars { - let mut named_variable_map = - NamedVarMap { defs: Default::default(), late_bound_vars: Default::default() }; + let mut named_variable_map = NamedVarMap { + defs: Default::default(), + late_bound_vars: Default::default(), + opaque_captured_lifetimes: Default::default(), + }; let mut visitor = BoundVarContext { tcx, map: &mut named_variable_map, @@ -264,13 +301,16 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou let defs = named_variable_map.defs.into_sorted_stable_ord(); let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord(); + let opaque_captured_lifetimes = named_variable_map.opaque_captured_lifetimes; let rl = ResolveBoundVars { defs: SortedMap::from_presorted_elements(defs), late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars), + opaque_captured_lifetimes, }; debug!(?rl.defs); debug!(?rl.late_bound_vars); + debug!(?rl.opaque_captured_lifetimes); rl } @@ -306,6 +346,26 @@ fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVaria } } +/// Whether this opaque always captures lifetimes in scope. +/// Right now, this is all RPITIT and TAITs, and when `lifetime_capture_rules_2024` +/// is enabled. We don't check the span of the edition, since this is done +/// on a per-opaque basis to account for nested opaques. +fn opaque_captures_all_in_scope_lifetimes<'tcx>( + tcx: TyCtxt<'tcx>, + opaque: &'tcx hir::OpaqueTy<'tcx>, +) -> bool { + match opaque.origin { + // if the opaque has the `use<...>` syntax, the user is telling us that they only want + // to account for those lifetimes, so do not try to be clever. + _ if opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..))) => false, + hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::TyAlias { .. } => true, + _ if tcx.features().lifetime_capture_rules_2024() || opaque.span.at_least_rust_2024() => { + true + } + hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(), + } +} + impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { /// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref. fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderScopeType) { @@ -317,7 +377,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { break (vec![], BinderScopeType::Normal); } - Scope::ObjectLifetimeDefault { s, .. } | Scope::LateBoundary { s, .. } => { + Scope::Opaque { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::LateBoundary { s, .. } => { scope = s; } @@ -488,29 +550,85 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } + /// Resolve the lifetimes inside the opaque type, and save them into + /// `opaque_captured_lifetimes`. + /// + /// This method has special handling for opaques that capture all lifetimes, + /// like async desugaring. #[instrument(level = "debug", skip(self))] fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { - // We want to start our early-bound indices at the end of the parent scope, - // not including any parent `impl Trait`s. - let mut bound_vars = FxIndexMap::default(); - debug!(?opaque.generics.params); - for param in opaque.generics.params { - let arg = ResolvedArg::early(param); - bound_vars.insert(param.def_id, arg); + let captures = RefCell::new(FxIndexMap::default()); + + let capture_all_in_scope_lifetimes = + opaque_captures_all_in_scope_lifetimes(self.tcx, opaque); + if capture_all_in_scope_lifetimes { + let lifetime_ident = |def_id: LocalDefId| { + let name = self.tcx.item_name(def_id.to_def_id()); + let span = self.tcx.def_span(def_id); + Ident::new(name, span) + }; + + // We list scopes outwards, this causes us to see lifetime parameters in reverse + // declaration order. In order to make it consistent with what `generics_of` might + // give, we will reverse the IndexMap after early captures. + let mut scope = self.scope; + let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)]; + loop { + match *scope { + Scope::Binder { ref bound_vars, s, .. } => { + for (&original_lifetime, &def) in bound_vars.iter().rev() { + if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) { + let ident = lifetime_ident(original_lifetime); + self.remap_opaque_captures(&opaque_capture_scopes, def, ident); + } + } + scope = s; + } + + Scope::Root { mut opt_parent_item } => { + while let Some(parent_item) = opt_parent_item { + let parent_generics = self.tcx.generics_of(parent_item); + for param in parent_generics.own_params.iter().rev() { + if let ty::GenericParamDefKind::Lifetime = param.kind { + let def = ResolvedArg::EarlyBound(param.def_id.expect_local()); + let ident = lifetime_ident(param.def_id.expect_local()); + self.remap_opaque_captures(&opaque_capture_scopes, def, ident); + } + } + opt_parent_item = parent_generics.parent.and_then(DefId::as_local); + } + break; + } + + Scope::Opaque { captures, def_id, s } => { + opaque_capture_scopes.push((def_id, captures)); + scope = s; + } + + Scope::Body { .. } => { + bug!("{:?}", scope) + } + + Scope::ObjectLifetimeDefault { s, .. } + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } + | Scope::LateBoundary { s, .. } => { + scope = s; + } + } + } + captures.borrow_mut().reverse(); } - let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id); - let scope = Scope::Binder { - hir_id, - bound_vars, - s: self.scope, - scope_type: BinderScopeType::Normal, - where_bound_origin: None, - }; + let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque)) - }) + }); + + let captures = captures.into_inner().into_iter().collect(); + debug!(?captures); + self.map.opaque_captured_lifetimes.insert(opaque.def_id, captures); } #[instrument(level = "debug", skip(self))] @@ -685,67 +803,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }; self.with(scope, |this| this.visit_ty(mt.ty)); } - hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => { - self.visit_opaque_ty(opaque_ty); - - // Resolve the lifetimes in the bounds to the lifetime defs in the generics. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `type MyAnonTy<'b> = impl MyTrait<'b>;` - // ^ ^ this gets resolved in the scope of - // the opaque_ty generics - - // Resolve the lifetimes that are applied to the opaque type. - // These are resolved in the current scope. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `fn foo<'a>() -> MyAnonTy<'a> { ... }` - // ^ ^this gets resolved in the current scope - for lifetime in lifetimes { - let hir::GenericArg::Lifetime(lifetime) = lifetime else { continue }; - self.visit_lifetime(lifetime); - - // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>` - // and ban them. Type variables instantiated inside binders aren't - // well-supported at the moment, so this doesn't work. - // In the future, this should be fixed and this error should be removed. - let def = self.map.defs.get(&lifetime.hir_id.local_id).copied(); - let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue }; - let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); - - let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id)) - { - // Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque - // it must be a reified late-bound lifetime from a trait goal. - hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`", - // Other items are fine. - hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => { - continue; - } - hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(_), .. }) => { - "higher-ranked lifetime from function pointer" - } - hir::Node::Ty(hir::Ty { kind: hir::TyKind::TraitObject(..), .. }) => { - "higher-ranked lifetime from `dyn` type" - } - _ => "higher-ranked lifetime", - }; - - let (span, label) = if lifetime.ident.span == self.tcx.def_span(lifetime_def_id) - { - (opaque_ty.span, Some(opaque_ty.span)) - } else { - (lifetime.ident.span, None) - }; - - // Ensure that the parent of the def is an item, not HRTB - self.tcx.dcx().emit_err(errors::OpaqueCapturesHigherRankedLifetime { - span, - label, - decl_span: self.tcx.def_span(lifetime_def_id), - bad_place, - }); - self.uninsert_lifetime_on_error(lifetime, def.unwrap()); - } - } _ => intravisit::walk_ty(self, ty), } } @@ -1129,6 +1186,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let mut scope = self.scope; let mut outermost_body = None; let mut crossed_late_boundary = None; + let mut opaque_capture_scopes = vec![]; let result = loop { match *scope { Scope::Body { id, s } => { @@ -1204,6 +1262,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { scope = s; } + Scope::Opaque { captures, def_id, s } => { + opaque_capture_scopes.push((def_id, captures)); + late_depth = 0; + scope = s; + } + Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { @@ -1218,6 +1282,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { }; if let Some(mut def) = result { + def = self.remap_opaque_captures(&opaque_capture_scopes, def, lifetime_ref.ident); + if let ResolvedArg::EarlyBound(..) = def { // Do not free early-bound regions, only late-bound ones. } else if let ResolvedArg::LateBound(_, _, param_def_id) = def @@ -1291,6 +1357,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Root { .. } => break, Scope::Binder { s, .. } | Scope::Body { s, .. } + | Scope::Opaque { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } @@ -1306,6 +1373,79 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { ); } + /// Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>` + /// and ban them. Type variables instantiated inside binders aren't + /// well-supported at the moment, so this doesn't work. + /// In the future, this should be fixed and this error should be removed. + fn check_lifetime_is_capturable( + &self, + opaque_def_id: LocalDefId, + lifetime: ResolvedArg, + capture_span: Span, + ) -> Result<(), ErrorGuaranteed> { + let ResolvedArg::LateBound(_, _, lifetime_def_id) = lifetime else { return Ok(()) }; + let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); + let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id)) { + // Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque + // it must be a reified late-bound lifetime from a trait goal. + hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`", + // Other items are fine. + hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => return Ok(()), + hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(_), .. }) => { + "higher-ranked lifetime from function pointer" + } + hir::Node::Ty(hir::Ty { kind: hir::TyKind::TraitObject(..), .. }) => { + "higher-ranked lifetime from `dyn` type" + } + _ => "higher-ranked lifetime", + }; + + let decl_span = self.tcx.def_span(lifetime_def_id); + let (span, label) = if capture_span != decl_span { + (capture_span, None) + } else { + let opaque_span = self.tcx.def_span(opaque_def_id); + (opaque_span, Some(opaque_span)) + }; + + // Ensure that the parent of the def is an item, not HRTB + let guar = self.tcx.dcx().emit_err(errors::OpaqueCapturesHigherRankedLifetime { + span, + label, + decl_span, + bad_place, + }); + Err(guar) + } + + #[instrument(level = "trace", skip(self, opaque_capture_scopes), ret)] + fn remap_opaque_captures( + &self, + opaque_capture_scopes: &Vec<(LocalDefId, &RefCell<FxIndexMap<ResolvedArg, LocalDefId>>)>, + mut lifetime: ResolvedArg, + ident: Ident, + ) -> ResolvedArg { + if let Some(&(opaque_def_id, _)) = opaque_capture_scopes.last() { + if let Err(guar) = + self.check_lifetime_is_capturable(opaque_def_id, lifetime, ident.span) + { + lifetime = ResolvedArg::Error(guar); + } + } + + for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() { + let mut captures = captures.borrow_mut(); + let remapped = *captures.entry(lifetime).or_insert_with(|| { + let feed = self.tcx.create_def(opaque_def_id, ident.name, DefKind::LifetimeParam); + feed.def_span(ident.span); + feed.def_ident_span(Some(ident.span)); + feed.def_id() + }); + lifetime = ResolvedArg::EarlyBound(remapped); + } + lifetime + } + fn resolve_type_ref(&mut self, param_def_id: LocalDefId, hir_id: HirId) { // Walk up the scope chain, tracking the number of fn scopes // that we pass through, until we find a lifetime with the @@ -1345,6 +1485,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } Scope::ObjectLifetimeDefault { s, .. } + | Scope::Opaque { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { scope = s; @@ -1425,6 +1566,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Root { .. } => break, Scope::Binder { s, .. } | Scope::Body { s, .. } + | Scope::Opaque { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } @@ -1501,6 +1643,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Binder { s, .. } | Scope::ObjectLifetimeDefault { s, .. } + | Scope::Opaque { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } | Scope::LateBoundary { s, .. } => { @@ -1786,7 +1929,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { let mut late_depth = 0; let mut scope = self.scope; - let lifetime = loop { + let mut opaque_capture_scopes = vec![]; + let mut lifetime = loop { match *scope { Scope::Binder { s, scope_type, .. } => { match scope_type { @@ -1800,7 +1944,15 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, - Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, + Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => { + break l.shifted(late_depth); + } + + Scope::Opaque { captures, def_id, s } => { + opaque_capture_scopes.push((def_id, captures)); + late_depth = 0; + scope = s; + } Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } @@ -1809,7 +1961,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } } }; - self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); + + lifetime = self.remap_opaque_captures(&opaque_capture_scopes, lifetime, lifetime_ref.ident); + + self.insert_lifetime(lifetime_ref, lifetime); } #[instrument(level = "debug", skip(self))] @@ -1818,18 +1973,6 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { self.map.defs.insert(lifetime_ref.hir_id.local_id, def); } - /// Sometimes we resolve a lifetime, but later find that it is an - /// error (esp. around impl trait). In that case, we remove the - /// entry into `map.defs` so as not to confuse later code. - fn uninsert_lifetime_on_error( - &mut self, - lifetime_ref: &'tcx hir::Lifetime, - bad_def: ResolvedArg, - ) { - let old_value = self.map.defs.remove(&lifetime_ref.hir_id.local_id); - assert_eq!(old_value, Some(bad_def)); - } - // When we have a return type notation type in a where clause, like // `where <T as Trait>::method(..): Send`, we need to introduce new bound // vars to the existing where clause's binder, to represent the lifetimes @@ -2013,18 +2156,22 @@ fn is_late_bound_map( tcx: TyCtxt<'_>, owner_id: hir::OwnerId, ) -> Option<&FxIndexSet<hir::ItemLocalId>> { - let decl = tcx.hir().fn_decl_by_hir_id(owner_id.into())?; + let sig = tcx.hir().fn_sig_by_hir_id(owner_id.into())?; let generics = tcx.hir().get_generics(owner_id.def_id)?; let mut late_bound = FxIndexSet::default(); let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx }; - for arg_ty in decl.inputs { + for arg_ty in sig.decl.inputs { constrained_by_input.visit_ty(arg_ty); } - let mut appears_in_output = AllCollector::default(); - intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); + let mut appears_in_output = + AllCollector { tcx, has_fully_capturing_opaque: false, regions: Default::default() }; + intravisit::walk_fn_ret_ty(&mut appears_in_output, &sig.decl.output); + if appears_in_output.has_fully_capturing_opaque { + appears_in_output.regions.extend(generics.params.iter().map(|param| param.def_id)); + } debug!(?constrained_by_input.regions); @@ -2032,7 +2179,8 @@ fn is_late_bound_map( // // Subtle point: because we disallow nested bindings, we can just // ignore binders here and scrape up all names we see. - let mut appears_in_where_clause = AllCollector::default(); + let mut appears_in_where_clause = + AllCollector { tcx, has_fully_capturing_opaque: true, regions: Default::default() }; appears_in_where_clause.visit_generics(generics); debug!(?appears_in_where_clause.regions); @@ -2198,17 +2346,26 @@ fn is_late_bound_map( } } - #[derive(Default)] - struct AllCollector { + struct AllCollector<'tcx> { + tcx: TyCtxt<'tcx>, + has_fully_capturing_opaque: bool, regions: FxHashSet<LocalDefId>, } - impl<'v> Visitor<'v> for AllCollector { + impl<'v> Visitor<'v> for AllCollector<'v> { fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { if let hir::LifetimeName::Param(def_id) = lifetime_ref.res { self.regions.insert(def_id); } } + + fn visit_opaque_ty(&mut self, opaque: &'v hir::OpaqueTy<'v>) { + if !self.has_fully_capturing_opaque { + self.has_fully_capturing_opaque = + opaque_captures_all_in_scope_lifetimes(self.tcx, opaque); + } + intravisit::walk_opaque_ty(self, opaque); + } } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 77e81af3ca9..a92a5e4278c 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1624,10 +1624,14 @@ pub(crate) struct InvalidReceiverTy<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_analysis_effects_without_next_solver)] +#[diag(hir_analysis_invalid_generic_receiver_ty, code = E0801)] #[note] -#[help] -pub(crate) struct EffectsWithoutNextSolver; +#[help(hir_analysis_invalid_generic_receiver_ty_help)] +pub(crate) struct InvalidGenericReceiverTy<'tcx> { + #[primary_span] + pub span: Span, + pub receiver_ty: Ty<'tcx>, +} #[derive(Diagnostic)] #[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)] 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 a5709089db6..8cc475b536d 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -168,12 +168,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match hir_bound { hir::GenericBound::Trait(poly_trait_ref) => { let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers; - let polarity = match polarity { - rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive, - rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative, - rustc_ast::BoundPolarity::Maybe(_) => continue, - }; - let _ = self.lower_poly_trait_ref( &poly_trait_ref.trait_ref, poly_trait_ref.span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index f2ee4b0ccd4..5e27ace4cbe 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -51,7 +51,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &trait_bound.trait_ref, trait_bound.span, hir::BoundConstness::Never, - ty::PredicatePolarity::Positive, + hir::BoundPolarity::Positive, dummy_self, &mut bounds, PredicateFilter::SelfOnly, @@ -140,9 +140,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.associated_items(pred.def_id()) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) - .filter(|item| { - !item.is_impl_trait_in_trait() && !item.is_effects_desugaring - }) + .filter(|item| !item.is_impl_trait_in_trait()) .map(|item| item.def_id), ); } 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 0891642f2c8..848813ffcb8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -20,6 +20,7 @@ pub mod errors; pub mod generics; mod lint; +use std::assert_matches::assert_matches; use std::slice; use rustc_ast::TraitObjectSyntax; @@ -39,7 +40,7 @@ use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, - TypeVisitableExt, + TypeVisitableExt, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; @@ -294,13 +295,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { lifetime: &hir::Lifetime, reason: RegionInferReason<'_>, ) -> ty::Region<'tcx> { + if let Some(resolved) = self.tcx().named_bound_var(lifetime.hir_id) { + self.lower_resolved_lifetime(resolved) + } else { + self.re_infer(lifetime.ident.span, reason) + } + } + + /// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*. + #[instrument(level = "debug", skip(self), ret)] + pub fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> { let tcx = self.tcx(); let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id)); - match tcx.named_bound_var(lifetime.hir_id) { - Some(rbv::ResolvedArg::StaticLifetime) => tcx.lifetimes.re_static, + match resolved { + rbv::ResolvedArg::StaticLifetime => tcx.lifetimes.re_static, - Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { + rbv::ResolvedArg::LateBound(debruijn, index, def_id) => { let name = lifetime_name(def_id); let br = ty::BoundRegion { var: ty::BoundVar::from_u32(index), @@ -309,7 +320,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Region::new_bound(tcx, debruijn, br) } - Some(rbv::ResolvedArg::EarlyBound(def_id)) => { + rbv::ResolvedArg::EarlyBound(def_id) => { let name = tcx.hir().ty_param_name(def_id); let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); @@ -317,7 +328,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name }) } - Some(rbv::ResolvedArg::Free(scope, id)) => { + rbv::ResolvedArg::Free(scope, id) => { let name = lifetime_name(id); ty::Region::new_late_param( tcx, @@ -328,9 +339,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // (*) -- not late-bound, won't change } - Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar), - - None => self.re_infer(lifetime.ident.span, reason), + rbv::ResolvedArg::Error(guar) => ty::Region::new_error(tcx, guar), } } @@ -659,7 +668,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_ref: &hir::TraitRef<'tcx>, span: Span, constness: hir::BoundConstness, - polarity: ty::PredicatePolarity, + polarity: hir::BoundPolarity, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, predicate_filter: PredicateFilter, @@ -681,15 +690,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(self_ty), ); - if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness - && !self.tcx().is_const_trait(trait_def_id) - { - self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { - span, - modifier: constness.as_str(), - }); - } - let tcx = self.tcx(); let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id); debug!(?bound_vars); @@ -699,6 +699,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bound_vars, ); + let polarity = match polarity { + rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive, + rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative, + rustc_ast::BoundPolarity::Maybe(_) => { + // Validate associated type at least. We may want to reject these + // outright in the future... + for constraint in trait_segment.args().constraints { + let _ = self.lower_assoc_item_constraint( + trait_ref.hir_ref_id, + poly_trait_ref, + constraint, + &mut Default::default(), + &mut Default::default(), + constraint.span, + predicate_filter, + ); + } + return arg_count; + } + }; + + if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness + && !self.tcx().is_const_trait(trait_def_id) + { + self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { + span, + modifier: constness.as_str(), + }); + } + match predicate_filter { PredicateFilter::All | PredicateFilter::SelfOnly @@ -713,7 +743,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds.push_const_bound( tcx, poly_trait_ref, - ty::HostPolarity::Const, + ty::BoundConstness::Const, span, ); } @@ -736,7 +766,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => match constness { hir::BoundConstness::Maybe(span) => { if polarity == ty::PredicatePolarity::Positive { - bounds.push_const_bound(tcx, poly_trait_ref, ty::HostPolarity::Maybe, span); + bounds.push_const_bound( + tcx, + poly_trait_ref, + ty::BoundConstness::Maybe, + span, + ); } } hir::BoundConstness::Always(_) | hir::BoundConstness::Never => {} @@ -749,11 +784,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // since we should have emitted an error for them earlier, and they // would not be well-formed! if polarity != ty::PredicatePolarity::Positive { - assert!( - self.dcx().has_errors().is_some(), + self.dcx().span_delayed_bug( + constraint.span, "negative trait bounds should not have assoc item constraints", ); - continue; + break; } // Specify type to assert that error was already reported in `Err` case. @@ -1300,7 +1335,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(infcx) => infcx, None => { assert!(!self_ty.has_infer()); - infcx_ = tcx.infer_ctxt().ignoring_regions().build(); + infcx_ = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); &infcx_ } }; @@ -1492,7 +1527,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { infcx } else { assert!(!qself_ty.has_infer()); - infcx_ = tcx.infer_ctxt().build(); + infcx_ = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); &infcx_ }; @@ -1798,7 +1833,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match path.res { Res::Def(DefKind::OpaqueTy, did) => { // Check for desugared `impl Trait`. - assert!(tcx.is_type_alias_impl_trait(did)); + assert_matches!(tcx.opaque_ty_origin(did), hir::OpaqueTyOrigin::TyAlias { .. }); let item_segment = path.segments.split_last().unwrap(); let _ = self .prohibit_generic_args(item_segment.1.iter(), GenericsArgsErrExtend::OpaqueTy); @@ -2094,13 +2129,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); self.lower_path(opt_self_ty, path, hir_ty.hir_id, false) } - &hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => { - let local_def_id = opaque_ty.def_id; - + &hir::TyKind::OpaqueDef(opaque_ty) => { // If this is an RPITIT and we are using the new RPITIT lowering scheme, we // generate the def_id of an associated type for the trait and return as // type a projection. - match opaque_ty.origin { + let in_trait = match opaque_ty.origin { hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(hir::RpitContext::Trait), .. @@ -2108,11 +2141,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { | hir::OpaqueTyOrigin::AsyncFn { in_trait_or_impl: Some(hir::RpitContext::Trait), .. - } => self.lower_opaque_ty( - tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id(), - lifetimes, - true, - ), + } => true, hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. @@ -2121,10 +2150,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. } - | hir::OpaqueTyOrigin::TyAlias { .. } => { - self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false) - } - } + | hir::OpaqueTyOrigin::TyAlias { .. } => false, + }; + + self.lower_opaque_ty(opaque_ty.def_id, in_trait) } // If we encounter a type relative path with RTN generics, then it must have // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore @@ -2264,40 +2293,34 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR. - #[instrument(level = "debug", skip_all, ret)] - fn lower_opaque_ty( - &self, - def_id: DefId, - lifetimes: &[hir::GenericArg<'_>], - in_trait: bool, - ) -> Ty<'tcx> { - debug!(?def_id, ?lifetimes); + #[instrument(level = "debug", skip(self), ret)] + fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> { let tcx = self.tcx(); + let lifetimes = tcx.opaque_captured_lifetimes(def_id); + debug!(?lifetimes); + + // If this is an RPITIT and we are using the new RPITIT lowering scheme, we + // generate the def_id of an associated type for the trait and return as + // type a projection. + let def_id = if in_trait { + tcx.associated_type_for_impl_trait_in_trait(def_id).to_def_id() + } else { + def_id.to_def_id() + }; + let generics = tcx.generics_of(def_id); debug!(?generics); + // We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count` + // since return-position impl trait in trait squashes all of the generics from its source fn + // into its own generics, so the opaque's "own" params isn't always just lifetimes. + let offset = generics.count() - lifetimes.len(); + let args = ty::GenericArgs::for_item(tcx, def_id, |param, _| { - // We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count` - // since return-position impl trait in trait squashes all of the generics from its source fn - // into its own generics, so the opaque's "own" params isn't always just lifetimes. - if let Some(i) = (param.index as usize).checked_sub(generics.count() - lifetimes.len()) - { - // Resolve our own lifetime parameters. - let GenericParamDefKind::Lifetime { .. } = param.kind else { - span_bug!( - tcx.def_span(param.def_id), - "only expected lifetime for opaque's own generics, got {:?}", - param - ); - }; - let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { - bug!( - "expected lifetime argument for param {param:?}, found {:?}", - &lifetimes[i] - ) - }; - self.lower_lifetime(lifetime, RegionInferReason::Param(¶m)).into() + if let Some(i) = (param.index as usize).checked_sub(offset) { + let (lifetime, _) = lifetimes[i]; + self.lower_resolved_lifetime(lifetime).into() } else { tcx.mk_param_from_def(param) } diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 2fa4ca68073..5b0165bf993 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -5,7 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::bug; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_span::def_id::LocalDefId; use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::debug; @@ -68,7 +68,7 @@ fn diagnostic_hir_wf_check<'tcx>( impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - let infcx = self.tcx.infer_ctxt().build(); + let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let tcx_ty = self.icx.lower_ty(ty); 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 a394fc2fbb1..b0c9aed5d85 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 @@ -72,7 +72,9 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::traits::specialization_graph::Node; use rustc_middle::ty::trait_def::TraitSpecializationKind; -use rustc_middle::ty::{self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{ + self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt, TypingMode, +}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; @@ -195,7 +197,7 @@ fn get_impl_args( impl1_def_id: LocalDefId, impl2_node: Node, ) -> Result<(GenericArgsRef<'_>, GenericArgsRef<'_>), ErrorGuaranteed> { - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); let param_env = tcx.param_env(impl1_def_id); let impl1_span = tcx.def_span(impl1_def_id); @@ -409,7 +411,7 @@ fn check_predicates<'tcx>( // Include the well-formed predicates of the type parameters of the impl. for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().instantiate_identity().args { - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let obligations = wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, arg, span) .unwrap(); diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 3ad35163191..339eddeeade 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -153,12 +153,6 @@ pub fn provide(providers: &mut Providers) { pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); - // FIXME(effects): remove once effects is implemented in old trait solver - // or if the next solver is stabilized. - if tcx.features().effects() && !tcx.next_trait_solver_globally() { - tcx.dcx().emit_err(errors::EffectsWithoutNextSolver); - } - tcx.sess.time("coherence_checking", || { tcx.hir().par_for_each_module(|module| { let _ = tcx.ensure().check_mod_type_wf(module); diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml index aacf41b6eb7..9af1fb8279e 100644 --- a/compiler/rustc_hir_pretty/Cargo.toml +++ b/compiler/rustc_hir_pretty/Cargo.toml @@ -5,9 +5,9 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_hir = { path = "../rustc_hir" } rustc_span = { path = "../rustc_span" } -rustc_target = { path = "../rustc_target" } # tidy-alphabetical-end diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 61214b99215..0a3aa8fec90 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -9,6 +9,7 @@ use std::cell::Cell; use std::vec; +use rustc_abi::ExternAbi; use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, Breaks}; @@ -20,7 +21,6 @@ use rustc_hir::{ use rustc_span::FileName; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; -use rustc_target::spec::abi::Abi; use {rustc_ast as ast, rustc_hir as hir}; pub fn id_to_string(map: &dyn rustc_hir::intravisit::Map<'_>, hir_id: HirId) -> String { @@ -659,8 +659,6 @@ impl<'a> State<'a> { fn print_opaque_ty(&mut self, o: &hir::OpaqueTy<'_>) { self.head("opaque"); - self.print_generic_params(o.generics.params); - self.print_where_clause(o.generics); self.word("{"); self.print_bounds("impl", o.bounds); self.word("}"); @@ -2242,7 +2240,7 @@ impl<'a> State<'a> { fn print_ty_fn( &mut self, - abi: Abi, + abi: ExternAbi, safety: hir::Safety, decl: &hir::FnDecl<'_>, name: Option<Symbol>, @@ -2278,7 +2276,7 @@ impl<'a> State<'a> { self.print_safety(header.safety); - if header.abi != Abi::Rust { + if header.abi != ExternAbi::Rust { self.word_nbsp("extern"); self.word_nbsp(header.abi.to_string()); } diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 3372cae7a51..1774772b50b 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -601,7 +601,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return None, }; let hir::OpaqueTyOrigin::FnReturn { parent: parent_def_id, .. } = - self.tcx.opaque_type_origin(def_id) + self.tcx.local_opaque_ty_origin(def_id) else { return None; }; diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index e4ca1cee757..7af26623ce7 100644 --- a/compiler/rustc_hir_typeck/src/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs @@ -23,7 +23,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, base_ty: Ty<'tcx>, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { - self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref) + self.try_overloaded_place_op(span, base_ty, None, PlaceOp::Deref) } /// Returns the adjustment steps. @@ -50,8 +50,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.try_overloaded_deref(autoderef.span(), source).and_then( |InferOk { value: method, obligations: o }| { obligations.extend(o); - if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { - Some(OverloadedDeref { region, mutbl, span: autoderef.span() }) + // FIXME: we should assert the sig is &T here... there's no reason for this to be fallible. + if let ty::Ref(_, _, mutbl) = *method.sig.output().kind() { + Some(OverloadedDeref { mutbl, span: autoderef.span() }) } else { None } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index ed56bb9c455..f9a21a9bef3 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -1,4 +1,4 @@ -use std::{iter, slice}; +use std::iter; use rustc_ast::util::parser::PREC_UNAMBIGUOUS; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; @@ -300,14 +300,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ident::with_dummy_span(method_name), trait_def_id, adjusted_ty, - opt_input_type.as_ref().map(slice::from_ref), + opt_input_type, ) { let method = self.register_infer_ok_obligations(ok); let mut autoref = None; if borrow { // Check for &self vs &mut self in the method signature. Since this is either // the Fn or FnMut trait, it should be one of those. - let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind() else { + let ty::Ref(_, _, mutbl) = method.sig.inputs()[0].kind() else { bug!("Expected `FnMut`/`Fn` to take receiver by-ref/by-mut") }; @@ -317,7 +317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::No); autoref = Some(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)), + kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)), target: method.sig.inputs()[0], }); } @@ -851,11 +851,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } + // If we have `rustc_do_not_const_check`, do not check `~const` bounds. + if self.tcx.has_attr(self.body_id, sym::rustc_do_not_const_check) { + return; + } + let host = match self.tcx.hir().body_const_context(self.body_id) { Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => { - ty::HostPolarity::Const + ty::BoundConstness::Const } - Some(hir::ConstContext::ConstFn) => ty::HostPolarity::Maybe, + Some(hir::ConstContext::ConstFn) => ty::BoundConstness::Maybe, None => return, }; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6fa958d9496..87798ca3fd9 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -113,7 +113,7 @@ fn identity(_: Ty<'_>) -> Vec<Adjustment<'_>> { vec![] } -fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> { +fn simple<'tcx>(kind: Adjust) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> { move |target| vec![Adjustment { kind, target }] } @@ -484,14 +484,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Now apply the autoref. We have to extract the region out of // the final ref type we got. - let ty::Ref(r_borrow, _, _) = ty.kind() else { + let ty::Ref(..) = ty.kind() else { span_bug!(span, "expected a ref type, got {:?}", ty); }; let mutbl = AutoBorrowMutability::new(mutbl_b, self.allow_two_phase); - adjustments.push(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(*r_borrow, mutbl)), - target: ty, - }); + adjustments.push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)), target: ty }); debug!("coerce_borrowed_pointer: succeeded ty={:?} adjustments={:?}", ty, adjustments); @@ -547,7 +544,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mutbl = AutoBorrowMutability::new(mutbl_b, AllowTwoPhase::No); Some((Adjustment { kind: Adjust::Deref(None), target: ty_a }, Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)), + kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)), target: Ty::new_ref(self.tcx, r_borrow, ty_a, mutbl_b), })) } @@ -827,7 +824,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { }; let (pin, a_region, a_ty, mut_a) = extract_pin_mut(a)?; - let (_, b_region, _b_ty, mut_b) = extract_pin_mut(b)?; + let (_, _, _b_ty, mut_b) = extract_pin_mut(b)?; coerce_mutbls(mut_a, mut_b)?; @@ -841,7 +838,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // To complete the reborrow, we need to make sure we can unify the inner types, and if so we // add the adjustments. self.unify_and(a, b, |_inner_ty| { - vec![Adjustment { kind: Adjust::ReborrowPin(b_region, mut_b), target: b }] + vec![Adjustment { kind: Adjust::ReborrowPin(mut_b), target: b }] }) } @@ -1321,7 +1318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let noop = match self.typeck_results.borrow().expr_adjustments(expr) { &[ Adjustment { kind: Adjust::Deref(_), .. }, - Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. }, + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(mutbl_adj)), .. }, ] => { match *self.node_ty(expr.hir_id).kind() { ty::Ref(_, _, mt_orig) => { diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index bb5f3511373..041ccfcddbb 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -781,7 +781,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.walk_autoref(expr, &place_with_id, autoref); } - adjustment::Adjust::ReborrowPin(_, mutbl) => { + adjustment::Adjust::ReborrowPin(mutbl) => { // Reborrowing a Pin is like a combinations of a deref and a borrow, so we do // both. let bk = match mutbl { @@ -804,7 +804,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx &self, expr: &hir::Expr<'_>, base_place: &PlaceWithHirId<'tcx>, - autoref: &adjustment::AutoBorrow<'tcx>, + autoref: &adjustment::AutoBorrow, ) { debug!( "walk_autoref(expr.hir_id={} base_place={:?} autoref={:?})", @@ -812,7 +812,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx ); match *autoref { - adjustment::AutoBorrow::Ref(_, m) => { + adjustment::AutoBorrow::Ref(m) => { self.delegate.borrow_mut().borrow( base_place, base_place.hir_id, @@ -1283,7 +1283,12 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx adjustment::Adjust::Deref(overloaded) => { // Equivalent to *expr or something similar. let base = if let Some(deref) = overloaded { - let ref_ty = Ty::new_ref(self.cx.tcx(), deref.region, target, deref.mutbl); + let ref_ty = Ty::new_ref( + self.cx.tcx(), + self.cx.tcx().lifetimes.re_erased, + target, + deref.mutbl, + ); self.cat_rvalue(expr.hir_id, ref_ty) } else { previous()? diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 0fc566c58f7..a1a78371fbd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -264,7 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let autoborrow_mut = adj.iter().any(|adj| { matches!(adj, &Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })), + kind: Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. })), .. }) }); diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index f2b55d3aa4e..3754fd02428 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -200,10 +200,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // for two-phase borrows. let mutbl = AutoBorrowMutability::new(mutbl, AllowTwoPhase::Yes); - adjustments.push(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), - target, - }); + adjustments + .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)), target }); if unsize { let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() { @@ -250,7 +248,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { _ => bug!("Cannot adjust receiver type for reborrowing pin of {target:?}"), }; - adjustments.push(Adjustment { kind: Adjust::ReborrowPin(region, mutbl), target }); + adjustments.push(Adjustment { kind: Adjust::ReborrowPin(mutbl), target }); } None => {} } @@ -533,9 +531,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.register_predicates(obligations); } Err(terr) => { - // FIXME(arbitrary_self_types): We probably should limit the - // situations where this can occur by adding additional restrictions - // to the feature, like the self type can't reference method args. if self.tcx.features().arbitrary_self_types() { self.err_ctxt() .report_mismatched_types( diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index e20a0cb67c3..e0b6ea0ac9d 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -324,35 +324,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(pick) } - pub(super) fn obligation_for_method( - &self, - cause: ObligationCause<'tcx>, - trait_def_id: DefId, - self_ty: Ty<'tcx>, - opt_input_types: Option<&[Ty<'tcx>]>, - ) -> (traits::PredicateObligation<'tcx>, ty::GenericArgsRef<'tcx>) { - // Construct a trait-reference `self_ty : Trait<input_tys>` - let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| { - match param.kind { - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {} - GenericParamDefKind::Type { .. } => { - if param.index == 0 { - return self_ty.into(); - } else if let Some(input_types) = opt_input_types { - return input_types[param.index as usize - 1].into(); - } - } - } - self.var_for_def(cause.span, param) - }); - - let trait_ref = ty::TraitRef::new_from_args(self.tcx, trait_def_id, args); - - // Construct an obligation - let poly_trait_ref = ty::Binder::dummy(trait_ref); - (traits::Obligation::new(self.tcx, cause, self.param_env, poly_trait_ref), args) - } - /// `lookup_method_in_trait` is used for overloaded operators. /// It does a very narrow slice of what the normal probe/confirm path does. /// In particular, it doesn't really do any probing: it simply constructs @@ -365,24 +336,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { m_name: Ident, trait_def_id: DefId, self_ty: Ty<'tcx>, - opt_input_types: Option<&[Ty<'tcx>]>, + opt_rhs_ty: Option<Ty<'tcx>>, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { - let (obligation, args) = - self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types); - self.construct_obligation_for_trait(m_name, trait_def_id, obligation, args) - } + // Construct a trait-reference `self_ty : Trait<input_tys>` + let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| match param.kind { + GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => { + unreachable!("did not expect operator trait to have lifetime/const") + } + GenericParamDefKind::Type { .. } => { + if param.index == 0 { + self_ty.into() + } else if let Some(rhs_ty) = opt_rhs_ty { + assert_eq!(param.index, 1, "did not expect >1 param on operator trait"); + rhs_ty.into() + } else { + // FIXME: We should stop passing `None` for the failure case + // when probing for call exprs. I.e. `opt_rhs_ty` should always + // be set when it needs to be. + self.var_for_def(cause.span, param) + } + } + }); - // FIXME(#18741): it seems likely that we can consolidate some of this - // code with the other method-lookup code. In particular, the second half - // of this method is basically the same as confirmation. - fn construct_obligation_for_trait( - &self, - m_name: Ident, - trait_def_id: DefId, - obligation: traits::PredicateObligation<'tcx>, - args: ty::GenericArgsRef<'tcx>, - ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { - debug!(?obligation); + let obligation = traits::Obligation::new( + self.tcx, + cause, + self.param_env, + ty::TraitRef::new_from_args(self.tcx, trait_def_id, args), + ); // Now we want to know if this can be matched if !self.predicate_may_hold(&obligation) { @@ -406,8 +387,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); let mut obligations = PredicateObligations::new(); - // FIXME(effects): revisit when binops get `#[const_trait]` - // Instantiate late-bound regions and instantiate the trait // parameters into the method type to get the actual method type. // @@ -418,12 +397,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let fn_sig = self.instantiate_binder_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig); - let InferOk { value, obligations: o } = + let InferOk { value: fn_sig, obligations: o } = self.at(&obligation.cause, self.param_env).normalize(fn_sig); - let fn_sig = { - obligations.extend(o); - value - }; + obligations.extend(o); // Register obligations for the parameters. This will include the // `Self` parameter, which in turn has a bound of the main trait, @@ -435,13 +411,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // any late-bound regions appearing in its bounds. let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args); - let InferOk { value, obligations: o } = + let InferOk { value: bounds, obligations: o } = self.at(&obligation.cause, self.param_env).normalize(bounds); - let bounds = { - obligations.extend(o); - value - }; - + obligations.extend(o); assert!(!bounds.has_escaping_bound_vars()); let predicates_cause = obligation.cause.clone(); @@ -454,7 +426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Also add an obligation for the method type being well-formed. let method_ty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig)); debug!( - "lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", + "lookup_method_in_trait: matched method method_ty={:?} obligation={:?}", method_ty, obligation ); obligations.push(traits::Obligation::new( @@ -467,7 +439,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); let callee = MethodCallee { def_id, args, sig: fn_sig }; - debug!("callee = {:?}", callee); Some(InferOk { obligations, value: callee }) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 569fdea11ce..eb5581f421b 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1365,7 +1365,6 @@ impl<'tcx> Pick<'tcx> { trait_item_def_id: _, fn_has_self_parameter: _, opt_rpitit_info: _, - is_effects_desugaring: _, }, kind: _, import_ids: _, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 1574e9e98d4..9c1459ee188 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -15,7 +15,7 @@ use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::{Ident, sym}; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt}; +use rustc_trait_selection::traits::{FulfillmentError, Obligation, ObligationCtxt}; use rustc_type_ir::TyKind::*; use tracing::debug; use {rustc_ast as ast, rustc_hir as hir}; @@ -256,23 +256,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(method) => { let by_ref_binop = !op.node.is_by_value(); if is_assign == IsAssign::Yes || by_ref_binop { - if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind() { + if let ty::Ref(_, _, mutbl) = method.sig.inputs()[0].kind() { let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes); let autoref = Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)), + kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)), target: method.sig.inputs()[0], }; self.apply_adjustments(lhs_expr, vec![autoref]); } } if by_ref_binop { - if let ty::Ref(region, _, mutbl) = method.sig.inputs()[1].kind() { + if let ty::Ref(_, _, mutbl) = method.sig.inputs()[1].kind() { // Allow two-phase borrows for binops in initial deployment // since they desugar to methods let mutbl = AutoBorrowMutability::new(*mutbl, AllowTwoPhase::Yes); let autoref = Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)), + kind: Adjust::Borrow(AutoBorrow::Ref(mutbl)), target: method.sig.inputs()[1], }; // HACK(eddyb) Bypass checks due to reborrows being in @@ -895,7 +895,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let opname = Ident::with_dummy_span(opname); let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip(); - let input_types = opt_rhs_ty.as_slice(); let cause = self.cause(span, ObligationCauseCode::BinOp { lhs_hir_id: lhs_expr.hir_id, rhs_hir_id: opt_rhs_expr.map(|expr| expr.hir_id), @@ -904,13 +903,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { output_ty: expected.only_has_type(self), }); - let method = self.lookup_method_in_trait( - cause.clone(), - opname, - trait_did, - lhs_ty, - Some(input_types), - ); + let method = + self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, opt_rhs_ty); match method { Some(ok) => { let method = self.register_infer_ok_obligations(ok); @@ -931,9 +925,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_coercible_to_type(rhs_expr, rhs_ty, None); } - let (obligation, _) = - self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types)); - // FIXME: This should potentially just add the obligation to the `FnCtxt` + // Construct an obligation `self_ty : Trait<input_tys>` + let args = + ty::GenericArgs::for_item(self.tcx, trait_did, |param, _| match param.kind { + ty::GenericParamDefKind::Lifetime + | ty::GenericParamDefKind::Const { .. } => { + unreachable!("did not expect operand trait to have lifetime/const args") + } + ty::GenericParamDefKind::Type { .. } => { + if param.index == 0 { + lhs_ty.into() + } else { + opt_rhs_ty.expect("expected RHS for binop").into() + } + } + }); + let obligation = Obligation::new( + self.tcx, + cause, + self.param_env, + ty::TraitRef::new_from_args(self.tcx, trait_did, args), + ); let ocx = ObligationCtxt::new_with_diagnostics(&self.infcx); ocx.register_obligation(obligation); Err(ocx.select_all_or_error()) diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 8604f5f6920..d5c7fe5fff3 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -29,9 +29,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?; let method = self.register_infer_ok_obligations(ok); - if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() { + if let ty::Ref(_, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() { self.apply_adjustments(oprnd_expr, vec![Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)), + kind: Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)), target: method.sig.inputs()[0], }]); } else { @@ -149,7 +149,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If some lookup succeeded, install method in table let input_ty = self.next_ty_var(base_expr.span); let method = - self.try_overloaded_place_op(expr.span, self_ty, &[input_ty], PlaceOp::Index); + self.try_overloaded_place_op(expr.span, self_ty, Some(input_ty), PlaceOp::Index); if let Some(result) = method { debug!("try_index_step: success, using overloaded indexing"); @@ -158,7 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut adjustments = self.adjust_steps(autoderef); if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() { adjustments.push(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)), + kind: Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)), target: Ty::new_imm_ref(self.tcx, *region, adjusted_ty), }); } else { @@ -189,7 +189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, base_ty: Ty<'tcx>, - arg_tys: &[Ty<'tcx>], + opt_rhs_ty: Option<Ty<'tcx>>, op: PlaceOp, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op); @@ -207,7 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ident::with_dummy_span(imm_op), imm_tr, base_ty, - Some(arg_tys), + opt_rhs_ty, ) } @@ -215,7 +215,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, base_ty: Ty<'tcx>, - arg_tys: &[Ty<'tcx>], + opt_rhs_ty: Option<Ty<'tcx>>, op: PlaceOp, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op); @@ -233,7 +233,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ident::with_dummy_span(mut_op), mut_tr, base_ty, - Some(arg_tys), + opt_rhs_ty, ) } @@ -284,14 +284,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(ok) = self.try_mutable_overloaded_place_op( expr.span, source, - &[], + None, PlaceOp::Deref, ) { let method = self.register_infer_ok_obligations(ok); - if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { - *deref = OverloadedDeref { region, mutbl, span: deref.span }; - } + let ty::Ref(_, _, mutbl) = *method.sig.output().kind() else { + span_bug!( + self.tcx.def_span(method.def_id), + "expected DerefMut to return a &mut" + ); + }; + *deref = OverloadedDeref { mutbl, span: deref.span }; // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514). // This helps avoid accidental drops. if inside_union @@ -359,8 +363,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(self.typeck_results.borrow().node_args(expr.hir_id).type_at(1)) } }; - let arg_tys = arg_ty.as_slice(); - let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op); + let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_ty, op); let method = match method { Some(ok) => self.register_infer_ok_obligations(ok), // Couldn't find the mutable variant of the place op, keep the @@ -391,7 +394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // not the case today. allow_two_phase_borrow: AllowTwoPhase::No, }; - adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)); + adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(mutbl)); adjustment.target = Ty::new_ref(self.tcx, *region, source, mutbl.into()); } source = adjustment.target; diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 18e40cfa428..903be7e732a 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -8,7 +8,7 @@ use rustc_hir::{HirId, HirIdMap}; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_middle::span_bug; use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_span::Span; use rustc_span::def_id::LocalDefIdMap; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -81,7 +81,8 @@ impl<'tcx> TypeckRootCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; - let infcx = tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(def_id).build(); + let infcx = + tcx.infer_ctxt().ignoring_regions().build(TypingMode::analysis_in_body(tcx, def_id)); let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner)); TypeckRootCtxt { diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 8c943a961e7..3eda3e9c67e 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -28,7 +28,7 @@ use relate::lattice::{LatticeOp, LatticeOpKind}; use rustc_middle::bug; use rustc_middle::ty::relate::solver_relating::RelateExt as NextSolverRelate; -use rustc_middle::ty::{Const, ImplSubject}; +use rustc_middle::ty::{Const, ImplSubject, TypingMode}; use super::*; use crate::infer::relate::type_relating::TypeRelating; @@ -67,30 +67,48 @@ impl<'tcx> InferCtxt<'tcx> { /// variables in the same state. This can be used to "branch off" many tests from the same /// common state. pub fn fork(&self) -> Self { - self.fork_with_intercrate(self.intercrate) + Self { + tcx: self.tcx, + typing_mode: self.typing_mode, + considering_regions: self.considering_regions, + skip_leak_check: self.skip_leak_check, + inner: self.inner.clone(), + lexical_region_resolutions: self.lexical_region_resolutions.clone(), + selection_cache: self.selection_cache.clone(), + evaluation_cache: self.evaluation_cache.clone(), + reported_trait_errors: self.reported_trait_errors.clone(), + reported_signature_mismatch: self.reported_signature_mismatch.clone(), + tainted_by_errors: self.tainted_by_errors.clone(), + universe: self.universe.clone(), + next_trait_solver: self.next_trait_solver, + obligation_inspector: self.obligation_inspector.clone(), + } } /// Forks the inference context, creating a new inference context with the same inference /// variables in the same state, except possibly changing the intercrate mode. This can be /// used to "branch off" many tests from the same common state. Used in negative coherence. - pub fn fork_with_intercrate(&self, intercrate: bool) -> Self { - Self { + pub fn fork_with_typing_mode(&self, typing_mode: TypingMode<'tcx>) -> Self { + // Unlike `fork`, this invalidates all cache entries as they may depend on the + // typing mode. + let forked = Self { tcx: self.tcx, - defining_opaque_types: self.defining_opaque_types, + typing_mode, considering_regions: self.considering_regions, skip_leak_check: self.skip_leak_check, inner: self.inner.clone(), lexical_region_resolutions: self.lexical_region_resolutions.clone(), - selection_cache: self.selection_cache.clone(), - evaluation_cache: self.evaluation_cache.clone(), + selection_cache: Default::default(), + evaluation_cache: Default::default(), reported_trait_errors: self.reported_trait_errors.clone(), reported_signature_mismatch: self.reported_signature_mismatch.clone(), tainted_by_errors: self.tainted_by_errors.clone(), universe: self.universe.clone(), - intercrate, next_trait_solver: self.next_trait_solver, obligation_inspector: self.obligation_inspector.clone(), - } + }; + forked.inner.borrow_mut().projection_cache().clear(); + forked } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 90d07964fda..c9d8ebecef0 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -46,7 +46,7 @@ impl<'tcx> InferCtxt<'tcx> { V: TypeFoldable<TyCtxt<'tcx>>, { let (param_env, value) = value.into_parts(); - let param_env = self.tcx.canonical_param_env_cache.get_or_insert( + let canonical_param_env = self.tcx.canonical_param_env_cache.get_or_insert( self.tcx, param_env, query_state, @@ -64,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> { ); let canonical = Canonicalizer::canonicalize_with_base( - param_env, + canonical_param_env, value, Some(self), self.tcx, @@ -72,7 +72,7 @@ impl<'tcx> InferCtxt<'tcx> { query_state, ) .unchecked_map(|(param_env, value)| param_env.and(value)); - CanonicalQueryInput { canonical, defining_opaque_types: self.defining_opaque_types() } + CanonicalQueryInput { canonical, typing_mode: self.typing_mode(param_env) } } /// Canonicalizes a query *response* `V`. When we canonicalize a diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 0c151a11ad4..ecda9c6eb00 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -1,7 +1,6 @@ ///! Definition of `InferCtxtLike` from the librarified type layer. -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::DefId; use rustc_middle::traits::ObligationCause; -use rustc_middle::traits::solve::SolverMode; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::relate::combine::PredicateEmittingRelation; @@ -21,11 +20,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.next_trait_solver } - fn solver_mode(&self) -> ty::solve::SolverMode { - match self.intercrate { - true => SolverMode::Coherence, - false => SolverMode::Normal, - } + fn typing_mode( + &self, + param_env_for_debug_assertion: ty::ParamEnv<'tcx>, + ) -> ty::TypingMode<'tcx> { + self.typing_mode(param_env_for_debug_assertion) } fn universe(&self) -> ty::UniverseIndex { @@ -91,10 +90,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) } - fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { - self.defining_opaque_types() - } - fn next_ty_infer(&self) -> Ty<'tcx> { self.next_ty_var(DUMMY_SP) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index be43cba97f0..fc54d69449f 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -38,11 +38,12 @@ use rustc_middle::ty::fold::{ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, - GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, + GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_span::Span; use rustc_span::symbol::Symbol; +use rustc_type_ir::solve::Reveal; use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; use type_variable::TypeVariableOrigin; @@ -243,8 +244,9 @@ impl<'tcx> InferCtxtInner<'tcx> { pub struct InferCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, - /// The `DefIds` of the opaque types that may have their hidden types constrained. - defining_opaque_types: &'tcx ty::List<LocalDefId>, + /// The mode of this inference context, see the struct documentation + /// for more details. + typing_mode: TypingMode<'tcx>, /// Whether this inference context should care about region obligations in /// the root universe. Most notably, this is used during hir typeck as region @@ -296,26 +298,6 @@ pub struct InferCtxt<'tcx> { /// bound. universe: Cell<ty::UniverseIndex>, - /// During coherence we have to assume that other crates may add - /// additional impls which we currently don't know about. - /// - /// To deal with this evaluation, we should be conservative - /// and consider the possibility of impls from outside this crate. - /// This comes up primarily when resolving ambiguity. Imagine - /// there is some trait reference `$0: Bar` where `$0` is an - /// inference variable. If `intercrate` is true, then we can never - /// say for sure that this reference is not implemented, even if - /// there are *no impls at all for `Bar`*, because `$0` could be - /// bound to some type that in a downstream crate that implements - /// `Bar`. - /// - /// Outside of coherence, we set this to false because we are only - /// interested in types that the user could actually have written. - /// In other words, we consider `$0: Bar` to be unimplemented if - /// there is no type that the user could *actually name* that - /// would satisfy it. This avoids crippling inference, basically. - pub intercrate: bool, - next_trait_solver: bool, pub obligation_inspector: Cell<Option<ObligationInspector<'tcx>>>, @@ -529,11 +511,8 @@ pub struct RegionObligation<'tcx> { /// Used to configure inference contexts before their creation. pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, - defining_opaque_types: &'tcx ty::List<LocalDefId>, considering_regions: bool, skip_leak_check: bool, - /// Whether we are in coherence mode. - intercrate: bool, /// Whether we should use the new trait solver in the local inference context, /// which affects things like which solver is used in `predicate_may_hold`. next_trait_solver: bool, @@ -544,37 +523,19 @@ impl<'tcx> TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { InferCtxtBuilder { tcx: self, - defining_opaque_types: ty::List::empty(), considering_regions: true, skip_leak_check: false, - intercrate: false, next_trait_solver: self.next_trait_solver_globally(), } } } impl<'tcx> InferCtxtBuilder<'tcx> { - /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types, - /// you need to call this function. Otherwise the opaque type will be treated opaquely. - /// - /// It is only meant to be called in two places, for typeck - /// (via `Inherited::build`) and for the inference context used - /// in mir borrowck. - pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self { - self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor); - self - } - pub fn with_next_trait_solver(mut self, next_trait_solver: bool) -> Self { self.next_trait_solver = next_trait_solver; self } - pub fn intercrate(mut self, intercrate: bool) -> Self { - self.intercrate = intercrate; - self - } - pub fn ignoring_regions(mut self) -> Self { self.considering_regions = false; self @@ -600,24 +561,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> { where T: TypeFoldable<TyCtxt<'tcx>>, { - self.defining_opaque_types = input.defining_opaque_types; - let infcx = self.build(); + let infcx = self.build(input.typing_mode); let (value, args) = infcx.instantiate_canonical(span, &input.canonical); (infcx, value, args) } - pub fn build(&mut self) -> InferCtxt<'tcx> { - let InferCtxtBuilder { - tcx, - defining_opaque_types, - considering_regions, - skip_leak_check, - intercrate, - next_trait_solver, - } = *self; + pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> { + let InferCtxtBuilder { tcx, considering_regions, skip_leak_check, next_trait_solver } = + *self; InferCtxt { tcx, - defining_opaque_types, + typing_mode, considering_regions, skip_leak_check, inner: RefCell::new(InferCtxtInner::new()), @@ -628,7 +582,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { reported_signature_mismatch: Default::default(), tainted_by_errors: Cell::new(None), universe: Cell::new(ty::UniverseIndex::ROOT), - intercrate, next_trait_solver, obligation_inspector: Cell::new(None), } @@ -659,14 +612,30 @@ impl<'tcx> InferCtxt<'tcx> { self.tcx.dcx().taintable_handle(&self.tainted_by_errors) } - pub fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { - self.defining_opaque_types - } - pub fn next_trait_solver(&self) -> bool { self.next_trait_solver } + #[inline(always)] + pub fn typing_mode( + &self, + param_env_for_debug_assertion: ty::ParamEnv<'tcx>, + ) -> TypingMode<'tcx> { + if cfg!(debug_assertions) { + match (param_env_for_debug_assertion.reveal(), self.typing_mode) { + (Reveal::All, TypingMode::PostAnalysis) + | (Reveal::UserFacing, TypingMode::Coherence | TypingMode::Analysis { .. }) => {} + (r, t) => unreachable!("TypingMode x Reveal mismatch: {r:?} {t:?}"), + } + } + self.typing_mode + } + + #[inline(always)] + pub fn typing_mode_unchecked(&self) -> TypingMode<'tcx> { + self.typing_mode + } + pub fn freshen<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) } @@ -1029,8 +998,12 @@ impl<'tcx> InferCtxt<'tcx> { #[inline(always)] pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool { - let Some(id) = id.into().as_local() else { return false }; - self.defining_opaque_types.contains(&id) + match self.typing_mode_unchecked() { + TypingMode::Analysis { defining_opaque_types } => { + id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id)) + } + TypingMode::Coherence | TypingMode::PostAnalysis => false, + } } pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 853ae6d2641..2bc006c37da 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -2,6 +2,7 @@ use hir::def_id::{DefId, LocalDefId}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; +use rustc_middle::bug; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::Goal; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -100,7 +101,7 @@ impl<'tcx> InferCtxt<'tcx> { let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => { let def_id = def_id.expect_local(); - if self.intercrate { + if let ty::TypingMode::Coherence = self.typing_mode(param_env) { // See comment on `insert_hidden_type` for why this is sufficient in coherence return Some(self.register_hidden_type( OpaqueTypeKey { def_id, args }, @@ -154,7 +155,10 @@ impl<'tcx> InferCtxt<'tcx> { // however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, where // it is of no concern, so we only check for TAITs. if self.can_define_opaque_ty(b_def_id) - && self.tcx.is_type_alias_impl_trait(b_def_id) + && matches!( + self.tcx.opaque_ty_origin(b_def_id), + hir::OpaqueTyOrigin::TyAlias { .. } + ) { self.dcx().emit_err(OpaqueHiddenTypeDiag { span, @@ -364,7 +368,7 @@ impl<'tcx> InferCtxt<'tcx> { span, concrete_ty, r, - choice_regions.clone(), + Lrc::clone(&choice_regions), ) }, }); @@ -519,28 +523,32 @@ impl<'tcx> InferCtxt<'tcx> { // value being folded. In simple cases like `-> impl Foo`, // these are the same span, but not in cases like `-> (impl // Foo, impl Bar)`. - if self.intercrate { - // During intercrate we do not define opaque types but instead always - // force ambiguity unless the hidden type is known to not implement - // our trait. - goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous)) - } else { - let prev = self - .inner - .borrow_mut() - .opaque_types() - .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span }); - if let Some(prev) = prev { - goals.extend( - self.at(&ObligationCause::dummy_with_span(span), param_env) - .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)? - .obligations - .into_iter() - // FIXME: Shuttling between obligations and goals is awkward. - .map(Goal::from), - ); + match self.typing_mode(param_env) { + ty::TypingMode::Coherence => { + // During intercrate we do not define opaque types but instead always + // force ambiguity unless the hidden type is known to not implement + // our trait. + goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous)); } - }; + ty::TypingMode::Analysis { .. } => { + let prev = self + .inner + .borrow_mut() + .opaque_types() + .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span }); + if let Some(prev) = prev { + goals.extend( + self.at(&ObligationCause::dummy_with_span(span), param_env) + .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)? + .obligations + .into_iter() + // FIXME: Shuttling between obligations and goals is awkward. + .map(Goal::from), + ); + } + } + ty::TypingMode::PostAnalysis => bug!("insert hidden type post-analysis"), + } Ok(()) } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 32817dbcb21..4c80bf4e07e 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -9,6 +9,7 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::visit::MaxUniverse; use rustc_middle::ty::{ self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeVisitable, TypeVisitableExt, + TypingMode, }; use rustc_span::Span; use tracing::{debug, instrument, warn}; @@ -519,7 +520,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { // // cc trait-system-refactor-initiative#108 if self.infcx.next_trait_solver() - && !self.infcx.intercrate + && !matches!( + self.infcx.typing_mode_unchecked(), + TypingMode::Coherence + ) && self.in_alias { inner.type_variables().equate(vid, new_var_id); @@ -650,7 +654,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { // See the comment for type inference variables // for more details. if self.infcx.next_trait_solver() - && !self.infcx.intercrate + && !matches!( + self.infcx.typing_mode_unchecked(), + TypingMode::Coherence + ) && self.in_alias { variable_table.union(vid, new_var_id); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 3a1833452d4..b6837ec764f 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -142,7 +142,7 @@ impl Linker { Ok(Linker { dep_graph: tcx.dep_graph.clone(), - output_filenames: tcx.output_filenames(()).clone(), + output_filenames: Arc::clone(tcx.output_filenames(())), crate_hash: if tcx.needs_crate_hash() { Some(tcx.crate_hash(LOCAL_CRATE)) } else { diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index 232d4c18fa4..dd7b40d0a32 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 3fa43296dfc..9187f6caad4 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -268,7 +268,7 @@ lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edi lint_extern_without_abi = extern declarations without an explicit ABI are deprecated .label = ABI should be specified here - .help = the default ABI is {$default_abi} + .suggestion = explicitly specify the {$default_abi} ABI lint_for_loops_over_fallibles = for loop over {$article} `{$ref_prefix}{$ty}`. This is more readably written as an `if let` statement diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index dbb8c667532..02d22ee49bd 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -16,6 +16,7 @@ use std::fmt::Write; use ast::token::TokenKind; +use rustc_abi::BackendRepr; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; @@ -31,7 +32,7 @@ use rustc_middle::bug; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, VariantDef}; use rustc_session::lint::FutureIncompatibilityReason; // hardwired lints from rustc_lint_defs pub use rustc_session::lint::builtin::*; @@ -40,7 +41,6 @@ use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{BytePos, InnerSpan, Span}; -use rustc_target::abi::Abi; use rustc_target::asm::InlineAsmArch; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; @@ -604,7 +604,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { && cx .tcx .infer_ctxt() - .build() + .build(cx.typing_mode()) .type_implements_trait(iter_trait, [ty], cx.param_env) .must_apply_modulo_regions() { @@ -648,7 +648,9 @@ fn type_implements_negative_copy_modulo_regions<'tcx>( predicate: pred.upcast(tcx), }; - tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) + tcx.infer_ctxt() + .build(TypingMode::non_body_analysis()) + .predicate_must_hold_modulo_regions(&obligation) } declare_lint! { @@ -2466,7 +2468,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { // Check if this ADT has a constrained layout (like `NonNull` and friends). if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) { - if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &layout.abi { + if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) = + &layout.backend_repr + { let range = scalar.valid_range(cx); let msg = if !range.contains(0) { "must be non-null" diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 4af1fd1baf9..aa7ec2659d0 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -11,15 +11,15 @@ use rustc_data_structures::sync; use rustc_data_structures::unord::UnordMap; use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; use rustc_feature::Features; -use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_infer::traits::Reveal; use rustc_middle::bug; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths}; -use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingMode}; use rustc_session::lint::{ BuiltinLintDiag, FutureIncompatibleInfo, Level, Lint, LintBuffer, LintExpectationId, LintId, }; @@ -27,8 +27,8 @@ use rustc_session::{LintStoreMarker, Session}; use rustc_span::Span; use rustc_span::edit_distance::find_best_match_for_names; use rustc_span::symbol::{Ident, Symbol, sym}; -use rustc_target::abi; use tracing::debug; +use {rustc_abi as abi, rustc_hir as hir}; use self::TargetLint::*; use crate::levels::LintLevelsBuilder; @@ -699,6 +699,15 @@ impl LintContext for EarlyContext<'_> { } impl<'tcx> LateContext<'tcx> { + /// The typing mode of the currently visited node. Use this when + /// building a new `InferCtxt`. + pub fn typing_mode(&self) -> TypingMode<'tcx> { + debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing); + // FIXME(#132279): In case we're in a body, we should use a typing + // mode which reveals the opaque types defined by that body. + TypingMode::non_body_analysis() + } + /// Gets the type-checking results for the current body, /// or `None` if outside a body. pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> { diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index fcb7a6108c0..cf68e41243f 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -166,7 +166,7 @@ fn suggest_question_mark<'tcx>( } let ty = args.type_at(0); - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); let ocx = ObligationCtxt::new(&infcx); let body_def_id = cx.tcx.hir().body_owner_def_id(body_id); diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 816882962be..394ea798d3e 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -1,3 +1,4 @@ +use rustc_abi::FIRST_VARIANT; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; @@ -6,7 +7,6 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt}; use rustc_session::declare_lint; use rustc_span::{Span, Symbol, sym}; -use rustc_target::abi::FIRST_VARIANT; use tracing::{debug, instrument}; use crate::lints::{BuiltinClashingExtern, BuiltinClashingExternSub}; @@ -217,7 +217,7 @@ fn structurally_same_type<'tcx>( // `extern` blocks cannot be generic, so we'll always get a layout here. let a_layout = tcx.layout_of(param_env.and(a)).unwrap(); let b_layout = tcx.layout_of(param_env.and(b)).unwrap(); - assert_eq!(a_layout.abi, b_layout.abi); + assert_eq!(a_layout.backend_repr, b_layout.backend_repr); assert_eq!(a_layout.size, b_layout.size); assert_eq!(a_layout.align, b_layout.align); } diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index bdfcc2c0a10..afcfbebc14b 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -24,7 +24,6 @@ declare_lint! { /// ### Example /// /// ```rust,edition2021 - /// #![feature(if_let_rescope)] /// #![warn(if_let_rescope)] /// #![allow(unused_variables)] /// @@ -243,7 +242,7 @@ impl_lint_pass!( impl<'tcx> LateLintPass<'tcx> for IfLetRescope { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope() { + if expr.span.edition().at_least_rust_2024() { return; } if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) { diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index cc40b67ab27..026826021c8 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::relate::{ Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys, }; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::FutureIncompatibilityReason; @@ -184,7 +184,7 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) { }), outlives_env: LazyCell::new(|| { let param_env = tcx.param_env(parent_def_id); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let ocx = ObligationCtxt::new(&infcx); let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default(); let implied_bounds = diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 000f4b697bd..38e52570e53 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2738,11 +2738,9 @@ pub(crate) struct PatternsInFnsWithoutBodySub { #[derive(LintDiagnostic)] #[diag(lint_extern_without_abi)] -#[help] pub(crate) struct MissingAbi { - #[label] + #[suggestion(code = "extern \"{default_abi}\"", applicability = "machine-applicable")] pub span: Span, - pub default_abi: &'static str, } diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 51877e8a034..cf25ec99e67 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -157,7 +157,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc Some(ty_def) if cx.tcx.is_lang_item(ty_def.did(), LangItem::String), ); - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); let suggest_display = is_str || cx.tcx.get_diagnostic_item(sym::Display).is_some_and(|t| { infcx.type_implements_trait(t, [ty], cx.param_env).may_apply() diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index ffbcf7f808e..5de0d4bc870 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -69,7 +69,7 @@ declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]); impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx>) { - let hir::TyKind::OpaqueDef(opaque, _) = &ty.kind else { + let hir::TyKind::OpaqueDef(opaque) = &ty.kind else { return; }; @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { } let def_id = opaque.def_id.to_def_id(); - let infcx = &cx.tcx.infer_ctxt().build(); + let infcx = &cx.tcx.infer_ctxt().build(cx.typing_mode()); // For every projection predicate in the opaque type's explicit bounds, // check that the type that we're assigning actually satisfies the bounds // of the associated type. diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 0751d35cb9c..88878a018e7 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,6 +1,7 @@ use std::iter; use std::ops::ControlFlow; +use rustc_abi::{BackendRepr, TagEncoding, Variants, WrappingRange}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; use rustc_hir::{Expr, ExprKind}; @@ -13,7 +14,6 @@ use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol, source_map}; -use rustc_target::abi::{Abi, TagEncoding, Variants, WrappingRange}; use rustc_target::spec::abi::Abi as SpecAbi; use tracing::debug; use {rustc_ast as ast, rustc_hir as hir}; @@ -776,8 +776,8 @@ pub(crate) fn repr_nullable_ptr<'tcx>( bug!("should be able to compute the layout of non-polymorphic type"); } - let field_ty_abi = &field_ty_layout.ok()?.abi; - if let Abi::Scalar(field_ty_scalar) = field_ty_abi { + let field_ty_abi = &field_ty_layout.ok()?.backend_repr; + if let BackendRepr::Scalar(field_ty_scalar) = field_ty_abi { match field_ty_scalar.valid_range(&tcx) { WrappingRange { start: 0, end } if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs index d1e850990dc..dca42fea57d 100644 --- a/compiler/rustc_lint/src/types/literal.rs +++ b/compiler/rustc_lint/src/types/literal.rs @@ -1,8 +1,8 @@ use hir::{ExprKind, Node, is_range_literal}; +use rustc_abi::{Integer, Size}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::{bug, ty}; -use rustc_target::abi::{Integer, Size}; use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir}; use crate::LateContext; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index bbb290c9459..b50a95e7d2b 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1610,7 +1610,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation { } for adj in cx.typeck_results().expr_adjustments(e) { - if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind { + if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(m)) = adj.kind { match m { adjustment::AutoBorrowMutability::Not => { cx.emit_span_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationDiag); diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml index eb2a184ef84..450885e7164 100644 --- a/compiler/rustc_lint_defs/Cargo.toml +++ b/compiler/rustc_lint_defs/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_messages = { path = "../rustc_error_messages" } @@ -12,6 +13,5 @@ rustc_hir = { path = "../rustc_hir" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } -rustc_target = { path = "../rustc_target" } serde = { version = "1.0.125", features = ["derive"] } # tidy-alphabetical-end diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 601784f9732..0caf6ef3a6d 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -2,6 +2,7 @@ #![warn(unreachable_pub)] // tidy-alphabetical-end +use rustc_abi::ExternAbi; use rustc_ast::node_id::NodeId; use rustc_ast::{AttrId, Attribute}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -15,7 +16,6 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; pub use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; use rustc_span::{Span, Symbol, sym}; -use rustc_target::spec::abi::Abi; use serde::{Deserialize, Serialize}; pub use self::Level::*; @@ -602,7 +602,7 @@ pub enum BuiltinLintDiag { path: String, since_kind: DeprecatedSinceKind, }, - MissingAbi(Span, Abi), + MissingAbi(Span, ExternAbi), UnusedDocComment(Span), UnusedBuiltinAttribute { attr_name: Symbol, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 4b303511dbc..3e906f89c15 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1251,12 +1251,12 @@ getFirstDefinitionForLinker(const GlobalValueSummaryList &GVSummaryList) { // here is basically the same as before threads are spawned in the `run` // function of `lib/LTO/ThinLTOCodeGenerator.cpp`. extern "C" LLVMRustThinLTOData * -LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, int num_modules, - const char **preserved_symbols, int num_symbols) { +LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, size_t num_modules, + const char **preserved_symbols, size_t num_symbols) { auto Ret = std::make_unique<LLVMRustThinLTOData>(); // Load each module's summary and merge it into one combined index - for (int i = 0; i < num_modules; i++) { + for (size_t i = 0; i < num_modules; i++) { auto module = &modules[i]; auto buffer = StringRef(module->data, module->len); auto mem_buffer = MemoryBufferRef(buffer, module->identifier); @@ -1275,7 +1275,7 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, int num_modules, // Convert the preserved symbols set from string to GUID, this is then needed // for internalization. - for (int i = 0; i < num_symbols; i++) { + for (size_t i = 0; i < num_symbols; i++) { auto GUID = GlobalValue::getGUID(preserved_symbols[i]); Ret->GUIDPreservedSymbols.insert(GUID); } @@ -1559,8 +1559,10 @@ extern "C" LLVMModuleRef LLVMRustParseBitcodeForLTO(LLVMContextRef Context, extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data, size_t len, const char *name, + size_t name_len, size_t *out_len) { *out_len = 0; + auto Name = StringRef(name, name_len); auto Data = StringRef(data, len); auto Buffer = MemoryBufferRef(Data, ""); // The id is unused. file_magic Type = identify_magic(Buffer.getBuffer()); @@ -1571,8 +1573,8 @@ extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data, return nullptr; } for (const object::SectionRef &Sec : (*ObjFileOrError)->sections()) { - Expected<StringRef> Name = Sec.getName(); - if (Name && *Name == name) { + Expected<StringRef> SecName = Sec.getName(); + if (SecName && *SecName == Name) { Expected<StringRef> SectionOrError = Sec.getContents(); if (!SectionOrError) { LLVMRustSetLastError(toString(SectionOrError.takeError()).c_str()); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 9f941637d8c..645b4082be5 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -853,25 +853,63 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } -extern "C" void LLVMRustAddModuleFlagU32(LLVMModuleRef M, - Module::ModFlagBehavior MergeBehavior, - const char *Name, uint32_t Value) { - unwrap(M)->addModuleFlag(MergeBehavior, Name, Value); +// FFI equivalent of LLVM's `llvm::Module::ModFlagBehavior`. +// Must match the layout of +// `rustc_codegen_llvm::llvm::ffi::ModuleFlagMergeBehavior`. +// +// There is a stable LLVM-C version of this enum (`LLVMModuleFlagBehavior`), +// but as of LLVM 19 it does not support all of the enum values in the unstable +// C++ API. +enum class LLVMRustModuleFlagMergeBehavior { + Error = 1, + Warning = 2, + Require = 3, + Override = 4, + Append = 5, + AppendUnique = 6, + Max = 7, + Min = 8, +}; + +static Module::ModFlagBehavior +fromRust(LLVMRustModuleFlagMergeBehavior Behavior) { + switch (Behavior) { + case LLVMRustModuleFlagMergeBehavior::Error: + return Module::ModFlagBehavior::Error; + case LLVMRustModuleFlagMergeBehavior::Warning: + return Module::ModFlagBehavior::Warning; + case LLVMRustModuleFlagMergeBehavior::Require: + return Module::ModFlagBehavior::Require; + case LLVMRustModuleFlagMergeBehavior::Override: + return Module::ModFlagBehavior::Override; + case LLVMRustModuleFlagMergeBehavior::Append: + return Module::ModFlagBehavior::Append; + case LLVMRustModuleFlagMergeBehavior::AppendUnique: + return Module::ModFlagBehavior::AppendUnique; + case LLVMRustModuleFlagMergeBehavior::Max: + return Module::ModFlagBehavior::Max; + case LLVMRustModuleFlagMergeBehavior::Min: + return Module::ModFlagBehavior::Min; + } + report_fatal_error("bad LLVMRustModuleFlagMergeBehavior"); +} + +extern "C" void +LLVMRustAddModuleFlagU32(LLVMModuleRef M, + LLVMRustModuleFlagMergeBehavior MergeBehavior, + const char *Name, size_t NameLen, uint32_t Value) { + unwrap(M)->addModuleFlag(fromRust(MergeBehavior), StringRef(Name, NameLen), + Value); } extern "C" void LLVMRustAddModuleFlagString( - LLVMModuleRef M, Module::ModFlagBehavior MergeBehavior, const char *Name, - const char *Value, size_t ValueLen) { + LLVMModuleRef M, LLVMRustModuleFlagMergeBehavior MergeBehavior, + const char *Name, size_t NameLen, const char *Value, size_t ValueLen) { unwrap(M)->addModuleFlag( - MergeBehavior, Name, + fromRust(MergeBehavior), StringRef(Name, NameLen), MDString::get(unwrap(M)->getContext(), StringRef(Value, ValueLen))); } -extern "C" bool LLVMRustHasModuleFlag(LLVMModuleRef M, const char *Name, - size_t Len) { - return unwrap(M)->getModuleFlag(StringRef(Name, Len)) != nullptr; -} - extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind, LLVMMetadataRef MD) { unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD)); @@ -1231,7 +1269,7 @@ extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() { return dwarf::DW_OP_plus_uconst; } -extern "C" int64_t LLVMRustDIBuilderCreateOpLLVMFragment() { +extern "C" uint64_t LLVMRustDIBuilderCreateOpLLVMFragment() { return dwarf::DW_OP_LLVM_fragment; } @@ -1499,38 +1537,6 @@ LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, RustStringRef MessageOut, return true; } -extern "C" OperandBundleDef *LLVMRustBuildOperandBundleDef(const char *Name, - LLVMValueRef *Inputs, - unsigned NumInputs) { - return new OperandBundleDef(Name, - ArrayRef<Value *>(unwrap(Inputs), NumInputs)); -} - -extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) { - delete Bundle; -} - -// OpBundlesIndirect is an array of pointers (*not* a pointer to an array). -extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, - LLVMValueRef Fn, LLVMValueRef *Args, - unsigned NumArgs, - OperandBundleDef **OpBundlesIndirect, - unsigned NumOpBundles) { - Value *Callee = unwrap(Fn); - FunctionType *FTy = unwrap<FunctionType>(Ty); - - // FIXME: Is there a way around this? - SmallVector<OperandBundleDef> OpBundles; - OpBundles.reserve(NumOpBundles); - for (unsigned i = 0; i < NumOpBundles; ++i) { - OpBundles.push_back(*OpBundlesIndirect[i]); - } - - return wrap(unwrap(B)->CreateCall(FTy, Callee, - ArrayRef<Value *>(unwrap(Args), NumArgs), - ArrayRef<OperandBundleDef>(OpBundles))); -} - extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, LLVMValueRef Src, unsigned SrcAlign, @@ -1558,37 +1564,18 @@ extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B, LLVMValueRef Dst, MaybeAlign(DstAlign), IsVolatile)); } -// OpBundlesIndirect is an array of pointers (*not* a pointer to an array). -extern "C" LLVMValueRef -LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, - LLVMValueRef *Args, unsigned NumArgs, - LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, - OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles, - const char *Name) { - Value *Callee = unwrap(Fn); - FunctionType *FTy = unwrap<FunctionType>(Ty); - - // FIXME: Is there a way around this? - SmallVector<OperandBundleDef> OpBundles; - OpBundles.reserve(NumOpBundles); - for (unsigned i = 0; i < NumOpBundles; ++i) { - OpBundles.push_back(*OpBundlesIndirect[i]); - } - - return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch), - ArrayRef<Value *>(unwrap(Args), NumArgs), - ArrayRef<OperandBundleDef>(OpBundles), - Name)); -} +// Polyfill for `LLVMBuildCallBr`, which was added in LLVM 19. +// <https://github.com/llvm/llvm-project/commit/584253c4e2f788f870488fc32193b52d67ddaccc> +// FIXME: Remove when Rust's minimum supported LLVM version reaches 19. +#if LLVM_VERSION_LT(19, 0) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OperandBundleDef, LLVMOperandBundleRef) -// OpBundlesIndirect is an array of pointers (*not* a pointer to an array). extern "C" LLVMValueRef -LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, - LLVMBasicBlockRef DefaultDest, - LLVMBasicBlockRef *IndirectDests, unsigned NumIndirectDests, - LLVMValueRef *Args, unsigned NumArgs, - OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles, - const char *Name) { +LLVMBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, + LLVMBasicBlockRef DefaultDest, LLVMBasicBlockRef *IndirectDests, + unsigned NumIndirectDests, LLVMValueRef *Args, unsigned NumArgs, + LLVMOperandBundleRef *Bundles, unsigned NumBundles, + const char *Name) { Value *Callee = unwrap(Fn); FunctionType *FTy = unwrap<FunctionType>(Ty); @@ -1601,9 +1588,9 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, // FIXME: Is there a way around this? SmallVector<OperandBundleDef> OpBundles; - OpBundles.reserve(NumOpBundles); - for (unsigned i = 0; i < NumOpBundles; ++i) { - OpBundles.push_back(*OpBundlesIndirect[i]); + OpBundles.reserve(NumBundles); + for (unsigned i = 0; i < NumBundles; ++i) { + OpBundles.push_back(*unwrap(Bundles[i])); } return wrap( @@ -1612,6 +1599,7 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, ArrayRef<Value *>(unwrap(Args), NumArgs), ArrayRef<OperandBundleDef>(OpBundles), Name)); } +#endif extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B, LLVMBasicBlockRef BB) { diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 79d3482472a..cece700b4dd 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" bitflags = "2.4.1" libloading = "0.8.0" odht = { version = "0.3.1", features = ["nightly"] } +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } @@ -26,7 +27,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_type_ir = { path = "../rustc_type_ir" } -snap = "1" tempfile = "3.2" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index a4a69ae9514..f924ed48b6f 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -213,7 +213,7 @@ //! metadata::locator or metadata::creader for all the juicy details! use std::borrow::Cow; -use std::io::{Read, Result as IoResult, Write}; +use std::io::{Result as IoResult, Write}; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::{cmp, fmt}; @@ -232,7 +232,6 @@ use rustc_session::utils::CanonicalizedPath; use rustc_span::Span; use rustc_span::symbol::Symbol; use rustc_target::spec::{Target, TargetTriple}; -use snap::read::FrameDecoder; use tracing::{debug, info}; use crate::creader::{Library, MetadataLoader}; @@ -792,7 +791,6 @@ fn get_metadata_section<'p>( CrateFlavor::Dylib => { let buf = loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?; - // The header is uncompressed let header_len = METADATA_HEADER.len(); // header + u64 length of data let data_start = header_len + 8; @@ -806,7 +804,7 @@ fn get_metadata_section<'p>( ))); } - // Length of the compressed stream - this allows linkers to pad the section if they want + // Length of the metadata - this allows linkers to pad the section if they want let Ok(len_bytes) = <[u8; 8]>::try_from(&buf[header_len..cmp::min(data_start, buf.len())]) else { @@ -814,29 +812,10 @@ fn get_metadata_section<'p>( "invalid metadata length found".to_string(), )); }; - let compressed_len = u64::from_le_bytes(len_bytes) as usize; + let metadata_len = u64::from_le_bytes(len_bytes) as usize; // Header is okay -> inflate the actual metadata - let compressed_bytes = buf.slice(|buf| &buf[data_start..(data_start + compressed_len)]); - if &compressed_bytes[..cmp::min(METADATA_HEADER.len(), compressed_bytes.len())] - == METADATA_HEADER - { - // The metadata was not actually compressed. - compressed_bytes - } else { - debug!("inflating {} bytes of compressed metadata", compressed_bytes.len()); - // Assume the decompressed data will be at least the size of the compressed data, so we - // don't have to grow the buffer as much. - let mut inflated = Vec::with_capacity(compressed_bytes.len()); - FrameDecoder::new(&*compressed_bytes).read_to_end(&mut inflated).map_err(|_| { - MetadataError::LoadFailure(format!( - "failed to decompress metadata: {}", - filename.display() - )) - })?; - - slice_owned(inflated, Deref::deref) - } + buf.slice(|buf| &buf[data_start..(data_start + metadata_len)]) } CrateFlavor::Rmeta => { // mmap the file, because only a small fraction of it is read. diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 4b406496337..ebfd3c09fc1 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1317,9 +1317,7 @@ impl<'a> CrateMetadataRef<'a> { } fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem { - let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() - || self.root.tables.is_effects_desugaring.get(self, id) - { + let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() { kw::Empty } else { self.item_name(id) @@ -1342,7 +1340,6 @@ impl<'a> CrateMetadataRef<'a> { container, fn_has_self_parameter: has_self, opt_rpitit_info, - is_effects_desugaring: self.root.tables.is_effects_desugaring.get(self, id), } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 926eb4f6210..f06f2fdc5e5 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -316,10 +316,7 @@ provide! { tcx, def_id, other, cdata, }) .unwrap_or_default() } - is_type_alias_impl_trait => { - debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy); - cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index) - } + opaque_ty_origin => { table } assumed_wf_types_for_rpitit => { table } collect_return_position_impl_trait_in_trait_tys => { Ok(cdata diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 47f7a8b7c20..7277039bb7d 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -278,7 +278,7 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData { let source_map = s.tcx.sess.source_map(); let source_file_index = source_map.lookup_source_file_idx(self.lo); s.source_file_cache = - (source_map.files()[source_file_index].clone(), source_file_index); + (Lrc::clone(&source_map.files()[source_file_index]), source_file_index); } let (ref source_file, source_file_index) = s.source_file_cache; debug_assert!(source_file.contains(self.lo)); @@ -1188,7 +1188,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::SyntheticCoroutineBody => true, DefKind::OpaqueTy => { - let origin = tcx.opaque_type_origin(def_id); + let origin = tcx.local_opaque_ty_origin(def_id); if let hir::OpaqueTyOrigin::FnReturn { parent, .. } | hir::OpaqueTyOrigin::AsyncFn { parent, .. } = origin && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(parent) @@ -1530,9 +1530,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let DefKind::OpaqueTy = def_kind { self.encode_explicit_item_bounds(def_id); self.encode_explicit_item_super_predicates(def_id); - self.tables - .is_type_alias_impl_trait - .set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id)); + record!(self.tables.opaque_ty_origin[def_id] <- self.tcx.opaque_ty_origin(def_id)); self.encode_precise_capturing_args(def_id); } if tcx.impl_method_has_trait_impl_trait_tys(def_id) @@ -1677,9 +1675,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_precise_capturing_args(def_id); } } - if item.is_effects_desugaring { - self.tables.is_effects_desugaring.set(def_id.index, true); - } } fn encode_precise_capturing_args(&mut self, def_id: DefId) { @@ -2275,7 +2270,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { encoder.emit_raw_bytes(&0u64.to_le_bytes()); let source_map_files = tcx.sess.source_map().files(); - let source_file_cache = (source_map_files[0].clone(), 0); + let source_file_cache = (Lrc::clone(&source_map_files[0]), 0); let required_source_files = Some(FxIndexSet::default()); drop(source_map_files); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a00ca27aacc..ab878760c00 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -6,6 +6,7 @@ use decoder::{DecodeContext, Metadata}; use def_path_hash_map::DefPathHashMapRef; use encoder::EncodeContext; pub use encoder::{EncodedMetadata, encode_metadata, rendered_const}; +use rustc_abi::{FieldIdx, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; @@ -37,7 +38,6 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span}; -use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::spec::{PanicStrategy, TargetTriple}; use table::TableBuilder; use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir}; @@ -378,7 +378,6 @@ define_tables! { - defaulted: intrinsic: Table<DefIndex, Option<LazyValue<ty::IntrinsicDef>>>, is_macro_rules: Table<DefIndex, bool>, - is_type_alias_impl_trait: Table<DefIndex, bool>, type_alias_is_lazy: Table<DefIndex, bool>, attr_flags: Table<DefIndex, AttrFlags>, // The u64 is the crate-local part of the DefPathHash. All hashes in this crate have the same @@ -396,7 +395,6 @@ define_tables! { inherent_impls: Table<DefIndex, LazyArray<DefIndex>>, associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>, opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>, - is_effects_desugaring: Table<DefIndex, bool>, unused_generic_params: Table<DefIndex, UnusedGenericParams>, // Reexported names are not associated with individual `DefId`s, // e.g. a glob import can introduce a lot of names, all with the same `DefId`. @@ -469,6 +467,7 @@ define_tables! { doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>, doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>, assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>, + opaque_ty_origin: Table<DefIndex, LazyValue<hir::OpaqueTyOrigin<DefId>>>, } #[derive(TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs index 615a7402139..c241c06fce4 100644 --- a/compiler/rustc_middle/src/middle/debugger_visualizer.rs +++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs @@ -32,7 +32,7 @@ impl DebuggerVisualizerFile { pub fn path_erased(&self) -> Self { DebuggerVisualizerFile { - src: self.src.clone(), + src: Lrc::clone(&self.src), visualizer_type: self.visualizer_type, path: None, } diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index 13e35cd0909..111ac990bc7 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -3,7 +3,7 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::ItemLocalId; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable}; use crate::ty; @@ -54,4 +54,6 @@ pub struct ResolveBoundVars { pub defs: SortedMap<ItemLocalId, ResolvedArg>, pub late_bound_vars: SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>>, + + pub opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>, } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index cd148aef29b..978abab8b08 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -39,7 +39,7 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths}; use crate::ty::visit::TypeVisitableExt; use crate::ty::{ - self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, + self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingMode, UserTypeAnnotationIndex, }; @@ -452,6 +452,15 @@ impl<'tcx> Body<'tcx> { self.basic_blocks.as_mut() } + pub fn typing_mode(&self, _tcx: TyCtxt<'tcx>) -> TypingMode<'tcx> { + match self.phase { + // FIXME(#132279): the MIR is quite clearly inside of a body, so we + // should instead reveal opaques defined by that body here. + MirPhase::Built | MirPhase::Analysis(_) => TypingMode::non_body_analysis(), + MirPhase::Runtime(_) => TypingMode::PostAnalysis, + } + } + #[inline] pub fn local_kind(&self, local: Local) -> LocalKind { let index = local.as_usize(); diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index c610fac80f6..85beb6ef1e7 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -19,9 +19,8 @@ use smallvec::SmallVec; use super::{BasicBlock, Const, Local, UserTypeProjection}; use crate::mir::coverage::CoverageKind; -use crate::traits::Reveal; use crate::ty::adjustment::PointerCoercion; -use crate::ty::{self, GenericArgsRef, List, Region, Ty, UserTypeAnnotationIndex}; +use crate::ty::{self, GenericArgsRef, List, Region, Ty, TyCtxt, UserTypeAnnotationIndex}; /// Represents the "flavors" of MIR. /// @@ -102,10 +101,10 @@ impl MirPhase { } } - pub fn reveal(&self) -> Reveal { - match *self { - MirPhase::Built | MirPhase::Analysis(_) => Reveal::UserFacing, - MirPhase::Runtime(_) => Reveal::All, + pub fn param_env<'tcx>(&self, tcx: TyCtxt<'tcx>, body_def_id: DefId) -> ty::ParamEnv<'tcx> { + match self { + MirPhase::Built | MirPhase::Analysis(_) => tcx.param_env(body_def_id), + MirPhase::Runtime(_) => tcx.param_env_reveal_all_normalized(body_def_id), } } } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 5f8427bd707..8cfc7f1e33e 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -280,6 +280,7 @@ trivial! { rustc_hir::IsAsync, rustc_hir::ItemLocalId, rustc_hir::LangItem, + rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>, rustc_hir::OwnerId, rustc_hir::Upvar, rustc_index::bit_set::FiniteBitSet<u32>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d7a60a843b7..088b5d4ec96 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -260,11 +260,10 @@ rustc_queries! { separate_provide_extern } - query is_type_alias_impl_trait(key: DefId) -> bool + query opaque_ty_origin(key: DefId) -> hir::OpaqueTyOrigin<DefId> { - desc { "determine whether the opaque is a type-alias impl trait" } + desc { "determine where the opaque originates from" } separate_provide_extern - feedable } query unsizing_params_for_adt(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32> @@ -1781,6 +1780,23 @@ rustc_queries! { -> &'tcx SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>> { desc { |tcx| "looking up late bound vars inside `{}`", tcx.def_path_str(owner_id) } } + /// For an opaque type, return the list of (captured lifetime, inner generic param). + /// ```ignore (illustrative) + /// fn foo<'a: 'a, 'b, T>(&'b u8) -> impl Into<Self> + 'b { ... } + /// ``` + /// + /// We would return `[('a, '_a), ('b, '_b)]`, with `'a` early-bound and `'b` late-bound. + /// + /// After hir_ty_lowering, we get: + /// ```ignore (pseudo-code) + /// opaque foo::<'a>::opaque<'_a, '_b>: Into<Foo<'_a>> + '_b; + /// ^^^^^^^^ inner generic params + /// fn foo<'a>: for<'b> fn(&'b u8) -> foo::<'a>::opaque::<'a, 'b> + /// ^^^^^^ captured lifetimes + /// ``` + query opaque_captured_lifetimes(def_id: LocalDefId) -> &'tcx [(ResolvedArg, LocalDefId)] { + desc { |tcx| "listing captured lifetimes for opaque `{}`", tcx.def_path_str(def_id) } + } /// Computes the visibility of the provided `def_id`. /// diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 35a16684615..8b77a4a81ca 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -472,32 +472,27 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { let CacheDecoder { tcx, file_index_to_file, file_index_to_stable_id, source_map, .. } = *self; - file_index_to_file - .borrow_mut() - .entry(index) - .or_insert_with(|| { - let source_file_id = &file_index_to_stable_id[&index]; - let source_file_cnum = - tcx.stable_crate_id_to_crate_num(source_file_id.stable_crate_id); - - // If this `SourceFile` is from a foreign crate, then make sure - // that we've imported all of the source files from that crate. - // This has usually already been done during macro invocation. - // However, when encoding query results like `TypeckResults`, - // we might encode an `AdtDef` for a foreign type (because it - // was referenced in the body of the function). There is no guarantee - // that we will load the source files from that crate during macro - // expansion, so we use `import_source_files` to ensure that the foreign - // source files are actually imported before we call `source_file_by_stable_id`. - if source_file_cnum != LOCAL_CRATE { - self.tcx.import_source_files(source_file_cnum); - } + Lrc::clone(file_index_to_file.borrow_mut().entry(index).or_insert_with(|| { + let source_file_id = &file_index_to_stable_id[&index]; + let source_file_cnum = tcx.stable_crate_id_to_crate_num(source_file_id.stable_crate_id); + + // If this `SourceFile` is from a foreign crate, then make sure + // that we've imported all of the source files from that crate. + // This has usually already been done during macro invocation. + // However, when encoding query results like `TypeckResults`, + // we might encode an `AdtDef` for a foreign type (because it + // was referenced in the body of the function). There is no guarantee + // that we will load the source files from that crate during macro + // expansion, so we use `import_source_files` to ensure that the foreign + // source files are actually imported before we call `source_file_by_stable_id`. + if source_file_cnum != LOCAL_CRATE { + self.tcx.import_source_files(source_file_cnum); + } - source_map - .source_file_by_stable_id(source_file_id.stable_source_file_id) - .expect("failed to lookup `SourceFile` in new context") - }) - .clone() + source_map + .source_file_by_stable_id(source_file_id.stable_source_file_id) + .expect("failed to lookup `SourceFile` in new context") + })) } } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 564d274bc8b..57da5b39ba7 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -323,7 +323,7 @@ macro_rules! define_callbacks { // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(target_pointer_width = "64")] const _: () = { - if mem::size_of::<Key<'static>>() > 72 { + if mem::size_of::<Key<'static>>() > 80 { panic!("{}", concat!( "the query `", stringify!($name), diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 71833eea5c0..c56038d358c 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -82,7 +82,7 @@ pub enum PointerCoercion { /// `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`. #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct Adjustment<'tcx> { - pub kind: Adjust<'tcx>, + pub kind: Adjust, pub target: Ty<'tcx>, } @@ -93,20 +93,20 @@ impl<'tcx> Adjustment<'tcx> { } #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] -pub enum Adjust<'tcx> { +pub enum Adjust { /// Go from ! to any type. NeverToAny, /// Dereference once, producing a place. - Deref(Option<OverloadedDeref<'tcx>>), + Deref(Option<OverloadedDeref>), /// Take the address and produce either a `&` or `*` pointer. - Borrow(AutoBorrow<'tcx>), + Borrow(AutoBorrow), Pointer(PointerCoercion), /// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`. - ReborrowPin(ty::Region<'tcx>, hir::Mutability), + ReborrowPin(hir::Mutability), } /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` @@ -115,17 +115,16 @@ pub enum Adjust<'tcx> { /// being those shared by both the receiver and the returned reference. #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] #[derive(TypeFoldable, TypeVisitable)] -pub struct OverloadedDeref<'tcx> { - pub region: ty::Region<'tcx>, +pub struct OverloadedDeref { pub mutbl: hir::Mutability, /// The `Span` associated with the field access or method call /// that triggered this overloaded deref. pub span: Span, } -impl<'tcx> OverloadedDeref<'tcx> { +impl OverloadedDeref { /// Get the zst function item type for this method call. - pub fn method_call(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> Ty<'tcx> { + pub fn method_call<'tcx>(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> Ty<'tcx> { let trait_def_id = match self.mutbl { hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None), hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None), @@ -187,9 +186,9 @@ impl From<AutoBorrowMutability> for hir::Mutability { #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] #[derive(TypeFoldable, TypeVisitable)] -pub enum AutoBorrow<'tcx> { +pub enum AutoBorrow { /// Converts from T to &T. - Ref(ty::Region<'tcx>, AutoBorrowMutability), + Ref(AutoBorrowMutability), /// Converts from T to *T. RawPtr(hir::Mutability), diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index db56e0016a2..3137fe9bd1d 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -34,8 +34,6 @@ pub struct AssocItem { /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` /// provides additional information about its source. pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>, - - pub is_effects_desugaring: bool, } impl AssocItem { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5ae9c589ec4..9abad6d1a68 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -54,9 +54,8 @@ use rustc_type_ir::TyKind::*; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::lang_items::TraitSolverLangItem; pub use rustc_type_ir::lift::Lift; -use rustc_type_ir::solve::SolverMode; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph}; -use tracing::{debug, trace}; +use tracing::{debug, instrument}; use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; @@ -77,8 +76,8 @@ use crate::traits::solve::{ }; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericArg, GenericArgs, - GenericArgsRef, GenericParamDefKind, HostPolarity, ImplPolarity, List, ListWithCachedTypeInfo, + self, AdtDef, AdtDefData, AdtKind, Binder, BoundConstness, Clause, Clauses, Const, GenericArg, + GenericArgs, GenericArgsRef, GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, Visibility, @@ -170,15 +169,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { tracked.get(self) } - fn with_global_cache<R>( - self, - mode: SolverMode, - f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R, - ) -> R { - match mode { - SolverMode::Normal => f(&mut *self.new_solver_evaluation_cache.lock()), - SolverMode::Coherence => f(&mut *self.new_solver_coherence_evaluation_cache.lock()), - } + fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R { + f(&mut *self.new_solver_evaluation_cache.lock()) } fn evaluation_is_concurrent(&self) -> bool { @@ -629,6 +621,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) -> ty::Binder<'tcx, T> { self.anonymize_bound_vars(binder) } + + fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::DefiningOpaqueTypes { + self.opaque_types_defined_by(defining_anchor) + } } macro_rules! bidirectional_lang_item_map { @@ -1334,7 +1330,6 @@ pub struct GlobalCtxt<'tcx> { /// Caches the results of goal evaluation in the new solver. pub new_solver_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>, - pub new_solver_coherence_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>, pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>, @@ -1561,7 +1556,6 @@ impl<'tcx> TyCtxt<'tcx> { selection_cache: Default::default(), evaluation_cache: Default::default(), new_solver_evaluation_cache: Default::default(), - new_solver_coherence_evaluation_cache: Default::default(), canonical_param_env_cache: Default::default(), data_layout, alloc_map: Lock::new(interpret::AllocMap::new()), @@ -2109,11 +2103,9 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns the origin of the opaque type `def_id`. - #[track_caller] - pub fn opaque_type_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin { - let origin = self.hir().expect_opaque_ty(def_id).origin; - trace!("opaque_type_origin({def_id:?}) => {origin:?}"); - origin + #[instrument(skip(self), level = "trace", ret)] + pub fn local_opaque_ty_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin<LocalDefId> { + self.hir().expect_opaque_ty(def_id).origin } } @@ -2211,7 +2203,7 @@ macro_rules! nop_slice_lift { nop_slice_lift! {ty::ValTree<'a> => ty::ValTree<'tcx>} TrivialLiftImpls! { - ImplPolarity, PredicatePolarity, Promoted, HostPolarity, + ImplPolarity, PredicatePolarity, Promoted, BoundConstness, } macro_rules! sty_debug_print { @@ -3066,7 +3058,7 @@ impl<'tcx> TyCtxt<'tcx> { loop { let parent = self.local_parent(opaque_lifetime_param_def_id); - let hir::OpaqueTy { lifetime_mapping, .. } = self.hir().expect_opaque_ty(parent); + let lifetime_mapping = self.opaque_captured_lifetimes(parent); let Some((lifetime, _)) = lifetime_mapping .iter() @@ -3075,8 +3067,8 @@ impl<'tcx> TyCtxt<'tcx> { bug!("duplicated lifetime param should be present"); }; - match self.named_bound_var(lifetime.hir_id) { - Some(resolve_bound_vars::ResolvedArg::EarlyBound(ebv)) => { + match *lifetime { + resolve_bound_vars::ResolvedArg::EarlyBound(ebv) => { let new_parent = self.local_parent(ebv); // If we map to another opaque, then it should be a parent @@ -3095,7 +3087,7 @@ impl<'tcx> TyCtxt<'tcx> { name: self.item_name(ebv.to_def_id()), }); } - Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => { + resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv) => { let new_parent = self.local_parent(lbv); return ty::Region::new_late_param( self, @@ -3106,13 +3098,13 @@ impl<'tcx> TyCtxt<'tcx> { ), ); } - Some(resolve_bound_vars::ResolvedArg::Error(guar)) => { + resolve_bound_vars::ResolvedArg::Error(guar) => { return ty::Region::new_error(self, guar); } _ => { return ty::Region::new_error_with_message( self, - lifetime.ident.span, + self.def_span(opaque_lifetime_param_def_id), "cannot resolve lifetime", ); } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 704a197aa49..04d03187541 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -267,7 +267,7 @@ impl FlagComputation { } ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate { trait_ref, - host: _, + constness: _, })) => { self.add_args(trait_ref.args); } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 990fc37a1f3..0560ffe058a 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -4,8 +4,9 @@ use std::{cmp, fmt}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ - Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutData, - PointeeInfo, PointerKind, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, Variants, + AddressSpace, Align, BackendRepr, FieldsShape, HasDataLayout, Integer, LayoutCalculator, + LayoutData, PointeeInfo, PointerKind, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, + Variants, }; use rustc_error_messages::DiagMessage; use rustc_errors::{ @@ -346,7 +347,7 @@ impl<'tcx> SizeSkeleton<'tcx> { // First try computing a static layout. let err = match tcx.layout_of(param_env.and(ty)) { Ok(layout) => { - if layout.abi.is_sized() { + if layout.is_sized() { return Ok(SizeSkeleton::Known(layout.size, Some(layout.align.abi))); } else { // Just to be safe, don't claim a known layout for unsized types. @@ -757,7 +758,7 @@ where Some(fields) => FieldsShape::Union(fields), None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() }, }, - abi: Abi::Uninhabited, + backend_repr: BackendRepr::Uninhabited, largest_niche: None, align: tcx.data_layout.i8_align, size: Size::ZERO, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b92fc864b49..dac81a6dfbb 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -100,7 +100,7 @@ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst, - ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, + ParamTy, PolyFnSig, TyKind, TypeAndMut, TypingMode, UpvarArgs, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ @@ -1625,16 +1625,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Whether the `def_id` is an associated type that was desugared from a - /// `#[const_trait]` or `impl_const`. - pub fn is_effects_desugared_assoc_ty(self, def_id: DefId) -> bool { - if let DefKind::AssocTy = self.def_kind(def_id) { - self.associated_item(def_id).is_effects_desugaring - } else { - false - } - } - pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<FieldIdx> { variant.fields.iter_enumerated().find_map(|(i, field)| { self.hygienic_eq(ident, field.ident(self), variant.def_id).then_some(i) diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 43bdce5b576..7c280bc8b49 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -94,6 +94,7 @@ trivially_parameterized_over_tcx! { rustc_hir::def_id::DefId, rustc_hir::def_id::DefIndex, rustc_hir::definitions::DefKey, + rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>, rustc_index::bit_set::BitSet<u32>, rustc_index::bit_set::FiniteBitSet<u32>, rustc_session::cstore::ForeignModule, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 0248aad53e2..2480cee3dc4 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1959,7 +1959,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::BoundConstness::Const => { p!("const "); } - ty::BoundConstness::ConstIfConst => { + ty::BoundConstness::Maybe => { p!("~const "); } } @@ -3076,9 +3076,9 @@ define_print! { } ty::HostEffectPredicate<'tcx> { - let constness = match self.host { - ty::HostPolarity::Const => { "const" } - ty::HostPolarity::Maybe => { "~const" } + let constness = match self.constness { + ty::BoundConstness::Const => { "const" } + ty::BoundConstness::Maybe => { "~const" } }; p!(print(self.trait_ref.self_ty()), ": {constness} "); p!(print(self.trait_ref.print_trait_sugared())) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d8362ccc0a9..f54afdbc929 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -40,6 +40,7 @@ pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>; pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>; pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>; pub type EarlyBinder<'tcx, T> = ir::EarlyBinder<TyCtxt<'tcx>, T>; +pub type TypingMode<'tcx> = ir::TypingMode<TyCtxt<'tcx>>; pub trait Article { fn article(&self) -> &'static str; @@ -1353,6 +1354,7 @@ impl<'tcx> Ty<'tcx> { } } + #[tracing::instrument(level = "trace", skip(tcx))] pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { match self.kind() { FnDef(def_id, args) => tcx.fn_sig(*def_id).instantiate(tcx, args), diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 529e9cc2711..11904722743 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" # tidy-alphabetical-start either = "1.5.0" itertools = "0.12" + +rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } @@ -22,7 +24,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_pattern_analysis = { path = "../rustc_pattern_analysis" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 9e3af891052..07964e304b9 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -1,3 +1,4 @@ +use rustc_abi::{FieldIdx, VariantIdx}; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::*; @@ -6,7 +7,6 @@ use rustc_middle::ty; use rustc_middle::ty::cast::mir_cast_kind; use rustc_span::Span; use rustc_span::source_map::Spanned; -use rustc_target::abi::{FieldIdx, VariantIdx}; use super::{PResult, ParseCtxt, parse_by_kind}; use crate::build::custom::ParseError; diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index ae164cf7605..3f2e3b956fc 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -1,5 +1,6 @@ //! See docs in build/expr/mod.rs +use rustc_abi::Size; use rustc_ast as ast; use rustc_hir::LangItem; use rustc_middle::mir::interpret::{ @@ -11,7 +12,6 @@ use rustc_middle::ty::{ self, CanonicalUserType, CanonicalUserTypeAnnotation, Ty, TyCtxt, UserTypeAnnotationIndex, }; use rustc_middle::{bug, mir, span_bug}; -use rustc_target::abi::Size; use tracing::{instrument, trace}; use crate::build::{Builder, parse_float_into_constval}; diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index c7298e3ddfa..9f6e0735b48 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -3,6 +3,7 @@ use std::assert_matches::assert_matches; use std::iter; +use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use rustc_hir::def_id::LocalDefId; use rustc_middle::hir::place::{Projection as HirProjection, ProjectionKind as HirProjectionKind}; use rustc_middle::middle::region; @@ -12,7 +13,6 @@ use rustc_middle::thir::*; use rustc_middle::ty::{self, AdtDef, CanonicalUserTypeAnnotation, Ty, Variance}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; -use rustc_target::abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use tracing::{debug, instrument, trace}; use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index fd949a53384..1985dd3fca0 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -1,5 +1,6 @@ //! See docs in `build/expr/mod.rs`. +use rustc_abi::{BackendRepr, FieldIdx, Primitive}; use rustc_hir::lang_items::LangItem; use rustc_index::{Idx, IndexVec}; use rustc_middle::bug; @@ -13,7 +14,6 @@ use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, Ty, UpvarArgs}; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span}; -use rustc_target::abi::{Abi, FieldIdx, Primitive}; use tracing::debug; use crate::build::expr::as_place::PlaceBase; @@ -207,7 +207,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); let (op, ty) = (Operand::Move(discr), discr_ty); - if let Abi::Scalar(scalar) = layout.unwrap().abi + if let BackendRepr::Scalar(scalar) = layout.unwrap().backend_repr && !scalar.is_always_valid(&this.tcx) && let Primitive::Int(int_width, _signed) = scalar.primitive() { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 51ead570205..a62d4e9d873 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -5,6 +5,7 @@ //! This also includes code for pattern bindings in `let` statements and //! function parameters. +use rustc_abi::VariantIdx; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::{BindingMode, ByRef}; @@ -15,7 +16,6 @@ use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Pos, Span}; -use rustc_target::abi::VariantIdx; use tracing::{debug, instrument}; use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 8c20d2e0d3a..1f853f6e1c3 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1,4 +1,5 @@ use itertools::Itertools; +use rustc_abi::{ExternAbi, FieldIdx}; use rustc_apfloat::Float; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_ast::attr; @@ -16,12 +17,10 @@ use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::query::TyCtxtAt; use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir}; -use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; -use rustc_target::abi::FieldIdx; -use rustc_target::spec::abi::Abi; use super::lints; use crate::build::expr::as_place::PlaceBuilder; @@ -467,7 +466,7 @@ fn construct_fn<'tcx>( if let DefKind::Closure = tcx.def_kind(fn_def) { // HACK(eddyb) Avoid having RustCall on closures, // as it adds unnecessary (and wrong) auto-tupling. - abi = Abi::Rust; + abi = ExternAbi::Rust; } let arguments = &thir.params; @@ -500,7 +499,9 @@ fn construct_fn<'tcx>( ); } - let infcx = tcx.infer_ctxt().build(); + // FIXME(#132279): This should be able to reveal opaque + // types defined during HIR typeck. + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut builder = Builder::new( thir, infcx, @@ -538,7 +539,7 @@ fn construct_fn<'tcx>( let mut body = builder.finish(); - body.spread_arg = if abi == Abi::RustCall { + body.spread_arg = if abi == ExternAbi::RustCall { // RustCall pseudo-ABI untuples the last argument. Some(Local::new(arguments.len())) } else { @@ -578,7 +579,9 @@ fn construct_const<'a, 'tcx>( _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def), }; - let infcx = tcx.infer_ctxt().build(); + // FIXME(#132279): We likely want to be able to use the hidden types of + // opaques used by this function here. + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut builder = Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index e2823456477..0481f715019 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,4 +1,5 @@ use itertools::Itertools; +use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -18,7 +19,6 @@ use rustc_middle::ty::{ }; use rustc_middle::{bug, span_bug}; use rustc_span::{Span, sym}; -use rustc_target::abi::{FIRST_VARIANT, FieldIdx}; use tracing::{debug, info, instrument, trace}; use crate::errors; @@ -140,7 +140,7 @@ impl<'tcx> Cx<'tcx> { expr = Expr { temp_lifetime, - ty: Ty::new_ref(self.tcx, deref.region, expr.ty, deref.mutbl), + ty: Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, expr.ty, deref.mutbl), span, kind: ExprKind::Borrow { borrow_kind: deref.mutbl.to_borrow_kind(), @@ -152,14 +152,14 @@ impl<'tcx> Cx<'tcx> { self.overloaded_place(hir_expr, adjustment.target, Some(call), expr, deref.span) } - Adjust::Borrow(AutoBorrow::Ref(_, m)) => ExprKind::Borrow { + Adjust::Borrow(AutoBorrow::Ref(m)) => ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: self.thir.exprs.push(expr), }, Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => { ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) } } - Adjust::ReborrowPin(region, mutbl) => { + Adjust::ReborrowPin(mutbl) => { debug!("apply ReborrowPin adjustment"); // Rewrite `$expr` as `Pin { __pointer: &(mut)? *($expr).__pointer }` @@ -197,7 +197,8 @@ impl<'tcx> Cx<'tcx> { hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, hir::Mutability::Not => BorrowKind::Shared, }; - let new_pin_target = Ty::new_ref(self.tcx, region, ptr_target_ty, mutbl); + let new_pin_target = + Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, ptr_target_ty, mutbl); let expr = self.thir.exprs.push(Expr { temp_lifetime, ty: new_pin_target, @@ -784,7 +785,7 @@ impl<'tcx> Cx<'tcx> { if_then_scope: region::Scope { id: then.hir_id.local_id, data: { - if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope() { + if expr.span.at_least_rust_2024() { region::ScopeData::IfThenRescope } else { region::ScopeData::IfThen 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 8498df59ce6..f222a869c03 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -79,6 +79,8 @@ enum LetSource { IfLetGuard, LetElse, WhileLet, + Else, + ElseIfLet, } struct MatchVisitor<'p, 'tcx> { @@ -129,15 +131,20 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { // Give a specific `let_source` for the condition. let let_source = match ex.span.desugaring_kind() { Some(DesugaringKind::WhileLoop) => LetSource::WhileLet, - _ => LetSource::IfLet, + _ => match self.let_source { + LetSource::Else => LetSource::ElseIfLet, + _ => LetSource::IfLet, + }, }; self.with_let_source(let_source, |this| this.visit_expr(&self.thir[cond])); self.with_let_source(LetSource::None, |this| { this.visit_expr(&this.thir[then]); - if let Some(else_) = else_opt { - this.visit_expr(&this.thir[else_]); - } }); + if let Some(else_) = else_opt { + self.with_let_source(LetSource::Else, |this| { + this.visit_expr(&this.thir[else_]) + }); + } return; } ExprKind::Match { scrutinee, scrutinee_hir_id: _, box ref arms, match_source } => { @@ -573,9 +580,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { // and we shouldn't lint. // For let guards inside a match, prefixes might use bindings of the match pattern, // so can't always be moved out. + // For `else if let`, an extra indentation level would be required to move the bindings. // FIXME: Add checking whether the bindings are actually used in the prefix, // and lint if they are not. - if !matches!(self.let_source, LetSource::WhileLet | LetSource::IfLetGuard) { + if !matches!( + self.let_source, + LetSource::WhileLet | LetSource::IfLetGuard | LetSource::ElseIfLet + ) { // Emit the lint let prefix = &chain_refutabilities[..until]; let span_start = prefix[0].unwrap().0; @@ -906,8 +917,8 @@ fn report_irrefutable_let_patterns( } match source { - LetSource::None | LetSource::PlainLet => bug!(), - LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet), + LetSource::None | LetSource::PlainLet | LetSource::Else => bug!(), + LetSource::IfLet | LetSource::ElseIfLet => emit_diag!(IrrefutableLetPatternsIfLet), LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard), LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse), LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet), diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 0dfa9168f7c..983853d2de1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -1,4 +1,5 @@ use either::Either; +use rustc_abi::{FieldIdx, VariantIdx}; use rustc_apfloat::Float; use rustc_hir as hir; use rustc_index::Idx; @@ -7,9 +8,8 @@ use rustc_infer::traits::Obligation; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir::{FieldPat, Pat, PatKind}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree}; use rustc_span::Span; -use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_trait_selection::traits::ObligationCause; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use tracing::{debug, instrument, trace}; @@ -36,7 +36,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { id: hir::HirId, span: Span, ) -> Box<Pat<'tcx>> { - let infcx = self.tcx.infer_ctxt().build(); + // FIXME(#132279): We likely want to be able to reveal the hidden types + // of opaques defined in this function here. + let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut convert = ConstToPat::new(self, id, span, infcx); convert.to_pat(c, ty) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 56e5156a91f..ec852add94d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -5,6 +5,7 @@ mod const_to_pat; use std::cmp::Ordering; +use rustc_abi::{FieldIdx, Integer}; use rustc_errors::codes::*; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; @@ -20,7 +21,6 @@ use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisita use rustc_middle::{bug, span_bug}; use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_target::abi::{FieldIdx, Integer}; use tracing::{debug, instrument}; pub(crate) use self::check_match::check_match; diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index 7199db677c4..62a69b3464f 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start polonius-engine = "0.13.0" regex = "1" +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs index bb53eaf6cbd..e5cddd0e5e4 100644 --- a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs +++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs @@ -1,5 +1,5 @@ +use rustc_abi::VariantIdx; use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind}; -use rustc_target::abi::VariantIdx; use tracing::debug; use super::move_paths::{InitKind, LookupResult, MoveData, MovePathIndex}; diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 7f2a07e2f5e..9a1f000d39d 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -1,5 +1,6 @@ use std::{fmt, iter}; +use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use rustc_hir::lang_items::LangItem; use rustc_index::Idx; use rustc_middle::mir::patch::MirPatch; @@ -10,7 +11,6 @@ use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_span::source_map::Spanned; -use rustc_target::abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use tracing::{debug, instrument}; /// The value of an inserted drop flag. diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 96a70f4fa5b..bac75b972f9 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -32,8 +32,11 @@ pub(crate) struct Formatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { - body: &'mir Body<'tcx>, - results: RefCell<Option<Results<'tcx, A>>>, + // The `RefCell` is used because `<Formatter as Labeller>::node_label` + // takes `&self`, but it needs to modify the cursor. This is also the + // reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has + // the operations that involve the mutation, i.e. within the `borrow_mut`. + cursor: RefCell<ResultsCursor<'mir, 'tcx, A>>, style: OutputStyle, reachable: BitSet<BasicBlock>, } @@ -48,11 +51,15 @@ where style: OutputStyle, ) -> Self { let reachable = mir::traversal::reachable_as_bitset(body); - Formatter { body, results: Some(results).into(), style, reachable } + Formatter { cursor: results.into_results_cursor(body).into(), style, reachable } + } + + fn body(&self) -> &'mir Body<'tcx> { + self.cursor.borrow().body() } pub(crate) fn into_results(self) -> Results<'tcx, A> { - self.results.into_inner().unwrap() + self.cursor.into_inner().into_results() } } @@ -81,7 +88,7 @@ where type Edge = CfgEdge; fn graph_id(&self) -> dot::Id<'_> { - let name = graphviz_safe_def_name(self.body.source.def_id()); + let name = graphviz_safe_def_name(self.body().source.def_id()); dot::Id::new(format!("graph_for_def_id_{name}")).unwrap() } @@ -90,20 +97,11 @@ where } fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { - let mut label = Vec::new(); - self.results.replace_with(|results| { - // `Formatter::result` is a `RefCell<Option<_>>` so we can replace - // the value with `None`, move it into the results cursor, move it - // back out, and return it to the refcell wrapped in `Some`. - let mut fmt = BlockFormatter { - results: results.take().unwrap().into_results_cursor(self.body), - style: self.style, - bg: Background::Light, - }; + let mut cursor = self.cursor.borrow_mut(); + let mut fmt = + BlockFormatter { cursor: &mut cursor, style: self.style, bg: Background::Light }; + let label = fmt.write_node_label(*block).unwrap(); - fmt.write_node_label(&mut label, *block).unwrap(); - Some(fmt.results.into_results()) - }); dot::LabelText::html(String::from_utf8(label).unwrap()) } @@ -112,12 +110,12 @@ where } fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> { - let label = &self.body[e.source].terminator().kind.fmt_successor_labels()[e.index]; + let label = &self.body()[e.source].terminator().kind.fmt_successor_labels()[e.index]; dot::LabelText::label(label.clone()) } } -impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'mir, 'tcx, A> +impl<'tcx, A> dot::GraphWalk<'_> for Formatter<'_, 'tcx, A> where A: Analysis<'tcx>, { @@ -125,7 +123,7 @@ where type Edge = CfgEdge; fn nodes(&self) -> dot::Nodes<'_, Self::Node> { - self.body + self.body() .basic_blocks .indices() .filter(|&idx| self.reachable.contains(idx)) @@ -134,10 +132,10 @@ where } fn edges(&self) -> dot::Edges<'_, Self::Edge> { - self.body - .basic_blocks + let body = self.body(); + body.basic_blocks .indices() - .flat_map(|bb| dataflow_successors(self.body, bb)) + .flat_map(|bb| dataflow_successors(body, bb)) .collect::<Vec<_>>() .into() } @@ -147,20 +145,20 @@ where } fn target(&self, edge: &Self::Edge) -> Self::Node { - self.body[edge.source].terminator().successors().nth(edge.index).unwrap() + self.body()[edge.source].terminator().successors().nth(edge.index).unwrap() } } -struct BlockFormatter<'mir, 'tcx, A> +struct BlockFormatter<'a, 'mir, 'tcx, A> where A: Analysis<'tcx>, { - results: ResultsCursor<'mir, 'tcx, A>, + cursor: &'a mut ResultsCursor<'mir, 'tcx, A>, bg: Background, style: OutputStyle, } -impl<'mir, 'tcx, A> BlockFormatter<'mir, 'tcx, A> +impl<'tcx, A> BlockFormatter<'_, '_, 'tcx, A> where A: Analysis<'tcx>, A::Domain: DebugWithContext<A>, @@ -173,7 +171,9 @@ where bg } - fn write_node_label(&mut self, w: &mut impl io::Write, block: BasicBlock) -> io::Result<()> { + fn write_node_label(&mut self, block: BasicBlock) -> io::Result<Vec<u8>> { + use std::io::Write; + // Sample output: // +-+-----------------------------------------------+ // A | bb4 | @@ -200,6 +200,9 @@ where // attributes. Make sure to test the output before trying to remove the redundancy. // Notably, `align` was found to have no effect when applied only to <table>. + let mut v = vec![]; + let w = &mut v; + let table_fmt = concat!( " border=\"1\"", " cellborder=\"1\"", @@ -219,8 +222,8 @@ where // C: State at start of block self.bg = Background::Light; - self.results.seek_to_block_start(block); - let block_start_state = self.results.get().clone(); + self.cursor.seek_to_block_start(block); + let block_start_state = self.cursor.get().clone(); self.write_row_with_full_state(w, "", "(on start)")?; // D + E: Statement and terminator transfer functions @@ -228,12 +231,12 @@ where // F: State at end of block - let terminator = self.results.body()[block].terminator(); + let terminator = self.cursor.body()[block].terminator(); // Write the full dataflow state immediately after the terminator if it differs from the // state at block entry. - self.results.seek_to_block_end(block); - if self.results.get() != &block_start_state || A::Direction::IS_BACKWARD { + self.cursor.seek_to_block_end(block); + if self.cursor.get() != &block_start_state || A::Direction::IS_BACKWARD { let after_terminator_name = match terminator.kind { mir::TerminatorKind::Call { target: Some(_), .. } => "(on unwind)", _ => "(on end)", @@ -250,8 +253,8 @@ where match terminator.kind { mir::TerminatorKind::Call { destination, .. } => { self.write_row(w, "", "(on successful return)", |this, w, fmt| { - let state_on_unwind = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { + let state_on_unwind = this.cursor.get().clone(); + this.cursor.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, block, @@ -265,9 +268,9 @@ where colspan = this.style.num_state_columns(), fmt = fmt, diff = diff_pretty( - this.results.get(), + this.cursor.get(), &state_on_unwind, - this.results.analysis() + this.cursor.analysis() ), ) })?; @@ -275,8 +278,8 @@ where mir::TerminatorKind::Yield { resume, resume_arg, .. } => { self.write_row(w, "", "(on yield resume)", |this, w, fmt| { - let state_on_coroutine_drop = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { + let state_on_coroutine_drop = this.cursor.get().clone(); + this.cursor.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, resume, @@ -290,9 +293,9 @@ where colspan = this.style.num_state_columns(), fmt = fmt, diff = diff_pretty( - this.results.get(), + this.cursor.get(), &state_on_coroutine_drop, - this.results.analysis() + this.cursor.analysis() ), ) })?; @@ -302,8 +305,8 @@ where if !targets.is_empty() => { self.write_row(w, "", "(on successful return)", |this, w, fmt| { - let state_on_unwind = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { + let state_on_unwind = this.cursor.get().clone(); + this.cursor.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, block, @@ -317,9 +320,9 @@ where colspan = this.style.num_state_columns(), fmt = fmt, diff = diff_pretty( - this.results.get(), + this.cursor.get(), &state_on_unwind, - this.results.analysis() + this.cursor.analysis() ), ) })?; @@ -328,7 +331,9 @@ where _ => {} }; - write!(w, "</table>") + write!(w, "</table>")?; + + Ok(v) } fn write_block_header_simple( @@ -407,9 +412,9 @@ where block: BasicBlock, ) -> io::Result<()> { let diffs = StateDiffCollector::run( - self.results.body(), + self.cursor.body(), block, - self.results.mut_results(), + self.cursor.mut_results(), self.style, ); @@ -420,7 +425,7 @@ where if A::Direction::IS_FORWARD { it.next().unwrap() } else { it.next_back().unwrap() } }; - for (i, statement) in self.results.body()[block].statements.iter().enumerate() { + for (i, statement) in self.cursor.body()[block].statements.iter().enumerate() { let statement_str = format!("{statement:?}"); let index_str = format!("{i}"); @@ -442,7 +447,7 @@ where assert!(diffs_after.is_empty()); assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty)); - let terminator = self.results.body()[block].terminator(); + let terminator = self.cursor.body()[block].terminator(); let mut terminator_str = String::new(); terminator.kind.fmt_head(&mut terminator_str).unwrap(); @@ -492,8 +497,8 @@ where mir: &str, ) -> io::Result<()> { self.write_row(w, i, mir, |this, w, fmt| { - let state = this.results.get(); - let analysis = this.results.analysis(); + let state = this.cursor.get(); + let analysis = this.cursor.analysis(); // FIXME: The full state vector can be quite long. It would be nice to split on commas // and use some text wrapping algorithm. diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 959f1ea5340..8f81da8bb04 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -7,18 +7,17 @@ //! //! The `impls` module contains several examples of dataflow analyses. //! -//! Create an `Engine` for your analysis using the `into_engine` method on the `Analysis` trait, -//! then call `iterate_to_fixpoint`. From there, you can use a `ResultsCursor` to inspect the -//! fixpoint solution to your dataflow problem, or implement the `ResultsVisitor` interface and use -//! `visit_results`. The following example uses the `ResultsCursor` approach. +//! Then call `iterate_to_fixpoint` on your type that impls `Analysis` to get a `Results`. From +//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem, +//! or implement the `ResultsVisitor` interface and use `visit_results`. The following example uses +//! the `ResultsCursor` approach. //! //! ```ignore (cross-crate-imports) -//! use rustc_const_eval::dataflow::Analysis; // Makes `into_engine` available. +//! use rustc_const_eval::dataflow::Analysis; // Makes `iterate_to_fixpoint` available. //! //! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) { //! let analysis = MyAnalysis::new() -//! .into_engine(tcx, body) -//! .iterate_to_fixpoint() +//! .iterate_to_fixpoint(tcx, body, None) //! .into_results_cursor(body); //! //! // Print the dataflow state *after* each statement in the start block. @@ -34,23 +33,29 @@ use std::cmp::Ordering; -use rustc_index::Idx; +use rustc_data_structures::work_queue::WorkQueue; use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; -use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges}; +use rustc_index::{Idx, IndexVec}; +use rustc_middle::bug; +use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal}; use rustc_middle::ty::TyCtxt; +use tracing::error; + +use self::results::write_graphviz_results; +use super::fmt::DebugWithContext; mod cursor; mod direction; -mod engine; pub mod fmt; pub mod graphviz; pub mod lattice; +mod results; mod visitor; pub use self::cursor::ResultsCursor; pub use self::direction::{Backward, Direction, Forward}; -pub use self::engine::{Engine, Results}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; +pub use self::results::Results; pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results}; /// Analysis domains are all bitsets of various kinds. This trait holds @@ -223,26 +228,92 @@ pub trait Analysis<'tcx> { /* Extension methods */ - /// Creates an `Engine` to find the fixpoint for this dataflow problem. + /// Finds the fixpoint for this dataflow problem. /// /// You shouldn't need to override this. Its purpose is to enable method chaining like so: /// /// ```ignore (cross-crate-imports) /// let results = MyAnalysis::new(tcx, body) - /// .into_engine(tcx, body, def_id) - /// .iterate_to_fixpoint() + /// .iterate_to_fixpoint(tcx, body, None) /// .into_results_cursor(body); /// ``` - #[inline] - fn into_engine<'mir>( - self, + /// You can optionally add a `pass_name` to the graphviz output for this particular run of a + /// dataflow analysis. Some analyses are run multiple times in the compilation pipeline. + /// Without a `pass_name` to differentiates them, only the results for the latest run will be + /// saved. + fn iterate_to_fixpoint<'mir>( + mut self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, - ) -> Engine<'mir, 'tcx, Self> + pass_name: Option<&'static str>, + ) -> Results<'tcx, Self> where Self: Sized, + Self::Domain: DebugWithContext<Self>, { - Engine::new(tcx, body, self) + let mut entry_sets = + IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len()); + self.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); + + if Self::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != self.bottom_value(body) { + bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); + } + + let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len()); + + if Self::Direction::IS_FORWARD { + for (bb, _) in traversal::reverse_postorder(body) { + dirty_queue.insert(bb); + } + } else { + // Reverse post-order on the reverse CFG may generate a better iteration order for + // backward dataflow analyses, but probably not enough to matter. + for (bb, _) in traversal::postorder(body) { + dirty_queue.insert(bb); + } + } + + // `state` is not actually used between iterations; + // this is just an optimization to avoid reallocating + // every iteration. + let mut state = self.bottom_value(body); + while let Some(bb) = dirty_queue.pop() { + let bb_data = &body[bb]; + + // Set the state to the entry state of the block. + // This is equivalent to `state = entry_sets[bb].clone()`, + // but it saves an allocation, thus improving compile times. + state.clone_from(&entry_sets[bb]); + + // Apply the block transfer function, using the cached one if it exists. + let edges = Self::Direction::apply_effects_in_block(&mut self, &mut state, bb, bb_data); + + Self::Direction::join_state_into_successors_of( + &mut self, + body, + &mut state, + bb, + edges, + |target: BasicBlock, state: &Self::Domain| { + let set_changed = entry_sets[target].join(state); + if set_changed { + dirty_queue.insert(target); + } + }, + ); + } + + let results = Results { analysis: self, entry_sets }; + + if tcx.sess.opts.unstable_opts.dump_mir_dataflow { + let (res, results) = write_graphviz_results(tcx, body, results, pass_name); + if let Err(e) = res { + error!("Failed to write graphviz dataflow results: {}", e); + } + results + } else { + results + } } } diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs index cbd1083d037..366fcbf33ba 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/results.rs @@ -1,23 +1,19 @@ -//! A solver for dataflow problems. +//! Dataflow analysis results. use std::ffi::OsString; use std::path::PathBuf; -use rustc_data_structures::work_queue::WorkQueue; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; -use rustc_middle::bug; use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal}; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_span::symbol::{Symbol, sym}; -use tracing::{debug, error}; +use tracing::debug; use {rustc_ast as ast, rustc_graphviz as dot}; use super::fmt::DebugWithContext; -use super::{ - Analysis, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz, visit_results, -}; +use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results}; use crate::errors::{ DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter, }; @@ -65,124 +61,17 @@ where body: &'mir mir::Body<'tcx>, vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>, ) { - let blocks = mir::traversal::reachable(body); + let blocks = traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) } } -/// A solver for dataflow problems. -pub struct Engine<'mir, 'tcx, A> -where - A: Analysis<'tcx>, -{ - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - entry_sets: IndexVec<BasicBlock, A::Domain>, - pass_name: Option<&'static str>, - analysis: A, -} - -impl<'mir, 'tcx, A, D> Engine<'mir, 'tcx, A> -where - A: Analysis<'tcx, Domain = D>, - D: Clone + JoinSemiLattice, -{ - /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer - /// function. - pub(crate) fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, analysis: A) -> Self { - let mut entry_sets = - IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len()); - analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); - - if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != analysis.bottom_value(body) - { - bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); - } - - Engine { analysis, tcx, body, pass_name: None, entry_sets } - } - - /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis. - /// - /// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name` - /// to differentiate them. Otherwise, only the results for the latest run will be saved. - pub fn pass_name(mut self, name: &'static str) -> Self { - self.pass_name = Some(name); - self - } - - /// Computes the fixpoint for this dataflow problem and returns it. - pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> - where - A::Domain: DebugWithContext<A>, - { - let Engine { mut analysis, body, mut entry_sets, tcx, pass_name } = self; - - let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len()); - - if A::Direction::IS_FORWARD { - for (bb, _) in traversal::reverse_postorder(body) { - dirty_queue.insert(bb); - } - } else { - // Reverse post-order on the reverse CFG may generate a better iteration order for - // backward dataflow analyses, but probably not enough to matter. - for (bb, _) in traversal::postorder(body) { - dirty_queue.insert(bb); - } - } - - // `state` is not actually used between iterations; - // this is just an optimization to avoid reallocating - // every iteration. - let mut state = analysis.bottom_value(body); - while let Some(bb) = dirty_queue.pop() { - let bb_data = &body[bb]; - - // Set the state to the entry state of the block. - // This is equivalent to `state = entry_sets[bb].clone()`, - // but it saves an allocation, thus improving compile times. - state.clone_from(&entry_sets[bb]); - - // Apply the block transfer function, using the cached one if it exists. - let edges = - A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data); - - A::Direction::join_state_into_successors_of( - &mut analysis, - body, - &mut state, - bb, - edges, - |target: BasicBlock, state: &A::Domain| { - let set_changed = entry_sets[target].join(state); - if set_changed { - dirty_queue.insert(target); - } - }, - ); - } - - let results = Results { analysis, entry_sets }; - - if tcx.sess.opts.unstable_opts.dump_mir_dataflow { - let (res, results) = write_graphviz_results(tcx, body, results, pass_name); - if let Err(e) = res { - error!("Failed to write graphviz dataflow results: {}", e); - } - results - } else { - results - } - } -} - // Graphviz /// Writes a DOT file containing the results of a dataflow analysis if the user requested it via /// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are /// the same. -fn write_graphviz_results<'tcx, A>( +pub(super) fn write_graphviz_results<'tcx, A>( tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, results: Results<'tcx, A>, diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index b284f0308f9..b404e3bfb72 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -18,9 +18,9 @@ pub use self::drop_flag_effects::{ move_path_children_matching, on_all_children_bits, on_lookup_result_bits, }; pub use self::framework::{ - Analysis, Backward, Direction, Engine, Forward, GenKill, JoinSemiLattice, MaybeReachable, - Results, ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, - lattice, visit_results, + Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results, + ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice, + visit_results, }; use self::move_paths::MoveData; diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 5727517bd61..99d0ccde105 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -43,31 +43,28 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let move_data = MoveData::gather_moves(body, tcx, |_| true); if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() { - let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .iterate_to_fixpoint(); + let flow_inits = + MaybeInitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(tcx, body, None); sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body)); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() { let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .iterate_to_fixpoint(); + .iterate_to_fixpoint(tcx, body, None); sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body)); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() { - let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data) - .into_engine(tcx, body) - .iterate_to_fixpoint(); + let flow_def_inits = + DefinitelyInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(tcx, body, None); sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body)); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() { - let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint(); + let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None); sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body)); } diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index d0f62bd82d1..af2d514fc76 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -1,400 +1,20 @@ -//! This module provides a framework on top of the normal MIR dataflow framework to simplify the -//! implementation of analyses that track information about the values stored in certain places. -//! We are using the term "place" here to refer to a `mir::Place` (a place expression) instead of -//! an `interpret::Place` (a memory location). -//! -//! The default methods of [`ValueAnalysis`] (prefixed with `super_` instead of `handle_`) -//! provide some behavior that should be valid for all abstract domains that are based only on the -//! value stored in a certain place. On top of these default rules, an implementation should -//! override some of the `handle_` methods. For an example, see `ConstAnalysis`. -//! -//! An implementation must also provide a [`Map`]. Before the analysis begins, all places that -//! should be tracked during the analysis must be registered. During the analysis, no new places -//! can be registered. The [`State`] can be queried to retrieve the abstract value stored for a -//! certain place by passing the map. -//! -//! This framework is currently experimental. Originally, it supported shared references and enum -//! variants. However, it was discovered that both of these were unsound, and especially references -//! had subtle but serious issues. In the future, they could be added back in, but we should clarify -//! the rules for optimizations that rely on the aliasing model first. -//! -//! -//! # Notes -//! -//! - The bottom state denotes uninitialized memory. Because we are only doing a sound approximation -//! of the actual execution, we can also use this state for places where access would be UB. -//! -//! - The assignment logic in `State::insert_place_idx` assumes that the places are non-overlapping, -//! or identical. Note that this refers to place expressions, not memory locations. -//! -//! - Currently, places that have their reference taken cannot be tracked. Although this would be -//! possible, it has to rely on some aliasing model, which we are not ready to commit to yet. -//! Because of that, we can assume that the only way to change the value behind a tracked place is -//! by direct assignment. - -use std::assert_matches::assert_matches; use std::fmt::{Debug, Formatter}; use std::ops::Range; +use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; -use rustc_middle::bug; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_target::abi::{FieldIdx, VariantIdx}; use tracing::debug; -use crate::fmt::DebugWithContext; +use crate::JoinSemiLattice; use crate::lattice::{HasBottom, HasTop}; -use crate::{Analysis, JoinSemiLattice, SwitchIntEdgeEffects}; - -pub trait ValueAnalysis<'tcx> { - /// For each place of interest, the analysis tracks a value of the given type. - type Value: Clone + JoinSemiLattice + HasBottom + HasTop + Debug; - - const NAME: &'static str; - - fn map(&self) -> &Map<'tcx>; - - fn handle_statement(&self, statement: &Statement<'tcx>, state: &mut State<Self::Value>) { - self.super_statement(statement, state) - } - - fn super_statement(&self, statement: &Statement<'tcx>, state: &mut State<Self::Value>) { - match &statement.kind { - StatementKind::Assign(box (place, rvalue)) => { - self.handle_assign(*place, rvalue, state); - } - StatementKind::SetDiscriminant { box place, variant_index } => { - self.handle_set_discriminant(*place, *variant_index, state); - } - StatementKind::Intrinsic(box intrinsic) => { - self.handle_intrinsic(intrinsic, state); - } - StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { - // StorageLive leaves the local in an uninitialized state. - // StorageDead makes it UB to access the local afterwards. - state.flood_with(Place::from(*local).as_ref(), self.map(), Self::Value::BOTTOM); - } - StatementKind::Deinit(box place) => { - // Deinit makes the place uninitialized. - state.flood_with(place.as_ref(), self.map(), Self::Value::BOTTOM); - } - StatementKind::Retag(..) => { - // We don't track references. - } - StatementKind::ConstEvalCounter - | StatementKind::Nop - | StatementKind::FakeRead(..) - | StatementKind::PlaceMention(..) - | StatementKind::Coverage(..) - | StatementKind::AscribeUserType(..) => (), - } - } - - fn handle_set_discriminant( - &self, - place: Place<'tcx>, - variant_index: VariantIdx, - state: &mut State<Self::Value>, - ) { - self.super_set_discriminant(place, variant_index, state) - } - - fn super_set_discriminant( - &self, - place: Place<'tcx>, - _variant_index: VariantIdx, - state: &mut State<Self::Value>, - ) { - state.flood_discr(place.as_ref(), self.map()); - } - - fn handle_intrinsic( - &self, - intrinsic: &NonDivergingIntrinsic<'tcx>, - state: &mut State<Self::Value>, - ) { - self.super_intrinsic(intrinsic, state); - } - - fn super_intrinsic( - &self, - intrinsic: &NonDivergingIntrinsic<'tcx>, - _state: &mut State<Self::Value>, - ) { - match intrinsic { - NonDivergingIntrinsic::Assume(..) => { - // Could use this, but ignoring it is sound. - } - NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { - dst: _, - src: _, - count: _, - }) => { - // This statement represents `*dst = *src`, `count` times. - } - } - } - - fn handle_assign( - &self, - target: Place<'tcx>, - rvalue: &Rvalue<'tcx>, - state: &mut State<Self::Value>, - ) { - self.super_assign(target, rvalue, state) - } - - fn super_assign( - &self, - target: Place<'tcx>, - rvalue: &Rvalue<'tcx>, - state: &mut State<Self::Value>, - ) { - let result = self.handle_rvalue(rvalue, state); - state.assign(target.as_ref(), result, self.map()); - } - - fn handle_rvalue( - &self, - rvalue: &Rvalue<'tcx>, - state: &mut State<Self::Value>, - ) -> ValueOrPlace<Self::Value> { - self.super_rvalue(rvalue, state) - } - - fn super_rvalue( - &self, - rvalue: &Rvalue<'tcx>, - state: &mut State<Self::Value>, - ) -> ValueOrPlace<Self::Value> { - match rvalue { - Rvalue::Use(operand) => self.handle_operand(operand, state), - Rvalue::CopyForDeref(place) => self.handle_operand(&Operand::Copy(*place), state), - Rvalue::Ref(..) | Rvalue::RawPtr(..) => { - // We don't track such places. - ValueOrPlace::TOP - } - Rvalue::Repeat(..) - | Rvalue::ThreadLocalRef(..) - | Rvalue::Len(..) - | Rvalue::Cast(..) - | Rvalue::BinaryOp(..) - | Rvalue::NullaryOp(..) - | Rvalue::UnaryOp(..) - | Rvalue::Discriminant(..) - | Rvalue::Aggregate(..) - | Rvalue::ShallowInitBox(..) => { - // No modification is possible through these r-values. - ValueOrPlace::TOP - } - } - } - - fn handle_operand( - &self, - operand: &Operand<'tcx>, - state: &mut State<Self::Value>, - ) -> ValueOrPlace<Self::Value> { - self.super_operand(operand, state) - } - - fn super_operand( - &self, - operand: &Operand<'tcx>, - state: &mut State<Self::Value>, - ) -> ValueOrPlace<Self::Value> { - match operand { - Operand::Constant(box constant) => { - ValueOrPlace::Value(self.handle_constant(constant, state)) - } - Operand::Copy(place) | Operand::Move(place) => { - // On move, we would ideally flood the place with bottom. But with the current - // framework this is not possible (similar to `InterpCx::eval_operand`). - self.map() - .find(place.as_ref()) - .map(ValueOrPlace::Place) - .unwrap_or(ValueOrPlace::TOP) - } - } - } - - fn handle_constant( - &self, - constant: &ConstOperand<'tcx>, - state: &mut State<Self::Value>, - ) -> Self::Value { - self.super_constant(constant, state) - } - - fn super_constant( - &self, - _constant: &ConstOperand<'tcx>, - _state: &mut State<Self::Value>, - ) -> Self::Value { - Self::Value::TOP - } - - /// The effect of a successful function call return should not be - /// applied here, see [`Analysis::apply_terminator_effect`]. - fn handle_terminator<'mir>( - &self, - terminator: &'mir Terminator<'tcx>, - state: &mut State<Self::Value>, - ) -> TerminatorEdges<'mir, 'tcx> { - self.super_terminator(terminator, state) - } - - fn super_terminator<'mir>( - &self, - terminator: &'mir Terminator<'tcx>, - state: &mut State<Self::Value>, - ) -> TerminatorEdges<'mir, 'tcx> { - match &terminator.kind { - TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => { - // Effect is applied by `handle_call_return`. - } - TerminatorKind::Drop { place, .. } => { - state.flood_with(place.as_ref(), self.map(), Self::Value::BOTTOM); - } - TerminatorKind::Yield { .. } => { - // They would have an effect, but are not allowed in this phase. - bug!("encountered disallowed terminator"); - } - TerminatorKind::SwitchInt { discr, targets } => { - return self.handle_switch_int(discr, targets, state); - } - TerminatorKind::TailCall { .. } => { - // FIXME(explicit_tail_calls): determine if we need to do something here (probably not) - } - TerminatorKind::Goto { .. } - | TerminatorKind::UnwindResume - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::Assert { .. } - | TerminatorKind::CoroutineDrop - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => { - // These terminators have no effect on the analysis. - } - } - terminator.edges() - } - - fn handle_call_return( - &self, - return_places: CallReturnPlaces<'_, 'tcx>, - state: &mut State<Self::Value>, - ) { - self.super_call_return(return_places, state) - } - - fn super_call_return( - &self, - return_places: CallReturnPlaces<'_, 'tcx>, - state: &mut State<Self::Value>, - ) { - return_places.for_each(|place| { - state.flood(place.as_ref(), self.map()); - }) - } - - fn handle_switch_int<'mir>( - &self, - discr: &'mir Operand<'tcx>, - targets: &'mir SwitchTargets, - state: &mut State<Self::Value>, - ) -> TerminatorEdges<'mir, 'tcx> { - self.super_switch_int(discr, targets, state) - } - - fn super_switch_int<'mir>( - &self, - discr: &'mir Operand<'tcx>, - targets: &'mir SwitchTargets, - _state: &mut State<Self::Value>, - ) -> TerminatorEdges<'mir, 'tcx> { - TerminatorEdges::SwitchInt { discr, targets } - } - - fn wrap(self) -> ValueAnalysisWrapper<Self> - where - Self: Sized, - { - ValueAnalysisWrapper(self) - } -} - -pub struct ValueAnalysisWrapper<T>(pub T); - -impl<'tcx, T: ValueAnalysis<'tcx>> Analysis<'tcx> for ValueAnalysisWrapper<T> { - type Domain = State<T::Value>; - - const NAME: &'static str = T::NAME; - - fn bottom_value(&self, _body: &Body<'tcx>) -> Self::Domain { - State::Unreachable - } - - fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { - // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥. - assert_matches!(state, State::Unreachable); - *state = State::new_reachable(); - for arg in body.args_iter() { - state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map()); - } - } - - fn apply_statement_effect( - &mut self, - state: &mut Self::Domain, - statement: &Statement<'tcx>, - _location: Location, - ) { - if state.is_reachable() { - self.0.handle_statement(statement, state); - } - } - - fn apply_terminator_effect<'mir>( - &mut self, - state: &mut Self::Domain, - terminator: &'mir Terminator<'tcx>, - _location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { - if state.is_reachable() { - self.0.handle_terminator(terminator, state) - } else { - TerminatorEdges::None - } - } - - fn apply_call_return_effect( - &mut self, - state: &mut Self::Domain, - _block: BasicBlock, - return_places: CallReturnPlaces<'_, 'tcx>, - ) { - if state.is_reachable() { - self.0.handle_call_return(return_places, state) - } - } - - fn apply_switch_int_edge_effects( - &mut self, - _block: BasicBlock, - _discr: &Operand<'tcx>, - _apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>, - ) { - } -} rustc_index::newtype_index!( /// This index uniquely identifies a place. @@ -464,7 +84,7 @@ impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for StateData<V> { } } -/// The dataflow state for an instance of [`ValueAnalysis`]. +/// Dataflow state. /// /// Every instance specifies a lattice that represents the possible values of a single tracked /// place. If we call this lattice `V` and set of tracked places `P`, then a [`State`] is an @@ -514,7 +134,7 @@ impl<V: Clone + HasBottom> State<V> { } } - fn is_reachable(&self) -> bool { + pub fn is_reachable(&self) -> bool { matches!(self, State::Reachable(_)) } @@ -858,7 +478,7 @@ impl<'tcx> Map<'tcx> { // Allocate a value slot if it doesn't have one, and the user requested one. assert!(place_info.value_index.is_none()); if let Ok(layout) = tcx.layout_of(param_env.and(place_info.ty)) - && layout.abi.is_scalar() + && layout.backend_repr.is_scalar() { place_info.value_index = Some(self.value_count.into()); self.value_count += 1; @@ -1317,34 +937,6 @@ pub fn excluded_locals(body: &Body<'_>) -> BitSet<Local> { collector.result } -/// This is used to visualize the dataflow analysis. -impl<'tcx, T> DebugWithContext<ValueAnalysisWrapper<T>> for State<T::Value> -where - T: ValueAnalysis<'tcx>, - T::Value: Debug, -{ - fn fmt_with(&self, ctxt: &ValueAnalysisWrapper<T>, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - State::Reachable(values) => debug_with_context(values, None, ctxt.0.map(), f), - State::Unreachable => write!(f, "unreachable"), - } - } - - fn fmt_diff_with( - &self, - old: &Self, - ctxt: &ValueAnalysisWrapper<T>, - f: &mut Formatter<'_>, - ) -> std::fmt::Result { - match (self, old) { - (State::Reachable(this), State::Reachable(old)) => { - debug_with_context(this, Some(old), ctxt.0.map(), f) - } - _ => Ok(()), // Consider printing something here. - } - } -} - fn debug_with_context_rec<V: Debug + Eq + HasBottom>( place: PlaceIndex, place_str: &str, @@ -1391,7 +983,7 @@ fn debug_with_context_rec<V: Debug + Eq + HasBottom>( Ok(()) } -fn debug_with_context<V: Debug + Eq + HasBottom>( +pub fn debug_with_context<V: Debug + Eq + HasBottom>( new: &StateData<V>, old: Option<&StateData<V>>, map: &Map<'_>, diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 07ca51a67ae..4b648d21084 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start either = "1" itertools = "0.12" +rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index cd291058977..6d5665b4331 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -64,7 +64,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{ - self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, + self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::Analysis; @@ -666,14 +666,13 @@ fn locals_live_across_suspend_points<'tcx>( // Calculate when MIR locals have live storage. This gives us an upper bound of their // lifetimes. let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); // Calculate the MIR locals which have been previously // borrowed (even if they are still active). let borrowed_locals_results = - MaybeBorrowedLocals.into_engine(tcx, body).pass_name("coroutine").iterate_to_fixpoint(); + MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")); let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body); @@ -681,16 +680,12 @@ fn locals_live_across_suspend_points<'tcx>( // for. let mut requires_storage_cursor = MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); // Calculate the liveness of MIR locals ignoring borrows. - let mut liveness = MaybeLiveLocals - .into_engine(tcx, body) - .pass_name("coroutine") - .iterate_to_fixpoint() - .into_results_cursor(body); + let mut liveness = + MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")).into_results_cursor(body); let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks); let mut live_locals_at_suspension_points = Vec::new(); @@ -1501,7 +1496,11 @@ fn check_field_tys_sized<'tcx>( return; } - let infcx = tcx.infer_ctxt().ignoring_regions().build(); + // FIXME(#132279): @lcnr believes that we may want to support coroutines + // whose `Sized`-ness relies on the hidden types of opaques defined by the + // parent function. In this case we'd have to be able to reveal only these + // opaques here. + let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); let param_env = tcx.param_env(def_id); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 002216f50f2..dd85d06540d 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -2,6 +2,10 @@ //! //! Currently, this pass only propagates scalar values. +use std::assert_matches::assert_matches; +use std::fmt::Formatter; + +use rustc_abi::{BackendRepr, FIRST_VARIANT, FieldIdx, Size, VariantIdx}; use rustc_const_eval::const_eval::{DummyMachine, throw_machine_stop_str}; use rustc_const_eval::interpret::{ ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable, interp_ok, @@ -14,13 +18,13 @@ use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_mir_dataflow::lattice::FlatSet; +use rustc_mir_dataflow::fmt::DebugWithContext; +use rustc_mir_dataflow::lattice::{FlatSet, HasBottom}; use rustc_mir_dataflow::value_analysis::{ - Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace, + Map, PlaceIndex, State, TrackElem, ValueOrPlace, debug_with_context, }; use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor}; use rustc_span::DUMMY_SP; -use rustc_target::abi::{Abi, FIRST_VARIANT, FieldIdx, Size, VariantIdx}; use tracing::{debug, debug_span, instrument}; // These constants are somewhat random guesses and have not been optimized. @@ -58,8 +62,8 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { // Perform the actual dataflow analysis. let analysis = ConstAnalysis::new(tcx, body, map); - let mut results = debug_span!("analyze") - .in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint()); + let mut results = + debug_span!("analyze").in_scope(|| analysis.iterate_to_fixpoint(tcx, body, None)); // Collect results and patch the body afterwards. let mut visitor = Collector::new(tcx, &body.local_decls); @@ -69,6 +73,10 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { } } +// Note: Currently, places that have their reference taken cannot be tracked. Although this would +// be possible, it has to rely on some aliasing model, which we are not ready to commit to yet. +// Because of that, we can assume that the only way to change the value behind a tracked place is +// by direct assignment. struct ConstAnalysis<'a, 'tcx> { map: Map<'tcx>, tcx: TyCtxt<'tcx>, @@ -77,20 +85,198 @@ struct ConstAnalysis<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, } -impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { - type Value = FlatSet<Scalar>; +impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { + type Domain = State<FlatSet<Scalar>>; const NAME: &'static str = "ConstAnalysis"; - fn map(&self) -> &Map<'tcx> { - &self.map + // The bottom state denotes uninitialized memory. Because we are only doing a sound + // approximation of the actual execution, we can also use this state for places where access + // would be UB. + fn bottom_value(&self, _body: &Body<'tcx>) -> Self::Domain { + State::Unreachable + } + + fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { + // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥. + assert_matches!(state, State::Unreachable); + *state = State::new_reachable(); + for arg in body.args_iter() { + state.flood(PlaceRef { local: arg, projection: &[] }, &self.map); + } + } + + fn apply_statement_effect( + &mut self, + state: &mut Self::Domain, + statement: &Statement<'tcx>, + _location: Location, + ) { + if state.is_reachable() { + self.handle_statement(statement, state); + } + } + + fn apply_terminator_effect<'mir>( + &mut self, + state: &mut Self::Domain, + terminator: &'mir Terminator<'tcx>, + _location: Location, + ) -> TerminatorEdges<'mir, 'tcx> { + if state.is_reachable() { + self.handle_terminator(terminator, state) + } else { + TerminatorEdges::None + } + } + + fn apply_call_return_effect( + &mut self, + state: &mut Self::Domain, + _block: BasicBlock, + return_places: CallReturnPlaces<'_, 'tcx>, + ) { + if state.is_reachable() { + self.handle_call_return(return_places, state) + } + } +} + +impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { + fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self { + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + Self { + map, + tcx, + local_decls: &body.local_decls, + ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine), + param_env, + } + } + + fn handle_statement(&self, statement: &Statement<'tcx>, state: &mut State<FlatSet<Scalar>>) { + match &statement.kind { + StatementKind::Assign(box (place, rvalue)) => { + self.handle_assign(*place, rvalue, state); + } + StatementKind::SetDiscriminant { box place, variant_index } => { + self.handle_set_discriminant(*place, *variant_index, state); + } + StatementKind::Intrinsic(box intrinsic) => { + self.handle_intrinsic(intrinsic); + } + StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { + // StorageLive leaves the local in an uninitialized state. + // StorageDead makes it UB to access the local afterwards. + state.flood_with( + Place::from(*local).as_ref(), + &self.map, + FlatSet::<Scalar>::BOTTOM, + ); + } + StatementKind::Deinit(box place) => { + // Deinit makes the place uninitialized. + state.flood_with(place.as_ref(), &self.map, FlatSet::<Scalar>::BOTTOM); + } + StatementKind::Retag(..) => { + // We don't track references. + } + StatementKind::ConstEvalCounter + | StatementKind::Nop + | StatementKind::FakeRead(..) + | StatementKind::PlaceMention(..) + | StatementKind::Coverage(..) + | StatementKind::AscribeUserType(..) => (), + } + } + + fn handle_intrinsic(&self, intrinsic: &NonDivergingIntrinsic<'tcx>) { + match intrinsic { + NonDivergingIntrinsic::Assume(..) => { + // Could use this, but ignoring it is sound. + } + NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { + dst: _, + src: _, + count: _, + }) => { + // This statement represents `*dst = *src`, `count` times. + } + } + } + + fn handle_operand( + &self, + operand: &Operand<'tcx>, + state: &mut State<FlatSet<Scalar>>, + ) -> ValueOrPlace<FlatSet<Scalar>> { + match operand { + Operand::Constant(box constant) => { + ValueOrPlace::Value(self.handle_constant(constant, state)) + } + Operand::Copy(place) | Operand::Move(place) => { + // On move, we would ideally flood the place with bottom. But with the current + // framework this is not possible (similar to `InterpCx::eval_operand`). + self.map.find(place.as_ref()).map(ValueOrPlace::Place).unwrap_or(ValueOrPlace::TOP) + } + } + } + + /// The effect of a successful function call return should not be + /// applied here, see [`Analysis::apply_terminator_effect`]. + fn handle_terminator<'mir>( + &self, + terminator: &'mir Terminator<'tcx>, + state: &mut State<FlatSet<Scalar>>, + ) -> TerminatorEdges<'mir, 'tcx> { + match &terminator.kind { + TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => { + // Effect is applied by `handle_call_return`. + } + TerminatorKind::Drop { place, .. } => { + state.flood_with(place.as_ref(), &self.map, FlatSet::<Scalar>::BOTTOM); + } + TerminatorKind::Yield { .. } => { + // They would have an effect, but are not allowed in this phase. + bug!("encountered disallowed terminator"); + } + TerminatorKind::SwitchInt { discr, targets } => { + return self.handle_switch_int(discr, targets, state); + } + TerminatorKind::TailCall { .. } => { + // FIXME(explicit_tail_calls): determine if we need to do something here (probably + // not) + } + TerminatorKind::Goto { .. } + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate(_) + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::Assert { .. } + | TerminatorKind::CoroutineDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => { + // These terminators have no effect on the analysis. + } + } + terminator.edges() + } + + fn handle_call_return( + &self, + return_places: CallReturnPlaces<'_, 'tcx>, + state: &mut State<FlatSet<Scalar>>, + ) { + return_places.for_each(|place| { + state.flood(place.as_ref(), &self.map); + }) } fn handle_set_discriminant( &self, place: Place<'tcx>, variant_index: VariantIdx, - state: &mut State<Self::Value>, + state: &mut State<FlatSet<Scalar>>, ) { state.flood_discr(place.as_ref(), &self.map); if self.map.find_discr(place.as_ref()).is_some() { @@ -109,17 +295,17 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { &self, target: Place<'tcx>, rvalue: &Rvalue<'tcx>, - state: &mut State<Self::Value>, + state: &mut State<FlatSet<Scalar>>, ) { match rvalue { Rvalue::Use(operand) => { - state.flood(target.as_ref(), self.map()); + state.flood(target.as_ref(), &self.map); if let Some(target) = self.map.find(target.as_ref()) { self.assign_operand(state, target, operand); } } Rvalue::CopyForDeref(rhs) => { - state.flood(target.as_ref(), self.map()); + state.flood(target.as_ref(), &self.map); if let Some(target) = self.map.find(target.as_ref()) { self.assign_operand(state, target, &Operand::Copy(*rhs)); } @@ -127,9 +313,9 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { Rvalue::Aggregate(kind, operands) => { // If we assign `target = Enum::Variant#0(operand)`, // we must make sure that all `target as Variant#i` are `Top`. - state.flood(target.as_ref(), self.map()); + state.flood(target.as_ref(), &self.map); - let Some(target_idx) = self.map().find(target.as_ref()) else { return }; + let Some(target_idx) = self.map.find(target.as_ref()) else { return }; let (variant_target, variant_index) = match **kind { AggregateKind::Tuple | AggregateKind::Closure(..) => (Some(target_idx), None), @@ -148,14 +334,14 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { if let Some(variant_target_idx) = variant_target { for (field_index, operand) in operands.iter_enumerated() { if let Some(field) = - self.map().apply(variant_target_idx, TrackElem::Field(field_index)) + self.map.apply(variant_target_idx, TrackElem::Field(field_index)) { self.assign_operand(state, field, operand); } } } if let Some(variant_index) = variant_index - && let Some(discr_idx) = self.map().apply(target_idx, TrackElem::Discriminant) + && let Some(discr_idx) = self.map.apply(target_idx, TrackElem::Discriminant) { // We are assigning the discriminant as part of an aggregate. // This discriminant can only alias a variant field's value if the operand @@ -170,23 +356,23 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } Rvalue::BinaryOp(op, box (left, right)) if op.is_overflowing() => { // Flood everything now, so we can use `insert_value_idx` directly later. - state.flood(target.as_ref(), self.map()); + state.flood(target.as_ref(), &self.map); - let Some(target) = self.map().find(target.as_ref()) else { return }; + let Some(target) = self.map.find(target.as_ref()) else { return }; - let value_target = self.map().apply(target, TrackElem::Field(0_u32.into())); - let overflow_target = self.map().apply(target, TrackElem::Field(1_u32.into())); + let value_target = self.map.apply(target, TrackElem::Field(0_u32.into())); + let overflow_target = self.map.apply(target, TrackElem::Field(1_u32.into())); if value_target.is_some() || overflow_target.is_some() { let (val, overflow) = self.binary_op(state, *op, left, right); if let Some(value_target) = value_target { // We have flooded `target` earlier. - state.insert_value_idx(value_target, val, self.map()); + state.insert_value_idx(value_target, val, &self.map); } if let Some(overflow_target) = overflow_target { // We have flooded `target` earlier. - state.insert_value_idx(overflow_target, overflow, self.map()); + state.insert_value_idx(overflow_target, overflow, &self.map); } } } @@ -196,27 +382,30 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { _, ) => { let pointer = self.handle_operand(operand, state); - state.assign(target.as_ref(), pointer, self.map()); + state.assign(target.as_ref(), pointer, &self.map); - if let Some(target_len) = self.map().find_len(target.as_ref()) + if let Some(target_len) = self.map.find_len(target.as_ref()) && let operand_ty = operand.ty(self.local_decls, self.tcx) && let Some(operand_ty) = operand_ty.builtin_deref(true) && let ty::Array(_, len) = operand_ty.kind() && let Some(len) = Const::Ty(self.tcx.types.usize, *len) .try_eval_scalar_int(self.tcx, self.param_env) { - state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map()); + state.insert_value_idx(target_len, FlatSet::Elem(len.into()), &self.map); } } - _ => self.super_assign(target, rvalue, state), + _ => { + let result = self.handle_rvalue(rvalue, state); + state.assign(target.as_ref(), result, &self.map); + } } } fn handle_rvalue( &self, rvalue: &Rvalue<'tcx>, - state: &mut State<Self::Value>, - ) -> ValueOrPlace<Self::Value> { + state: &mut State<FlatSet<Scalar>>, + ) -> ValueOrPlace<FlatSet<Scalar>> { let val = match rvalue { Rvalue::Len(place) => { let place_ty = place.ty(self.local_decls, self.tcx); @@ -225,7 +414,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { .try_eval_scalar(self.tcx, self.param_env) .map_or(FlatSet::Top, FlatSet::Elem) } else if let [ProjectionElem::Deref] = place.projection[..] { - state.get_len(place.local.into(), self.map()) + state.get_len(place.local.into(), &self.map) } else { FlatSet::Top } @@ -296,8 +485,24 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { }; FlatSet::Elem(Scalar::from_target_usize(val, &self.tcx)) } - Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), self.map()), - _ => return self.super_rvalue(rvalue, state), + Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map), + Rvalue::Use(operand) => return self.handle_operand(operand, state), + Rvalue::CopyForDeref(place) => { + return self.handle_operand(&Operand::Copy(*place), state); + } + Rvalue::Ref(..) | Rvalue::RawPtr(..) => { + // We don't track such places. + return ValueOrPlace::TOP; + } + Rvalue::Repeat(..) + | Rvalue::ThreadLocalRef(..) + | Rvalue::Cast(..) + | Rvalue::BinaryOp(..) + | Rvalue::Aggregate(..) + | Rvalue::ShallowInitBox(..) => { + // No modification is possible through these r-values. + return ValueOrPlace::TOP; + } }; ValueOrPlace::Value(val) } @@ -305,8 +510,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { fn handle_constant( &self, constant: &ConstOperand<'tcx>, - _state: &mut State<Self::Value>, - ) -> Self::Value { + _state: &mut State<FlatSet<Scalar>>, + ) -> FlatSet<Scalar> { constant .const_ .try_eval_scalar(self.tcx, self.param_env) @@ -317,11 +522,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { &self, discr: &'mir Operand<'tcx>, targets: &'mir SwitchTargets, - state: &mut State<Self::Value>, + state: &mut State<FlatSet<Scalar>>, ) -> TerminatorEdges<'mir, 'tcx> { let value = match self.handle_operand(discr, state) { ValueOrPlace::Value(value) => value, - ValueOrPlace::Place(place) => state.get_idx(place, self.map()), + ValueOrPlace::Place(place) => state.get_idx(place, &self.map), }; match value { // We are branching on uninitialized data, this is UB, treat it as unreachable. @@ -334,19 +539,6 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { FlatSet::Top => TerminatorEdges::SwitchInt { discr, targets }, } } -} - -impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { - fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self { - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - Self { - map, - tcx, - local_decls: &body.local_decls, - ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine), - param_env, - } - } /// The caller must have flooded `place`. fn assign_operand( @@ -457,7 +649,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { // a pair and sometimes not. But as a hack we always return a pair // and just make the 2nd component `Bottom` when it does not exist. Some(val) => { - if matches!(val.layout.abi, Abi::ScalarPair(..)) { + if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) { let (val, overflow) = val.to_scalar_pair(); (FlatSet::Elem(val), FlatSet::Elem(overflow)) } else { @@ -470,7 +662,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { // Exactly one side is known, attempt some algebraic simplifications. (FlatSet::Elem(const_arg), _) | (_, FlatSet::Elem(const_arg)) => { let layout = const_arg.layout; - if !matches!(layout.abi, rustc_target::abi::Abi::Scalar(..)) { + if !matches!(layout.backend_repr, rustc_target::abi::BackendRepr::Scalar(..)) { return (FlatSet::Top, FlatSet::Top); } @@ -537,16 +729,40 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } -pub(crate) struct Patch<'tcx> { +/// This is used to visualize the dataflow analysis. +impl<'tcx> DebugWithContext<ConstAnalysis<'_, 'tcx>> for State<FlatSet<Scalar>> { + fn fmt_with(&self, ctxt: &ConstAnalysis<'_, 'tcx>, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + State::Reachable(values) => debug_with_context(values, None, &ctxt.map, f), + State::Unreachable => write!(f, "unreachable"), + } + } + + fn fmt_diff_with( + &self, + old: &Self, + ctxt: &ConstAnalysis<'_, 'tcx>, + f: &mut Formatter<'_>, + ) -> std::fmt::Result { + match (self, old) { + (State::Reachable(this), State::Reachable(old)) => { + debug_with_context(this, Some(old), &ctxt.map, f) + } + _ => Ok(()), // Consider printing something here. + } + } +} + +struct Patch<'tcx> { tcx: TyCtxt<'tcx>, /// For a given MIR location, this stores the values of the operands used by that location. In /// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are /// properly captured. (This may become UB soon, but it is currently emitted even by safe code.) - pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), Const<'tcx>>, + before_effect: FxHashMap<(Location, Place<'tcx>), Const<'tcx>>, /// Stores the assigned values for assignments where the Rvalue is constant. - pub(crate) assignments: FxHashMap<Location, Const<'tcx>>, + assignments: FxHashMap<Location, Const<'tcx>>, } impl<'tcx> Patch<'tcx> { @@ -589,13 +805,13 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { } let place = map.find(place.as_ref())?; - if layout.abi.is_scalar() + if layout.backend_repr.is_scalar() && let Some(value) = propagatable_scalar(place, state, map) { return Some(Const::Val(ConstValue::Scalar(value), ty)); } - if matches!(layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + if matches!(layout.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) { let alloc_id = ecx .intern_with_temp_alloc(layout, |ecx, dest| { try_write_constant(ecx, dest, place, ty, state, map) @@ -641,7 +857,7 @@ fn try_write_constant<'tcx>( } // Fast path for scalars. - if layout.abi.is_scalar() + if layout.backend_repr.is_scalar() && let Some(value) = propagatable_scalar(place, state, map) { return ecx.write_immediate(Immediate::Scalar(value), dest); @@ -725,8 +941,7 @@ fn try_write_constant<'tcx>( interp_ok(()) } -impl<'mir, 'tcx> - ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>> +impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx>>> for Collector<'_, 'tcx> { type Domain = State<FlatSet<Scalar>>; @@ -734,7 +949,7 @@ impl<'mir, 'tcx> #[instrument(level = "trace", skip(self, results, statement))] fn visit_statement_before_primary_effect( &mut self, - results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, + results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, state: &Self::Domain, statement: &'mir Statement<'tcx>, location: Location, @@ -744,8 +959,8 @@ impl<'mir, 'tcx> OperandCollector { state, visitor: self, - ecx: &mut results.analysis.0.ecx, - map: &results.analysis.0.map, + ecx: &mut results.analysis.ecx, + map: &results.analysis.map, } .visit_rvalue(rvalue, location); } @@ -756,7 +971,7 @@ impl<'mir, 'tcx> #[instrument(level = "trace", skip(self, results, statement))] fn visit_statement_after_primary_effect( &mut self, - results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, + results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, state: &Self::Domain, statement: &'mir Statement<'tcx>, location: Location, @@ -767,10 +982,10 @@ impl<'mir, 'tcx> } StatementKind::Assign(box (place, _)) => { if let Some(value) = self.try_make_constant( - &mut results.analysis.0.ecx, + &mut results.analysis.ecx, place, state, - &results.analysis.0.map, + &results.analysis.map, ) { self.patch.assignments.insert(location, value); } @@ -781,7 +996,7 @@ impl<'mir, 'tcx> fn visit_terminator_before_primary_effect( &mut self, - results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, + results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, state: &Self::Domain, terminator: &'mir Terminator<'tcx>, location: Location, @@ -789,8 +1004,8 @@ impl<'mir, 'tcx> OperandCollector { state, visitor: self, - ecx: &mut results.analysis.0.ecx, - map: &results.analysis.0.map, + ecx: &mut results.analysis.ecx, + map: &results.analysis.map, } .visit_terminator(terminator, location); } diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index edffe6ce78f..2898f82e25c 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -37,8 +37,7 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { always_live.union(&borrowed_locals); let mut live = MaybeTransitiveLiveLocals::new(&always_live) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); // For blocks with a call terminator, if an argument copy can be turned into a move, diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index ad83c0295ba..beeab0d4a66 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -169,10 +169,7 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation { let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body); - let live = MaybeLiveLocals - .into_engine(tcx, body) - .pass_name("MaybeLiveLocals-DestinationPropagation") - .iterate_to_fixpoint(); + let live = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("MaybeLiveLocals-DestProp")); let points = DenseLocationMap::new(body); let mut live = save_as_intervals(&points, body, live); diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 30e1ac05e03..58e1db19438 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -64,18 +64,14 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops { let mut inits = MaybeInitializedPlaces::new(tcx, body, &env.move_data) .skipping_unreachable_unwind() - .into_engine(tcx, body) - .pass_name("elaborate_drops") - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, Some("elaborate_drops")) .into_results_cursor(body); let dead_unwinds = compute_dead_unwinds(body, &mut inits); let uninits = MaybeUninitializedPlaces::new(tcx, body, &env.move_data) .mark_inactive_variants_as_uninit() .skipping_unreachable_unwind(dead_unwinds) - .into_engine(tcx, body) - .pass_name("elaborate_drops") - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, Some("elaborate_drops")) .into_results_cursor(body); let drop_flags = IndexVec::from_elem(None, &env.move_data.move_paths); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 79c62372df0..274eea9563f 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -85,6 +85,7 @@ use std::borrow::Cow; use either::Either; +use rustc_abi::{self as abi, BackendRepr, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx}; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, Scalar, @@ -103,7 +104,6 @@ use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; -use rustc_target::abi::{self, Abi, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx}; use smallvec::SmallVec; use tracing::{debug, instrument, trace}; @@ -427,7 +427,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { }; let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); ImmTy::from_immediate(ptr_imm, ty).into() - } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + } else if matches!( + ty.backend_repr, + BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) + ) { let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; let variant_dest = if let Some(variant) = variant { self.ecx.project_downcast(&dest, variant).discard_err()? @@ -573,12 +576,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // limited transmutes: it only works between types with the same layout, and // cannot transmute pointers to integers. if value.as_mplace_or_imm().is_right() { - let can_transmute = match (value.layout.abi, to.abi) { - (Abi::Scalar(s1), Abi::Scalar(s2)) => { + let can_transmute = match (value.layout.backend_repr, to.backend_repr) { + (BackendRepr::Scalar(s1), BackendRepr::Scalar(s2)) => { s1.size(&self.ecx) == s2.size(&self.ecx) && !matches!(s1.primitive(), Primitive::Pointer(..)) } - (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => { + (BackendRepr::ScalarPair(a1, b1), BackendRepr::ScalarPair(a2, b2)) => { a1.size(&self.ecx) == a2.size(&self.ecx) && b1.size(&self.ecx) == b2.size(&self.ecx) && // The alignment of the second component determines its offset, so that also needs to match. @@ -1079,7 +1082,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } - if let AggregateTy::Def(_, _) = ty + // unsound: https://github.com/rust-lang/rust/issues/132353 + if tcx.sess.opts.unstable_opts.unsound_mir_opts + && let AggregateTy::Def(_, _) = ty && let Some(value) = self.simplify_aggregate_to_copy(rvalue, location, &fields, variant_index) { @@ -1241,7 +1246,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let as_bits = |value| { let constant = self.evaluated[value].as_ref()?; - if layout.abi.is_scalar() { + if layout.backend_repr.is_scalar() { let scalar = self.ecx.read_scalar(constant).discard_err()?; scalar.to_bits(constant.layout.size).discard_err() } else { @@ -1497,12 +1502,12 @@ fn op_to_prop_const<'tcx>( // Do not synthetize too large constants. Codegen will just memcpy them, which we'd like to // avoid. - if !matches!(op.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + if !matches!(op.layout.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) { return None; } // If this constant has scalar ABI, return it as a `ConstValue::Scalar`. - if let Abi::Scalar(abi::Scalar::Initialized { .. }) = op.layout.abi + if let BackendRepr::Scalar(abi::Scalar::Initialized { .. }) = op.layout.backend_repr && let Some(scalar) = ecx.read_scalar(op).discard_err() { if !scalar.try_to_scalar_int().is_ok() { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 42d6bdf6cee..404470db5c5 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -244,8 +244,13 @@ impl<'tcx> Inliner<'tcx> { // Normally, this shouldn't be required, but trait normalization failure can create a // validation ICE. let output_type = callee_body.return_ty(); - if !util::relate_types(self.tcx, self.param_env, ty::Covariant, output_type, destination_ty) - { + if !util::sub_types( + self.tcx, + caller_body.typing_mode(self.tcx), + self.param_env, + output_type, + destination_ty, + ) { trace!(?output_type, ?destination_ty); return Err("failed to normalize return type"); } @@ -275,8 +280,13 @@ impl<'tcx> Inliner<'tcx> { self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter()) { let input_type = callee_body.local_decls[input].ty; - if !util::relate_types(self.tcx, self.param_env, ty::Covariant, input_type, arg_ty) - { + if !util::sub_types( + self.tcx, + caller_body.typing_mode(self.tcx), + self.param_env, + input_type, + arg_ty, + ) { trace!(?arg_ty, ?input_type); return Err("failed to normalize tuple argument type"); } @@ -285,8 +295,13 @@ impl<'tcx> Inliner<'tcx> { for (arg, input) in args.iter().zip(callee_body.args_iter()) { let input_type = callee_body.local_decls[input].ty; let arg_ty = arg.node.ty(&caller_body.local_decls, self.tcx); - if !util::relate_types(self.tcx, self.param_env, ty::Covariant, input_type, arg_ty) - { + if !util::sub_types( + self.tcx, + caller_body.typing_mode(self.tcx), + self.param_env, + input_type, + arg_ty, + ) { trace!(?arg_ty, ?input_type); return Err("failed to normalize argument type"); } diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 08923748eb2..0604665642a 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -4,6 +4,7 @@ use std::fmt::Debug; +use rustc_abi::{BackendRepr, FieldIdx, HasDataLayout, Size, TargetDataLayout, VariantIdx}; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error, interp_ok, @@ -19,7 +20,6 @@ use rustc_middle::mir::*; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::{self, ConstInt, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; -use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, VariantIdx}; use tracing::{debug, instrument, trace}; use crate::errors::{AssertLint, AssertLintKind}; @@ -557,7 +557,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?; let val = self.use_ecx(|this| this.ecx.binary_op(bin_op, &left, &right))?; - if matches!(val.layout.abi, Abi::ScalarPair(..)) { + if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) { // FIXME `Value` should properly support pairs in `Immediate`... but currently // it does not. let (val, overflow) = val.to_pair(&self.ecx); @@ -651,9 +651,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let to = self.ecx.layout_of(to).ok()?; // `offset` for immediates only supports scalar/scalar-pair ABIs, // so bail out if the target is not one. - match (value.layout.abi, to.abi) { - (Abi::Scalar(..), Abi::Scalar(..)) => {} - (Abi::ScalarPair(..), Abi::ScalarPair(..)) => {} + match (value.layout.backend_repr, to.backend_repr) { + (BackendRepr::Scalar(..), BackendRepr::Scalar(..)) => {} + (BackendRepr::ScalarPair(..), BackendRepr::ScalarPair(..)) => {} _ => return None, } diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs index 23733994a8b..d8ff1cfc90b 100644 --- a/compiler/rustc_mir_transform/src/lint.rs +++ b/compiler/rustc_mir_transform/src/lint.rs @@ -17,13 +17,11 @@ pub(super) fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String let always_live_locals = &always_storage_live_locals(body); let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); let maybe_storage_dead = MaybeStorageDead::new(Cow::Borrowed(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); let mut lint = Lint { diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index 53e53d9d5ba..b11b503e8d4 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -126,8 +126,7 @@ fn compute_replacement<'tcx>( // Compute `MaybeStorageDead` dataflow to check that we only replace when the pointee is // definitely live. let mut maybe_dead = MaybeStorageDead::new(Cow::Owned(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); // Map for each local to the pointee. diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index 09969a4c7cc..55dd96100b0 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -22,9 +22,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops { let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env)); let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .pass_name("remove_uninit_drops") - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, Some("remove_uninit_drops")) .into_results_cursor(body); let mut to_remove = vec![]; diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs index 5612e779d6b..3011af4d9d7 100644 --- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs @@ -1,5 +1,6 @@ //! A pass that eliminates branches on uninhabited or unreachable enum variants. +use rustc_abi::Variants; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::mir::patch::MirPatch; @@ -9,7 +10,6 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; -use rustc_target::abi::{Abi, Variants}; use tracing::trace; pub(super) struct UnreachableEnumBranching; @@ -65,7 +65,7 @@ fn variant_discriminants<'tcx>( Variants::Multiple { variants, .. } => variants .iter_enumerated() .filter_map(|(idx, layout)| { - (layout.abi != Abi::Uninhabited) + (!layout.is_uninhabited()) .then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val) }) .collect(), diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 25e68f44456..8109a9b8ba0 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -5,7 +5,7 @@ use rustc_hir::LangItem; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::{Obligation, ObligationCause, Reveal}; +use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -20,7 +20,7 @@ use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::ObligationCtxt; use rustc_type_ir::Upcast; -use crate::util::{is_within_packed, relate_types}; +use crate::util::{self, is_within_packed}; #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum EdgeKind { @@ -50,11 +50,7 @@ impl<'tcx> crate::MirPass<'tcx> for Validator { } let def_id = body.source.def_id(); let mir_phase = self.mir_phase; - let param_env = match mir_phase.reveal() { - Reveal::UserFacing => tcx.param_env(def_id), - Reveal::All => tcx.param_env_reveal_all_normalized(def_id), - }; - + let param_env = mir_phase.param_env(tcx, def_id); let can_unwind = if mir_phase <= MirPhase::Runtime(RuntimePhase::Initial) { // In this case `AbortUnwindingCalls` haven't yet been executed. true @@ -587,7 +583,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Variance::Covariant }; - crate::util::relate_types(self.tcx, self.param_env, variance, src, dest) + crate::util::relate_types( + self.tcx, + self.body.typing_mode(self.tcx), + self.param_env, + variance, + src, + dest, + ) } /// Check that the given predicate definitely holds in the param-env of this MIR body. @@ -606,7 +609,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return true; } - let infcx = self.tcx.infer_ctxt().build(); + let infcx = self.tcx.infer_ctxt().build(self.body.typing_mode(self.tcx)); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligation(Obligation::new( self.tcx, @@ -798,10 +801,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } ProjectionElem::Subtype(ty) => { - if !relate_types( + if !util::sub_types( self.tcx, + self.body.typing_mode(self.tcx), self.param_env, - Variance::Covariant, ty, place_ref.ty(&self.body.local_decls, self.tcx).ty, ) { diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 4da1e7fa711..f7fbfed5b8e 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -1,7 +1,7 @@ use std::ops::Deref; use rustc_type_ir::fold::TypeFoldable; -use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode}; +use rustc_type_ir::solve::{Certainty, Goal, NoSolution}; use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Sized { @@ -15,7 +15,6 @@ pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Size fn build_with_canonical<V>( cx: Self::Interner, - solver_mode: SolverMode, canonical: &ty::CanonicalQueryInput<Self::Interner, V>, ) -> (Self, V, ty::CanonicalVarValues<Self::Interner>) where @@ -93,7 +92,6 @@ pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Size fn fetch_eligible_assoc_item( &self, - param_env: <Self::Interner as Interner>::ParamEnv, goal_trait_ref: ty::TraitRef<Self::Interner>, trait_assoc_def_id: <Self::Interner as Interner>::DefId, impl_def_id: <Self::Interner as Interner>::DefId, 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 f6a5f20a639..ebf7372926f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -8,14 +8,14 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::solve::inspect; use rustc_type_ir::visit::TypeVisitableExt as _; -use rustc_type_ir::{self as ty, Interner, Upcast as _, elaborate}; +use rustc_type_ir::{self as ty, Interner, TypingMode, Upcast as _, elaborate}; use tracing::{debug, instrument}; use crate::delegate::SolverDelegate; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource, - MaybeCause, NoSolution, QueryResult, SolverMode, + MaybeCause, NoSolution, QueryResult, }; /// A candidate is a possible way to prove a goal. @@ -328,11 +328,12 @@ where let mut candidates = vec![]; - if self.solver_mode() == SolverMode::Coherence { + if let TypingMode::Coherence = self.typing_mode(goal.param_env) { if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) { return vec![candidate]; } } + self.assemble_impl_candidates(goal, &mut candidates); self.assemble_builtin_impl_candidates(goal, &mut candidates); @@ -343,8 +344,11 @@ where self.assemble_param_env_candidates(goal, &mut candidates); - if self.solver_mode() == SolverMode::Normal { - self.discard_impls_shadowed_by_env(goal, &mut candidates); + match self.typing_mode(goal.param_env) { + TypingMode::Coherence => {} + TypingMode::Analysis { .. } | TypingMode::PostAnalysis => { + self.discard_impls_shadowed_by_env(goal, &mut candidates); + } } candidates 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 8d57ad8f255..5bfc156ed94 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -44,7 +44,7 @@ where ) -> Result<Candidate<I>, NoSolution> { if let Some(host_clause) = assumption.as_host_effect_clause() { if host_clause.def_id() == goal.predicate.def_id() - && host_clause.host().satisfies(goal.predicate.host) + && host_clause.constness().satisfies(goal.predicate.constness) { if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( goal.predicate.trait_ref.args, @@ -91,7 +91,7 @@ where cx, cx.implied_const_bounds(alias_ty.def_id) .iter_instantiated(cx, alias_ty.args) - .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.host)), + .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.constness)), ) { candidates.extend(Self::probe_and_match_goal_against_assumption( ecx, @@ -107,7 +107,7 @@ where .map(|trait_ref| { goal.with( cx, - trait_ref.to_host_effect_clause(cx, goal.predicate.host), + trait_ref.to_host_effect_clause(cx, goal.predicate.constness), ) }), ); @@ -163,7 +163,10 @@ where .const_conditions(impl_def_id) .iter_instantiated(cx, impl_args) .map(|bound_trait_ref| { - goal.with(cx, bound_trait_ref.to_host_effect_clause(cx, goal.predicate.host)) + goal.with( + cx, + bound_trait_ref.to_host_effect_clause(cx, goal.predicate.constness), + ) }); ecx.add_goals(GoalSource::ImplWhereBound, const_conditions); diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index e2fd0dd2a25..2f50070d438 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -55,6 +55,7 @@ where &self, goal: Goal<I, T>, ) -> (Vec<I::GenericArg>, CanonicalInput<I, T>) { + let param_env_for_debug_assertion = goal.param_env; let opaque_types = self.delegate.clone_opaque_types_for_query_response(); let (goal, opaque_types) = (goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate)); @@ -73,7 +74,7 @@ where ); let query_input = ty::CanonicalQueryInput { canonical, - defining_opaque_types: self.delegate.defining_opaque_types(), + typing_mode: self.typing_mode(param_env_for_debug_assertion), }; (orig_values, query_input) } 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 7608253882a..8685896715e 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 @@ -10,7 +10,7 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner}; +use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypingMode}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::{instrument, trace}; @@ -21,7 +21,6 @@ use crate::solve::search_graph::SearchGraph; use crate::solve::{ CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, GoalSource, HasChanged, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, - SolverMode, }; pub(super) mod canonical; @@ -215,8 +214,8 @@ where D: SolverDelegate<Interner = I>, I: Interner, { - pub(super) fn solver_mode(&self) -> SolverMode { - self.search_graph.solver_mode() + pub(super) fn typing_mode(&self, param_env_for_debug_assertion: I::ParamEnv) -> TypingMode<I> { + self.delegate.typing_mode(param_env_for_debug_assertion) } pub(super) fn set_is_normalizes_to_goal(&mut self) { @@ -232,7 +231,7 @@ where generate_proof_tree: GenerateProofTree, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R, ) -> (R, Option<inspect::GoalEvaluation<I>>) { - let mut search_graph = SearchGraph::new(delegate.solver_mode(), root_depth); + let mut search_graph = SearchGraph::new(root_depth); let mut ecx = EvalCtxt { delegate, @@ -279,7 +278,7 @@ where f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R, ) -> R { let (ref delegate, input, var_values) = - SolverDelegate::build_with_canonical(cx, search_graph.solver_mode(), &canonical_input); + SolverDelegate::build_with_canonical(cx, &canonical_input); let mut ecx = EvalCtxt { delegate, @@ -942,21 +941,11 @@ where pub(super) fn fetch_eligible_assoc_item( &self, - param_env: I::ParamEnv, goal_trait_ref: ty::TraitRef<I>, trait_assoc_def_id: I::DefId, impl_def_id: I::DefId, ) -> Result<Option<I::DefId>, NoSolution> { - self.delegate.fetch_eligible_assoc_item( - param_env, - goal_trait_ref, - trait_assoc_def_id, - impl_def_id, - ) - } - - pub(super) fn can_define_opaque_ty(&self, def_id: I::LocalDefId) -> bool { - self.delegate.defining_opaque_types().contains(&def_id) + self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id) } pub(super) fn insert_hidden_type( 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 7287cdf74bf..129744b4db7 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 @@ -6,7 +6,7 @@ mod weak_types; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; -use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _}; +use rustc_type_ir::{self as ty, Interner, NormalizesTo, TypingMode, Upcast as _}; use tracing::instrument; use crate::delegate::SolverDelegate; @@ -15,7 +15,7 @@ use crate::solve::assembly::{self, Candidate}; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, - NoSolution, QueryResult, Reveal, + NoSolution, QueryResult, }; impl<D, I> EvalCtxt<'_, D> @@ -71,21 +71,21 @@ where Ok(()) } ty::AliasTermKind::OpaqueTy => { - match param_env.reveal() { - // In user-facing mode, paques are only rigid if we may not define it. - Reveal::UserFacing => { + match self.typing_mode(param_env) { + // Opaques are never rigid outside of analysis mode. + TypingMode::Coherence | TypingMode::PostAnalysis => Err(NoSolution), + // During analysis, opaques are only rigid if we may not define it. + TypingMode::Analysis { defining_opaque_types } => { if rigid_alias .def_id .as_local() - .is_some_and(|def_id| self.can_define_opaque_ty(def_id)) + .is_some_and(|def_id| defining_opaque_types.contains(&def_id)) { Err(NoSolution) } else { Ok(()) } } - // Opaques are never rigid in reveal-all mode. - Reveal::All => Err(NoSolution), } } // FIXME(generic_const_exprs): we would need to support generic consts here @@ -252,7 +252,6 @@ where // return ambiguity this would otherwise be incomplete, resulting in // unsoundness during coherence (#105782). let Some(target_item_def_id) = ecx.fetch_eligible_assoc_item( - goal.param_env, goal_trait_ref, goal.predicate.def_id(), impl_def_id, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index f8d51f304f3..d1d701695ab 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -4,12 +4,10 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_type_ir::inherent::*; -use rustc_type_ir::{self as ty, Interner}; +use rustc_type_ir::{self as ty, Interner, TypingMode}; use crate::delegate::SolverDelegate; -use crate::solve::{ - Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode, inspect, -}; +use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, inspect}; impl<D, I> EvalCtxt<'_, D> where @@ -24,17 +22,27 @@ where let opaque_ty = goal.predicate.alias; let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const"); - match (goal.param_env.reveal(), self.solver_mode()) { - (Reveal::UserFacing, SolverMode::Normal) => { - let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else { + match self.typing_mode(goal.param_env) { + TypingMode::Coherence => { + // An impossible opaque type bound is the only way this goal will fail + // e.g. assigning `impl Copy := NotCopy` + self.add_item_bounds_for_hidden_type( + opaque_ty.def_id, + opaque_ty.args, + goal.param_env, + expected, + ); + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + TypingMode::Analysis { defining_opaque_types } => { + let Some(def_id) = opaque_ty.def_id.as_local() else { return Err(NoSolution); }; - // FIXME: at some point we should call queries without defining - // new opaque types but having the existing opaque type definitions. - // This will require moving this below "Prefer opaques registered already". - if !self.can_define_opaque_ty(opaque_ty_def_id) { + + if !defining_opaque_types.contains(&def_id) { return Err(NoSolution); } + // FIXME: This may have issues when the args contain aliases... match uses_unique_placeholders_ignoring_regions(self.cx(), opaque_ty.args) { Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { @@ -48,8 +56,7 @@ where Ok(()) => {} } // Prefer opaques registered already. - let opaque_type_key = - ty::OpaqueTypeKey { def_id: opaque_ty_def_id, args: opaque_ty.args }; + let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args }; // FIXME: This also unifies the previous hidden type with the expected. // // If that fails, we insert `expected` as a new hidden type instead of @@ -69,7 +76,7 @@ where } ecx.eq(goal.param_env, candidate_ty, expected)?; ecx.add_item_bounds_for_hidden_type( - candidate_key.def_id.into(), + def_id.into(), candidate_key.args, goal.param_env, candidate_ty, @@ -82,25 +89,14 @@ where // FIXME: should we use `inject_hidden_type_unchecked` here? self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; self.add_item_bounds_for_hidden_type( - opaque_ty.def_id, + def_id.into(), opaque_ty.args, goal.param_env, expected, ); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - (Reveal::UserFacing, SolverMode::Coherence) => { - // An impossible opaque type bound is the only way this goal will fail - // e.g. assigning `impl Copy := NotCopy` - self.add_item_bounds_for_hidden_type( - opaque_ty.def_id, - opaque_ty.args, - goal.param_env, - expected, - ); - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - } - (Reveal::All, _) => { + TypingMode::PostAnalysis => { // FIXME: Add an assertion that opaque type storage is empty. let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args); self.eq(goal.param_env, expected, actual)?; 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 08cc89d950e..e23e475a2a6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -6,7 +6,7 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::visit::TypeVisitableExt as _; -use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _, elaborate}; +use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate}; use tracing::{instrument, trace}; use crate::delegate::SolverDelegate; @@ -15,7 +15,7 @@ use crate::solve::assembly::{self, Candidate}; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, - NoSolution, QueryResult, Reveal, SolverMode, + NoSolution, QueryResult, }; impl<D, I> assembly::GoalKind<D> for TraitPredicate<I> @@ -67,9 +67,9 @@ where let maximal_certainty = match (impl_polarity, goal.predicate.polarity) { // In intercrate mode, this is ambiguous. But outside of intercrate, // it's not a real impl. - (ty::ImplPolarity::Reservation, _) => match ecx.solver_mode() { - SolverMode::Coherence => Certainty::AMBIGUOUS, - SolverMode::Normal => return Err(NoSolution), + (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode(goal.param_env) { + TypingMode::Coherence => Certainty::AMBIGUOUS, + TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Err(NoSolution), }, // Impl matches polarity @@ -167,30 +167,26 @@ where return result; } - // Don't call `type_of` on a local TAIT that's in the defining scope, - // since that may require calling `typeck` on the same item we're + // We only look into opaque types during analysis for opaque types + // outside of their defining scope. Doing so for opaques in the + // defining scope may require calling `typeck` on the same item we're // currently type checking, which will result in a fatal cycle that // ideally we want to avoid, since we can make progress on this goal // via an alias bound or a locally-inferred hidden type instead. - // - // Also, don't call `type_of` on a TAIT in `Reveal::All` mode, since - // we already normalize the self type in - // `assemble_candidates_after_normalizing_self_ty`, and we'd - // just be registering an identical candidate here. - // - // We always return `Err(NoSolution)` here in `SolverMode::Coherence` - // since we'll always register an ambiguous candidate in - // `assemble_candidates_after_normalizing_self_ty` due to normalizing - // the TAIT. if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { - if matches!(goal.param_env.reveal(), Reveal::All) - || matches!(ecx.solver_mode(), SolverMode::Coherence) - || opaque_ty - .def_id - .as_local() - .is_some_and(|def_id| ecx.can_define_opaque_ty(def_id)) - { - return Err(NoSolution); + match ecx.typing_mode(goal.param_env) { + TypingMode::Coherence | TypingMode::PostAnalysis => { + unreachable!("rigid opaque outside of analysis: {goal:?}"); + } + TypingMode::Analysis { defining_opaque_types } => { + if opaque_ty + .def_id + .as_local() + .is_some_and(|def_id| defining_opaque_types.contains(&def_id)) + { + return Err(NoSolution); + } + } } } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a9384501547..a1fe5508970 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -14,6 +14,7 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::sync::Lrc; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, PErr, PResult, Subdiagnostic, Suggestions, pluralize, @@ -2437,7 +2438,7 @@ impl<'a> Parser<'a> { let mut labels = vec![]; while let TokenKind::Interpolated(nt) = &tok.kind { let tokens = nt.tokens(); - labels.push(nt.clone()); + labels.push(Lrc::clone(nt)); if let Some(tokens) = tokens && let tokens = tokens.to_attr_token_stream() && let tokens = tokens.0.deref() diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 36733726564..6b4e2d0f4e2 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1194,6 +1194,7 @@ impl<'a> Parser<'a> { attrs: &mut AttrVec, mut safety: Safety, ) -> PResult<'a, ItemInfo> { + let extern_span = self.prev_token.uninterpolated_span(); let abi = self.parse_abi(); // ABI? // FIXME: This recovery should be tested better. if safety == Safety::Default @@ -1205,6 +1206,7 @@ impl<'a> Parser<'a> { let _ = self.eat_keyword(kw::Unsafe); } let module = ast::ForeignMod { + extern_span, safety, abi, items: self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 77ad4fdeeb1..50a8b6542df 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -424,7 +424,7 @@ impl TokenDescription { } } -pub(super) fn token_descr(token: &Token) -> String { +pub fn token_descr(token: &Token) -> String { let name = pprust::token_to_string(token).to_string(); let kind = match (TokenDescription::from_token(token), &token.kind) { diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index b45a8dae277..ed5991459ac 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8c4592cbb36..0a2926c0404 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -25,7 +25,7 @@ use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, @@ -2267,7 +2267,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let def_id = hir_id.expect_owner().def_id; let param_env = ty::ParamEnv::empty(); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let span = tcx.def_span(def_id); diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index af17fbf7e4d..b1db66fa52d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -7,6 +7,7 @@ use std::mem; use hir::ItemKind; use hir::def_id::{LocalDefIdMap, LocalDefIdSet}; +use rustc_abi::FieldIdx; use rustc_data_structures::unord::UnordSet; use rustc_errors::MultiSpan; use rustc_hir as hir; @@ -22,7 +23,6 @@ use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_session::lint::builtin::DEAD_CODE; use rustc_span::symbol::{Symbol, sym}; -use rustc_target::abi::FieldIdx; use crate::errors::{ ChangeFields, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo, UselessAssignment, diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 93729a7f6df..986dce5b56d 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -1,13 +1,14 @@ +use rustc_abi::{HasDataLayout, TargetDataLayout}; use rustc_ast::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; +use rustc_middle::infer::canonical::ir::TypingMode; use rustc_middle::span_bug; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; -use rustc_target::abi::{HasDataLayout, TargetDataLayout}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::TyCtxtInferExt; use rustc_trait_selection::traits; @@ -54,7 +55,7 @@ pub fn ensure_wf<'tcx>( param_env, pred, ); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); @@ -81,8 +82,12 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { let meta_items = attr.meta_item_list().unwrap_or_default(); for meta_item in meta_items { match meta_item.name_or_empty() { + // FIXME: this never was about ABI and now this dump arg is confusing sym::abi => { - tcx.dcx().emit_err(LayoutAbi { span, abi: format!("{:?}", ty_layout.abi) }); + tcx.dcx().emit_err(LayoutAbi { + span, + abi: format!("{:?}", ty_layout.backend_repr), + }); } sym::align => { diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 34fb1bdf6fa..f98e4243375 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" [dependencies] # tidy-alphabetical-start rustc-hash = "2.0.0" + +rustc_abi = { path = "../rustc_abi", optional = true } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } @@ -29,6 +31,7 @@ tracing-tree = "0.3.0" [features] default = ["rustc"] rustc = [ + "dep:rustc_abi", "dep:rustc_arena", "dep:rustc_data_structures", "dep:rustc_errors", diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 0e132b27fb4..9ea5023064c 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -1,6 +1,7 @@ use std::fmt; use std::iter::once; +use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx}; use rustc_arena::DroplessArena; use rustc_hir::HirId; use rustc_hir::def_id::DefId; @@ -15,7 +16,6 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; -use rustc_target::abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx}; use crate::constructor::Constructor::*; use crate::constructor::{ diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index 17e389df17e..7649f72f868 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -11,10 +11,10 @@ use std::fmt; +use rustc_abi::{FieldIdx, VariantIdx}; use rustc_middle::bug; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_span::sym; -use rustc_target::abi::{FieldIdx, VariantIdx}; #[derive(Clone, Debug)] pub(crate) struct FieldPat { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 05954143aee..1a5c29afdc9 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -139,7 +139,7 @@ where } ty::ClauseKind::HostEffect(pred) => { try_visit!(self.visit_trait(pred.trait_ref)); - pred.host.visit_with(self) + pred.constness.visit_with(self) } ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_term: projection_ty, diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index cd7725d2d70..5e30f17d626 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -134,7 +134,7 @@ impl<D: Deps> DepGraph<D> { encoder, record_graph, record_stats, - prev_graph.clone(), + Arc::clone(&prev_graph), ); let colors = DepNodeColorMap::new(prev_graph_node_count); diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index ca3efc11201..5af41b9e687 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -237,7 +237,7 @@ impl QueryLatch { // the `wait` call below, by 1) the `set` method or 2) by deadlock detection. // Both of these will remove it from the `waiters` list before resuming // this thread. - info.waiters.push(waiter.clone()); + info.waiters.push(Arc::clone(waiter)); // If this detects a deadlock and the deadlock handler wants to resume this thread // we have to be in the `wait` call. This is ensured by the deadlock handler diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index adb0ba7c820..f4a85c358e3 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -841,10 +841,9 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.r.record_partial_res(ty.id, PartialRes::new(res)); visit::walk_ty(self, ty) } - TyKind::ImplTrait(node_id, _) => { + TyKind::ImplTrait(..) => { let candidates = self.lifetime_elision_candidates.take(); visit::walk_ty(self, ty); - self.record_lifetime_params_for_impl_trait(*node_id); self.lifetime_elision_candidates = candidates; } TyKind::TraitObject(bounds, ..) => { @@ -977,14 +976,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), &sig.decl.output, ); - - if let Some((coro_node_id, _)) = sig - .header - .coroutine_kind - .map(|coroutine_kind| coroutine_kind.return_id()) - { - this.record_lifetime_params_for_impl_trait(coro_node_id); - } }, ); return; @@ -1026,10 +1017,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)), &declaration.output, ); - - if let Some((async_node_id, _)) = coro_node_id { - this.record_lifetime_params_for_impl_trait(async_node_id); - } }, ); @@ -1220,7 +1207,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r } }, AssocItemConstraintKind::Bound { ref bounds } => { - self.record_lifetime_params_for_impl_trait(constraint.id); walk_list!(self, visit_param_bound, bounds, BoundKind::Bound); } } @@ -4795,30 +4781,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ) } - /// Construct the list of in-scope lifetime parameters for impl trait lowering. - /// We include all lifetime parameters, either named or "Fresh". - /// The order of those parameters does not matter, as long as it is - /// deterministic. - fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId) { - let mut extra_lifetime_params = vec![]; - - for rib in self.lifetime_ribs.iter().rev() { - extra_lifetime_params - .extend(rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res))); - match rib.kind { - LifetimeRibKind::Item => break, - LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { - if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) { - extra_lifetime_params.extend(earlier_fresh); - } - } - _ => {} - } - } - - self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params); - } - fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> Option<Res> { // FIXME: This caching may be incorrect in case of multiple `macro_rules` // items with the same name in the same module. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 35d491cfc18..9abb3180388 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1694,9 +1694,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc<SyntaxExtension> { match macro_kind { - MacroKind::Bang => self.dummy_ext_bang.clone(), - MacroKind::Derive => self.dummy_ext_derive.clone(), - MacroKind::Attr => self.non_macro_attr.ext.clone(), + MacroKind::Bang => Lrc::clone(&self.dummy_ext_bang), + MacroKind::Derive => Lrc::clone(&self.dummy_ext_derive), + MacroKind::Attr => Lrc::clone(&self.non_macro_attr.ext), } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 1dc27776cb0..0b4d0e04c29 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -826,7 +826,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } _ => None, }, - None => self.get_macro(res).map(|macro_data| macro_data.ext.clone()), + None => self.get_macro(res).map(|macro_data| Lrc::clone(¯o_data.ext)), }; Ok((ext, res)) } diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 75cc8f18a54..e9983699609 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # tidy-alphabetical-start bitflags = "2.4.1" getopts = "0.2" +rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs index 7a32c0c2655..f3c21992784 100644 --- a/compiler/rustc_session/src/code_stats.rs +++ b/compiler/rustc_session/src/code_stats.rs @@ -1,10 +1,10 @@ use std::cmp; +use rustc_abi::{Align, Size}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lock; use rustc_span::Symbol; use rustc_span::def_id::DefId; -use rustc_target::abi::{Align, Size}; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct VariantInfo { diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index ccc01728958..31ef2bda4f1 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -23,12 +23,12 @@ use std::hash::Hash; use std::iter; +use rustc_abi::Align; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::EXPLICIT_BUILTIN_CFGS_IN_FLAGS; use rustc_span::symbol::{Symbol, sym}; -use rustc_target::abi::Align; use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, TARGETS, Target, TargetTriple}; use crate::Session; diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 4aae2649843..b3e3381d986 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -84,7 +84,7 @@ fn current_dll_path() -> Result<PathBuf, String> { loop { if libc::loadquery( libc::L_GETINFO, - buffer.as_mut_ptr() as *mut i8, + buffer.as_mut_ptr() as *mut u8, (std::mem::size_of::<libc::ld_info>() * buffer.len()) as u32, ) >= 0 { diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 3d44810e7dd..f20ae85b8e8 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -241,7 +241,7 @@ impl ParseSess { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let emitter = Box::new( HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle) - .sm(Some(sm.clone())), + .sm(Some(Lrc::clone(&sm))), ); let dcx = DiagCtxt::new(emitter); ParseSess::with_dcx(dcx, sm) @@ -278,7 +278,7 @@ impl ParseSess { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let emitter = Box::new(HumanEmitter::new( stderr_destination(ColorConfig::Auto), - fallback_bundle.clone(), + Lrc::clone(&fallback_bundle), )); let fatal_dcx = DiagCtxt::new(emitter); let dcx = DiagCtxt::new(Box::new(SilentEmitter { @@ -297,7 +297,7 @@ impl ParseSess { } pub fn clone_source_map(&self) -> Lrc<SourceMap> { - self.source_map.clone() + Lrc::clone(&self.source_map) } pub fn buffer_lint( diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1963cf4eb7c..45434534c75 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1036,7 +1036,8 @@ pub fn build_session( sopts.unstable_opts.translate_directionality_markers, ); let source_map = rustc_span::source_map::get_source_map().unwrap(); - let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle); + let emitter = + default_emitter(&sopts, registry, Lrc::clone(&source_map), bundle, fallback_bundle); let mut dcx = DiagCtxt::new(emitter).with_flags(sopts.unstable_opts.dcx_flags(can_emit_warnings)); @@ -1079,7 +1080,7 @@ pub fn build_session( let target_tlib_path = if host_triple == target_triple { // Use the same `SearchPath` if host and target triple are identical to avoid unnecessary // rescanning of the target lib path and an unnecessary allocation. - host_tlib_path.clone() + Lrc::clone(&host_tlib_path) } else { Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, target_triple)) }; diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 55b47817f9a..a326e8583ea 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -170,7 +170,7 @@ impl<'tcx> Tables<'tcx> { stable_mir::mir::mono::StaticDef(self.create_def_id(did)) } - pub(crate) fn layout_id(&mut self, layout: rustc_target::abi::Layout<'tcx>) -> Layout { + pub(crate) fn layout_id(&mut self, layout: rustc_abi::Layout<'tcx>) -> Layout { self.layouts.create_or_fetch(layout) } } diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs index 0d8740ae31f..5c09879f60e 100644 --- a/compiler/rustc_smir/src/rustc_smir/alloc.rs +++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs @@ -1,3 +1,4 @@ +use rustc_abi::{Align, Size}; use rustc_middle::mir::ConstValue; use rustc_middle::mir::interpret::{AllocRange, Pointer, alloc_range}; use stable_mir::Error; @@ -7,7 +8,7 @@ use stable_mir::ty::{Allocation, ProvenanceMap}; use crate::rustc_smir::{Stable, Tables}; /// Creates new empty `Allocation` from given `Align`. -fn new_empty_allocation(align: rustc_target::abi::Align) -> Allocation { +fn new_empty_allocation(align: Align) -> Allocation { Allocation { bytes: Vec::new(), provenance: ProvenanceMap { ptrs: Vec::new() }, @@ -45,7 +46,7 @@ pub(crate) fn try_new_allocation<'tcx>( .align; let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi); allocation - .write_scalar(&tables.tcx, alloc_range(rustc_target::abi::Size::ZERO, size), scalar) + .write_scalar(&tables.tcx, alloc_range(Size::ZERO, size), scalar) .map_err(|e| e.stable(tables))?; allocation.stable(tables) } @@ -59,7 +60,7 @@ pub(crate) fn try_new_allocation<'tcx>( } ConstValue::Slice { data, meta } => { let alloc_id = tables.tcx.reserve_and_set_memory_alloc(data); - let ptr = Pointer::new(alloc_id.into(), rustc_target::abi::Size::ZERO); + let ptr = Pointer::new(alloc_id.into(), Size::ZERO); let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx); let scalar_meta = rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx); @@ -72,7 +73,7 @@ pub(crate) fn try_new_allocation<'tcx>( allocation .write_scalar( &tables.tcx, - alloc_range(rustc_target::abi::Size::ZERO, tables.tcx.data_layout.pointer_size), + alloc_range(Size::ZERO, tables.tcx.data_layout.pointer_size), scalar_ptr, ) .map_err(|e| e.stable(tables))?; @@ -112,10 +113,7 @@ pub(super) fn allocation_filter<'tcx>( .map(Some) .collect(); for (i, b) in bytes.iter_mut().enumerate() { - if !alloc - .init_mask() - .get(rustc_target::abi::Size::from_bytes(i + alloc_range.start.bytes_usize())) - { + if !alloc.init_mask().get(Size::from_bytes(i + alloc_range.start.bytes_usize())) { *b = None; } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index dbfcde56f6e..af24fd23f50 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -1,9 +1,9 @@ -//! Conversion of internal Rust compiler `rustc_target::abi` and `rustc_abi` items to stable ones. +//! Conversion of internal Rust compiler `rustc_target` and `rustc_abi` items to stable ones. #![allow(rustc::usage_of_qualified_ty)] use rustc_middle::ty; -use rustc_target::abi::call::Conv; +use rustc_target::callconv::{self, Conv}; use stable_mir::abi::{ AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout, LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape, @@ -15,7 +15,7 @@ use stable_mir::ty::{Align, IndexedVal, VariantIdx}; use crate::rustc_smir::{Stable, Tables}; -impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx { +impl<'tcx> Stable<'tcx> for rustc_abi::VariantIdx { type T = VariantIdx; fn stable(&self, _: &mut Tables<'_>) -> Self::T { VariantIdx::to_val(self.as_usize()) @@ -33,7 +33,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Endian { } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> { +impl<'tcx> Stable<'tcx> for rustc_abi::TyAndLayout<'tcx, ty::Ty<'tcx>> { type T = TyAndLayout; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -41,7 +41,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> { } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> { +impl<'tcx> Stable<'tcx> for rustc_abi::Layout<'tcx> { type T = Layout; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -49,23 +49,21 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> { } } -impl<'tcx> Stable<'tcx> - for rustc_abi::LayoutData<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx> -{ +impl<'tcx> Stable<'tcx> for rustc_abi::LayoutData<rustc_abi::FieldIdx, rustc_abi::VariantIdx> { type T = LayoutShape; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { LayoutShape { fields: self.fields.stable(tables), variants: self.variants.stable(tables), - abi: self.abi.stable(tables), + abi: self.backend_repr.stable(tables), abi_align: self.align.abi.stable(tables), size: self.size.stable(tables), } } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> { +impl<'tcx> Stable<'tcx> for callconv::FnAbi<'tcx, ty::Ty<'tcx>> { type T = FnAbi; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -81,7 +79,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> { } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> { +impl<'tcx> Stable<'tcx> for callconv::ArgAbi<'tcx, ty::Ty<'tcx>> { type T = ArgAbi; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -93,7 +91,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv { +impl<'tcx> Stable<'tcx> for callconv::Conv { type T = CallConvention; fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { @@ -122,31 +120,29 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv { } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode { +impl<'tcx> Stable<'tcx> for callconv::PassMode { type T = PassMode; fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { match self { - rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore, - rustc_target::abi::call::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)), - rustc_target::abi::call::PassMode::Pair(first, second) => { + callconv::PassMode::Ignore => PassMode::Ignore, + callconv::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)), + callconv::PassMode::Pair(first, second) => { PassMode::Pair(opaque(first), opaque(second)) } - rustc_target::abi::call::PassMode::Cast { pad_i32, cast } => { + callconv::PassMode::Cast { pad_i32, cast } => { PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) } } - rustc_target::abi::call::PassMode::Indirect { attrs, meta_attrs, on_stack } => { - PassMode::Indirect { - attrs: opaque(attrs), - meta_attrs: opaque(meta_attrs), - on_stack: *on_stack, - } - } + callconv::PassMode::Indirect { attrs, meta_attrs, on_stack } => PassMode::Indirect { + attrs: opaque(attrs), + meta_attrs: opaque(meta_attrs), + on_stack: *on_stack, + }, } } } -impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_target::abi::FieldIdx> { +impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_abi::FieldIdx> { type T = FieldsShape; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -163,9 +159,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_target::abi::FieldIdx> } } -impl<'tcx> Stable<'tcx> - for rustc_abi::Variants<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx> -{ +impl<'tcx> Stable<'tcx> for rustc_abi::Variants<rustc_abi::FieldIdx, rustc_abi::VariantIdx> { type T = VariantsShape; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -185,7 +179,7 @@ impl<'tcx> Stable<'tcx> } } -impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_target::abi::VariantIdx> { +impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_abi::VariantIdx> { type T = TagEncoding; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { @@ -202,20 +196,20 @@ impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_target::abi::VariantIdx } } -impl<'tcx> Stable<'tcx> for rustc_abi::Abi { +impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr { type T = ValueAbi; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match *self { - rustc_abi::Abi::Uninhabited => ValueAbi::Uninhabited, - rustc_abi::Abi::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)), - rustc_abi::Abi::ScalarPair(first, second) => { + rustc_abi::BackendRepr::Uninhabited => ValueAbi::Uninhabited, + rustc_abi::BackendRepr::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)), + rustc_abi::BackendRepr::ScalarPair(first, second) => { ValueAbi::ScalarPair(first.stable(tables), second.stable(tables)) } - rustc_abi::Abi::Vector { element, count } => { + rustc_abi::BackendRepr::Vector { element, count } => { ValueAbi::Vector { element: element.stable(tables), count } } - rustc_abi::Abi::Aggregate { sized } => ValueAbi::Aggregate { sized }, + rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized }, } } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index dbae4b7e719..820d8a6be25 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -691,11 +691,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::Allocation { type T = stable_mir::ty::Allocation; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - alloc::allocation_filter( - self, - alloc_range(rustc_target::abi::Size::ZERO, self.size()), - tables, - ) + alloc::allocation_filter(self, alloc_range(rustc_abi::Size::ZERO, self.size()), tables) } } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 9b27b94fb5a..9032156b257 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -36,7 +36,7 @@ pub struct Tables<'tcx> { pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>, pub(crate) ty_consts: IndexMap<ty::Const<'tcx>, TyConstId>, pub(crate) mir_consts: IndexMap<mir::Const<'tcx>, MirConstId>, - pub(crate) layouts: IndexMap<rustc_target::abi::Layout<'tcx>, Layout>, + pub(crate) layouts: IndexMap<rustc_abi::Layout<'tcx>, Layout>, } impl<'tcx> Tables<'tcx> { diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs index 26aa782e5d7..9f977b98b82 100644 --- a/compiler/rustc_span/src/caching_source_map_view.rs +++ b/compiler/rustc_span/src/caching_source_map_view.rs @@ -63,7 +63,7 @@ pub struct CachingSourceMapView<'sm> { impl<'sm> CachingSourceMapView<'sm> { pub fn new(source_map: &'sm SourceMap) -> CachingSourceMapView<'sm> { let files = source_map.files(); - let first_file = files[0].clone(); + let first_file = Lrc::clone(&files[0]); let entry = CacheEntry { time_stamp: 0, line_number: 0, @@ -92,7 +92,7 @@ impl<'sm> CachingSourceMapView<'sm> { cache_entry.touch(self.time_stamp); let col = RelativeBytePos(pos.to_u32() - cache_entry.line.start.to_u32()); - return Some((cache_entry.file.clone(), cache_entry.line_number, col)); + return Some((Lrc::clone(&cache_entry.file), cache_entry.line_number, col)); } // No cache hit ... @@ -109,7 +109,7 @@ impl<'sm> CachingSourceMapView<'sm> { cache_entry.update(new_file_and_idx, pos, self.time_stamp); let col = RelativeBytePos(pos.to_u32() - cache_entry.line.start.to_u32()); - Some((cache_entry.file.clone(), cache_entry.line_number, col)) + Some((Lrc::clone(&cache_entry.file), cache_entry.line_number, col)) } pub fn span_data_to_lines_and_cols( @@ -133,7 +133,7 @@ impl<'sm> CachingSourceMapView<'sm> { } ( - lo.file.clone(), + Lrc::clone(&lo.file), lo.line_number, span_data.lo - lo.line.start, hi.line_number, @@ -181,7 +181,7 @@ impl<'sm> CachingSourceMapView<'sm> { lo.update(new_file_and_idx, span_data.lo, self.time_stamp); if !lo.line.contains(&span_data.hi) { - let new_file_and_idx = Some((lo.file.clone(), lo.file_index)); + let new_file_and_idx = Some((Lrc::clone(&lo.file), lo.file_index)); let next_oldest = self.oldest_cache_entry_index_avoid(oldest); let hi = &mut self.line_cache[next_oldest]; hi.update(new_file_and_idx, span_data.hi, self.time_stamp); @@ -227,7 +227,7 @@ impl<'sm> CachingSourceMapView<'sm> { assert_eq!(lo.file_index, hi.file_index); Some(( - lo.file.clone(), + Lrc::clone(&lo.file), lo.line_number, span_data.lo - lo.line.start, hi.line_number, @@ -277,7 +277,7 @@ impl<'sm> CachingSourceMapView<'sm> { let file = &self.source_map.files()[file_idx]; if file_contains(file, pos) { - return Some((file.clone(), file_idx)); + return Some((Lrc::clone(file), file_idx)); } } diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 8a023305937..f36bb38623e 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -286,8 +286,8 @@ impl SourceMap { }); let file = Lrc::new(file); - files.source_files.push(file.clone()); - files.stable_id_to_source_file.insert(file_id, file.clone()); + files.source_files.push(Lrc::clone(&file)); + files.stable_id_to_source_file.insert(file_id, Lrc::clone(&file)); Ok(file) } @@ -386,7 +386,7 @@ impl SourceMap { /// Return the SourceFile that contains the given `BytePos` pub fn lookup_source_file(&self, pos: BytePos) -> Lrc<SourceFile> { let idx = self.lookup_source_file_idx(pos); - (*self.files.borrow().source_files)[idx].clone() + Lrc::clone(&(*self.files.borrow().source_files)[idx]) } /// Looks up source information about a `BytePos`. @@ -468,7 +468,7 @@ impl SourceMap { if lo != hi { return true; } - let f = (*self.files.borrow().source_files)[lo].clone(); + let f = Lrc::clone(&(*self.files.borrow().source_files)[lo]); let lo = f.relative_position(sp.lo()); let hi = f.relative_position(sp.hi()); f.lookup_line(lo) != f.lookup_line(hi) @@ -994,7 +994,7 @@ impl SourceMap { let filename = self.path_mapping().map_filename_prefix(filename).0; for sf in self.files.borrow().source_files.iter() { if filename == sf.name { - return Some(sf.clone()); + return Some(Lrc::clone(&sf)); } } None @@ -1003,7 +1003,7 @@ impl SourceMap { /// For a global `BytePos`, computes the local offset within the containing `SourceFile`. pub fn lookup_byte_offset(&self, bpos: BytePos) -> SourceFileAndBytePos { let idx = self.lookup_source_file_idx(bpos); - let sf = (*self.files.borrow().source_files)[idx].clone(); + let sf = Lrc::clone(&(*self.files.borrow().source_files)[idx]); let offset = bpos - sf.start_pos; SourceFileAndBytePos { sf, pos: offset } } diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 65aa9e40c8b..644e710d1db 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" # tidy-alphabetical-start punycode = "0.4.0" rustc-demangle = "0.1.21" + +rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index d092fa8f082..868345c7594 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -2,6 +2,7 @@ use std::fmt::Write; use std::iter; use std::ops::Range; +use rustc_abi::Integer; use rustc_data_structures::base_n::ToBaseN; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; @@ -17,7 +18,6 @@ use rustc_middle::ty::{ TyCtxt, TypeVisitable, TypeVisitableExt, UintTy, }; use rustc_span::symbol::kw; -use rustc_target::abi::Integer; use rustc_target::spec::abi::Abi; pub(super) fn mangle<'tcx>( diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index ffec76370d0..d1234c3cc91 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -1,5 +1,7 @@ use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; -use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; +use crate::abi::{ + self, BackendRepr, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout, +}; use crate::spec::HasTargetSpec; use crate::spec::abi::Abi as SpecAbi; @@ -21,8 +23,8 @@ enum FloatConv { struct CannotUseFpConv; fn is_loongarch_aggregate<Ty>(arg: &ArgAbi<'_, Ty>) -> bool { - match arg.layout.abi { - Abi::Vector { .. } => true, + match arg.layout.backend_repr { + BackendRepr::Vector { .. } => true, _ => arg.layout.is_aggregate(), } } @@ -38,8 +40,8 @@ fn should_use_fp_conv_helper<'a, Ty, C>( where Ty: TyAbiInterface<'a, C> + Copy, { - match arg_layout.abi { - Abi::Scalar(scalar) => match scalar.primitive() { + match arg_layout.backend_repr { + BackendRepr::Scalar(scalar) => match scalar.primitive() { abi::Int(..) | abi::Pointer(_) => { if arg_layout.size.bits() > xlen { return Err(CannotUseFpConv); @@ -77,8 +79,8 @@ where } } }, - Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv), - Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields { + BackendRepr::Vector { .. } | BackendRepr::Uninhabited => return Err(CannotUseFpConv), + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") } @@ -311,7 +313,7 @@ fn classify_arg<'a, Ty, C>( } fn extend_integer_width<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64) { - if let Abi::Scalar(scalar) = arg.layout.abi { + if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr { if let abi::Int(i, _) = scalar.primitive() { // 32-bit integers are always sign-extended if i.size().bits() == 32 && xlen > 32 { diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index 2c3258c8d42..5bdf4c2ad77 100644 --- a/compiler/rustc_target/src/callconv/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs @@ -5,7 +5,7 @@ use crate::abi::{self, HasDataLayout, Size, TyAbiInterface}; fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) { // Always sign extend u32 values on 64-bit mips - if let abi::Abi::Scalar(scalar) = arg.layout.abi { + if let abi::BackendRepr::Scalar(scalar) = arg.layout.backend_repr { if let abi::Int(i, signed) = scalar.primitive() { if !signed && i.size().bits() == 32 { if let PassMode::Direct(ref mut attrs) = arg.mode { @@ -24,8 +24,8 @@ where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { - match ret.layout.field(cx, i).abi { - abi::Abi::Scalar(scalar) => match scalar.primitive() { + match ret.layout.field(cx, i).backend_repr { + abi::BackendRepr::Scalar(scalar) => match scalar.primitive() { abi::Float(abi::F32) => Some(Reg::f32()), abi::Float(abi::F64) => Some(Reg::f64()), _ => None, @@ -109,7 +109,7 @@ where let offset = arg.layout.fields.offset(i); // We only care about aligned doubles - if let abi::Abi::Scalar(scalar) = field.abi { + if let abi::BackendRepr::Scalar(scalar) = field.backend_repr { if scalar.primitive() == abi::Float(abi::F64) { if offset.is_aligned(dl.f64_align.abi) { // Insert enough integers to cover [last_offset, offset) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 25b001b57e8..8c3df9c426b 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -6,7 +6,8 @@ use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use crate::abi::{ - self, Abi, AddressSpace, Align, HasDataLayout, Pointer, Size, TyAbiInterface, TyAndLayout, + self, AddressSpace, Align, BackendRepr, HasDataLayout, Pointer, Size, TyAbiInterface, + TyAndLayout, }; use crate::spec::abi::Abi as SpecAbi; use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi}; @@ -350,15 +351,17 @@ impl<'a, Ty> ArgAbi<'a, Ty> { layout: TyAndLayout<'a, Ty>, scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, abi::Scalar, Size) -> ArgAttributes, ) -> Self { - let mode = match layout.abi { - Abi::Uninhabited => PassMode::Ignore, - Abi::Scalar(scalar) => PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)), - Abi::ScalarPair(a, b) => PassMode::Pair( + let mode = match layout.backend_repr { + BackendRepr::Uninhabited => PassMode::Ignore, + BackendRepr::Scalar(scalar) => { + PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)) + } + BackendRepr::ScalarPair(a, b) => PassMode::Pair( scalar_attrs(&layout, a, Size::ZERO), scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)), ), - Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()), - Abi::Aggregate { .. } => Self::indirect_pass_mode(&layout), + BackendRepr::Vector { .. } => PassMode::Direct(ArgAttributes::new()), + BackendRepr::Memory { .. } => Self::indirect_pass_mode(&layout), }; ArgAbi { layout, mode } } @@ -460,7 +463,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { pub fn extend_integer_width_to(&mut self, bits: u64) { // Only integers have signedness - if let Abi::Scalar(scalar) = self.layout.abi { + if let BackendRepr::Scalar(scalar) = self.layout.backend_repr { if let abi::Int(i, signed) = scalar.primitive() { if i.size().bits() < bits { if let PassMode::Direct(ref mut attrs) = self.mode { @@ -512,7 +515,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { // That elevates any type difference to an ABI difference since we just use the // full Rust type as the LLVM argument/return type. if matches!(self.mode, PassMode::Direct(..)) - && matches!(self.layout.abi, Abi::Aggregate { .. }) + && matches!(self.layout.backend_repr, BackendRepr::Memory { .. }) { // For aggregates in `Direct` mode to be compatible, the types need to be equal. self.layout.ty == other.layout.ty @@ -791,8 +794,8 @@ impl<'a, Ty> FnAbi<'a, Ty> { continue; } - match arg.layout.abi { - Abi::Aggregate { .. } => {} + match arg.layout.backend_repr { + BackendRepr::Memory { .. } => {} // This is a fun case! The gist of what this is doing is // that we want callers and callees to always agree on the @@ -813,7 +816,9 @@ impl<'a, Ty> FnAbi<'a, Ty> { // Note that the intrinsic ABI is exempt here as // that's how we connect up to LLVM and it's unstable // anyway, we control all calls to it in libstd. - Abi::Vector { .. } if abi != SpecAbi::RustIntrinsic && spec.simd_types_indirect => { + BackendRepr::Vector { .. } + if abi != SpecAbi::RustIntrinsic && spec.simd_types_indirect => + { arg.make_indirect(); continue; } diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index f96169e6a61..c0298edb5ab 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -4,8 +4,10 @@ // Reference: Clang RISC-V ELF psABI lowering code // https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773 +use rustc_abi::{BackendRepr, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; + +use crate::abi; use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; -use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; use crate::spec::HasTargetSpec; use crate::spec::abi::Abi as SpecAbi; @@ -27,8 +29,8 @@ enum FloatConv { struct CannotUseFpConv; fn is_riscv_aggregate<Ty>(arg: &ArgAbi<'_, Ty>) -> bool { - match arg.layout.abi { - Abi::Vector { .. } => true, + match arg.layout.backend_repr { + BackendRepr::Vector { .. } => true, _ => arg.layout.is_aggregate(), } } @@ -44,8 +46,8 @@ fn should_use_fp_conv_helper<'a, Ty, C>( where Ty: TyAbiInterface<'a, C> + Copy, { - match arg_layout.abi { - Abi::Scalar(scalar) => match scalar.primitive() { + match arg_layout.backend_repr { + BackendRepr::Scalar(scalar) => match scalar.primitive() { abi::Int(..) | abi::Pointer(_) => { if arg_layout.size.bits() > xlen { return Err(CannotUseFpConv); @@ -83,8 +85,8 @@ where } } }, - Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv), - Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields { + BackendRepr::Vector { .. } | BackendRepr::Uninhabited => return Err(CannotUseFpConv), + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") } @@ -317,7 +319,7 @@ fn classify_arg<'a, Ty, C>( } fn extend_integer_width<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64) { - if let Abi::Scalar(scalar) = arg.layout.abi { + if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr { if let abi::Int(i, _) = scalar.primitive() { // 32-bit integers are always sign-extended if i.size().bits() == 32 && xlen > 32 { diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index 835353f76fc..313d8730399 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -109,11 +109,11 @@ where return data; } - match layout.abi { - abi::Abi::Scalar(scalar) => { + match layout.backend_repr { + abi::BackendRepr::Scalar(scalar) => { data = arg_scalar(cx, &scalar, offset, data); } - abi::Abi::Aggregate { .. } => { + abi::BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { if offset < layout.fields.offset(i) { offset = layout.fields.offset(i); @@ -122,7 +122,7 @@ where } } _ => { - if let abi::Abi::ScalarPair(scalar1, scalar2) = &layout.abi { + if let abi::BackendRepr::ScalarPair(scalar1, scalar2) = &layout.backend_repr { data = arg_scalar_pair(cx, scalar1, scalar2, offset, data); } } diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index e907beecb38..a5af975d4d2 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -1,6 +1,6 @@ use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind}; use crate::abi::{ - Abi, AddressSpace, Align, Float, HasDataLayout, Pointer, TyAbiInterface, TyAndLayout, + AddressSpace, Align, BackendRepr, Float, HasDataLayout, Pointer, TyAbiInterface, TyAndLayout, }; use crate::spec::HasTargetSpec; use crate::spec::abi::Abi as SpecAbi; @@ -105,10 +105,12 @@ where where Ty: TyAbiInterface<'a, C> + Copy, { - match layout.abi { - Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) => false, - Abi::Vector { .. } => true, - Abi::Aggregate { .. } => { + match layout.backend_repr { + BackendRepr::Uninhabited + | BackendRepr::Scalar(_) + | BackendRepr::ScalarPair(..) => false, + BackendRepr::Vector { .. } => true, + BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { if contains_vector(cx, layout.field(cx, i)) { return true; @@ -223,9 +225,9 @@ where // Intrinsics themselves are not actual "real" functions, so theres no need to change their ABIs. && abi != SpecAbi::RustIntrinsic { - let has_float = match fn_abi.ret.layout.abi { - Abi::Scalar(s) => matches!(s.primitive(), Float(_)), - Abi::ScalarPair(s1, s2) => { + let has_float = match fn_abi.ret.layout.backend_repr { + BackendRepr::Scalar(s) => matches!(s.primitive(), Float(_)), + BackendRepr::ScalarPair(s1, s2) => { matches!(s1.primitive(), Float(_)) || matches!(s2.primitive(), Float(_)) } _ => false, // anyway not passed via registers on x86 diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index 9910e623ac9..bd101b23ea1 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -1,8 +1,10 @@ // The classification code for the x86_64 ABI is taken from the clay language // https://github.com/jckarter/clay/blob/db0bd2702ab0b6e48965cd85f8859bbd5f60e48e/compiler/externals.cpp +use rustc_abi::{BackendRepr, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; + +use crate::abi; use crate::abi::call::{ArgAbi, CastTarget, FnAbi, Reg, RegKind}; -use crate::abi::{self, Abi, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; /// Classification of "eightbyte" components. // N.B., the order of the variants is from general to specific, @@ -46,17 +48,17 @@ where return Ok(()); } - let mut c = match layout.abi { - Abi::Uninhabited => return Ok(()), + let mut c = match layout.backend_repr { + BackendRepr::Uninhabited => return Ok(()), - Abi::Scalar(scalar) => match scalar.primitive() { + BackendRepr::Scalar(scalar) => match scalar.primitive() { abi::Int(..) | abi::Pointer(_) => Class::Int, abi::Float(_) => Class::Sse, }, - Abi::Vector { .. } => Class::Sse, + BackendRepr::Vector { .. } => Class::Sse, - Abi::ScalarPair(..) | Abi::Aggregate { .. } => { + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { let field_off = off + layout.fields.offset(i); classify(cx, layout.field(cx, i), cls, field_off)?; diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index e5a20b248e4..83d94cb11ba 100644 --- a/compiler/rustc_target/src/callconv/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs @@ -1,25 +1,28 @@ +use rustc_abi::{BackendRepr, Float, Primitive}; + use crate::abi::call::{ArgAbi, FnAbi, Reg}; -use crate::abi::{Abi, Float, Primitive}; use crate::spec::HasTargetSpec; // Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) { let fixup = |a: &mut ArgAbi<'_, Ty>| { - match a.layout.abi { - Abi::Uninhabited | Abi::Aggregate { sized: false } => {} - Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => match a.layout.size.bits() { - 8 => a.cast_to(Reg::i8()), - 16 => a.cast_to(Reg::i16()), - 32 => a.cast_to(Reg::i32()), - 64 => a.cast_to(Reg::i64()), - _ => a.make_indirect(), - }, - Abi::Vector { .. } => { + match a.layout.backend_repr { + BackendRepr::Uninhabited | BackendRepr::Memory { sized: false } => {} + BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { + match a.layout.size.bits() { + 8 => a.cast_to(Reg::i8()), + 16 => a.cast_to(Reg::i16()), + 32 => a.cast_to(Reg::i32()), + 64 => a.cast_to(Reg::i64()), + _ => a.make_indirect(), + } + } + BackendRepr::Vector { .. } => { // FIXME(eddyb) there should be a size cap here // (probably what clang calls "illegal vectors"). } - Abi::Scalar(scalar) => { + BackendRepr::Scalar(scalar) => { // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up // with what LLVM expects. if a.layout.size.bytes() > 8 diff --git a/compiler/rustc_target/src/callconv/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs index e1728b08a39..9d313d16500 100644 --- a/compiler/rustc_target/src/callconv/xtensa.rs +++ b/compiler/rustc_target/src/callconv/xtensa.rs @@ -6,7 +6,7 @@ //! Section 2.3 from the Xtensa programmers guide. use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform}; -use crate::abi::{Abi, HasDataLayout, Size, TyAbiInterface}; +use crate::abi::{BackendRepr, HasDataLayout, Size, TyAbiInterface}; use crate::spec::HasTargetSpec; const NUM_ARG_GPRS: u64 = 6; @@ -114,8 +114,8 @@ where } fn is_xtensa_aggregate<'a, Ty>(arg: &ArgAbi<'a, Ty>) -> bool { - match arg.layout.abi { - Abi::Vector { .. } => true, + match arg.layout.backend_repr { + BackendRepr::Vector { .. } => true, _ => arg.layout.is_aggregate(), } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f4cbe47e0f3..3e7b42d3d1c 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -55,9 +55,15 @@ use crate::json::{Json, ToJson}; use crate::spec::abi::Abi; use crate::spec::crt_objects::CrtObjects; -pub mod abi; pub mod crt_objects; +pub mod abi { + pub use rustc_abi::{ + AbiDisabled, AbiUnsupported, ExternAbi as Abi, all_names, enabled_names, is_enabled, + is_stable, lookup, + }; +} + mod base; pub use base::apple::{ deployment_target_for_target as current_apple_deployment_target, diff --git a/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs b/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs index c60bf650311..1b8f9b71e93 100644 --- a/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs +++ b/compiler/rustc_target/src/spec/targets/mipsel_sony_psx.rs @@ -14,8 +14,11 @@ pub(crate) fn target() -> Target { arch: "mips".into(), options: TargetOptions { - os: "none".into(), - env: "psx".into(), + // The Playstation 1 is mostly bare-metal, but the BIOS does provide some a slight bit + // of functionality post load, so we still declare it as `cfg!(target_os = "psx")`. + // + // See <https://github.com/rust-lang/rust/pull/131168> for details. + os: "psx".into(), vendor: "sony".into(), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), cpu: "mips1".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs index 7d089aeb787..ac2141f9b08 100644 --- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_linux_gnu.rs @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-i64:64-n32:64-S128".into(), + data_layout: "E-m:e-i64:64-i128:128-n32:64-S128".into(), arch: "sparc64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs index 21f09d6428e..d16b3776cfb 100644 --- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_netbsd.rs @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-i64:64-n32:64-S128".into(), + data_layout: "E-m:e-i64:64-i128:128-n32:64-S128".into(), arch: "sparc64".into(), options: TargetOptions { endian: Endian::Big, mcount: "__mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs index 12626dce477..91e64061020 100644 --- a/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/sparc64_unknown_openbsd.rs @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-i64:64-n32:64-S128".into(), + data_layout: "E-m:e-i64:64-i128:128-n32:64-S128".into(), arch: "sparc64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs index 08f0bb302dd..2777395757f 100644 --- a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs @@ -11,7 +11,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 32, - data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".into(), + data_layout: "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64".into(), arch: "sparc".into(), options: TargetOptions { cpu: "v9".into(), diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs index 0157d03f854..987f69429c0 100644 --- a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { ..Default::default() }; Target { - data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".into(), + data_layout: "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64".into(), llvm_target: "sparc-unknown-none-elf".into(), metadata: crate::spec::TargetMetadata { description: Some("Bare 32-bit SPARC V7+".into()), diff --git a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs index 138ce902d5e..fdc9628f78e 100644 --- a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-i64:64-n32:64-S128".into(), + data_layout: "E-m:e-i64:64-i128:128-n32:64-S128".into(), // Use "sparc64" instead of "sparcv9" here, since the former is already // used widely in the source base. If we ever needed ABI // differentiation from the sparc64, we could, but that would probably diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index cc5931be860..bd47d12ef9f 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -165,7 +165,8 @@ impl Target { assert_matches!(&*self.llvm_abiname, "ilp32" | "ilp32f" | "ilp32d" | "ilp32e") } "riscv64" => { - assert_matches!(&*self.llvm_abiname, "lp64" | "lp64f" | "lp64d" | "lp64q") + // Note that the `lp64e` is still unstable as it's not (yet) part of the ELF psABI. + assert_matches!(&*self.llvm_abiname, "lp64" | "lp64f" | "lp64d" | "lp64q" | "lp64e") } _ => {} } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index a6474f10d5b..af3b5e0d5d4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -551,10 +551,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ] => "", [ .., - Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), - target: _, - }, + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(mut_)), target: _ }, ] => hir::Mutability::from(*mut_).ref_prefix_str(), _ => "", }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 8541621b23b..2b19db2c14e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -284,7 +284,7 @@ pub fn suggest_new_region_bound( } match fn_return.kind { // FIXME(precise_captures): Suggest adding to `use<...>` list instead. - TyKind::OpaqueDef(opaque, _) => { + TyKind::OpaqueDef(opaque) => { // Get the identity type for this RPIT let did = opaque.def_id.to_def_id(); let ty = Ty::new_opaque(tcx, did, ty::GenericArgs::identity_for_item(tcx, did)); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 0cf7c43beb5..b97f3dc303b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -384,7 +384,10 @@ impl<T> Trait<T> for X { | DefKind::AssocFn | DefKind::AssocConst ) - && tcx.is_type_alias_impl_trait(opaque_ty.def_id) + && matches!( + tcx.opaque_ty_origin(opaque_ty.def_id), + hir::OpaqueTyOrigin::TyAlias { .. } + ) && !tcx .opaque_types_defined_by(body_owner_def_id.expect_local()) .contains(&opaque_ty.def_id.expect_local()) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 833358b2e14..438639e72f9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -862,22 +862,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.add_lt_suggs.push(lt.suggestion(self.new_lt)); } } - - fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) { - let hir::TyKind::OpaqueDef(opaque_ty, _) = ty.kind else { - return hir::intravisit::walk_ty(self, ty); - }; - if let Some(&(_, b)) = - opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle) - { - let prev_needle = - std::mem::replace(&mut self.needle, hir::LifetimeName::Param(b)); - for bound in opaque_ty.bounds { - self.visit_param_bound(bound); - } - self.needle = prev_needle; - } - } } let (lifetime_def_id, lifetime_scope) = 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 6014ed555b6..7aa558cfd3f 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 @@ -545,10 +545,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { polarity: ty::PredicatePolarity::Positive, }), None, - Some(match predicate.host { - ty::HostPolarity::Maybe => ty::BoundConstness::ConstIfConst, - ty::HostPolarity::Const => ty::BoundConstness::Const, - }), + Some(predicate.constness), None, String::new(), ); @@ -2238,18 +2235,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (None, _) => Some(cannot_do_this), // suggested using default post message ( - Some(ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst), + Some(ty::BoundConstness::Const | ty::BoundConstness::Maybe), Some(AppendConstMessage::Default), ) => Some(format!("{cannot_do_this} in const contexts")), // overridden post message ( - Some(ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst), + Some(ty::BoundConstness::Const | ty::BoundConstness::Maybe), Some(AppendConstMessage::Custom(custom_msg, _)), ) => Some(format!("{cannot_do_this}{custom_msg}")), // fallback to generic message - (Some(ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst), None) => { - None - } + (Some(ty::BoundConstness::Const | ty::BoundConstness::Maybe), None) => None, } }) .unwrap_or_else(|| { @@ -2653,7 +2648,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, def_id: DefId, ) -> ErrorGuaranteed { - let name = match self.tcx.opaque_type_origin(def_id.expect_local()) { + let name = match self.tcx.local_opaque_ty_origin(def_id.expect_local()) { hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } => { "opaque type".to_string() } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index a7d1f1bd8d0..553bb61ed04 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -361,7 +361,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) | hir::Node::TraitItem(hir::TraitItem { generics, .. }) | hir::Node::ImplItem(hir::ImplItem { generics, .. }) - | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. }) if param_ty => { // We skip the 0'th arg (self) because we do not want @@ -424,10 +423,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::TraitAlias(generics, _), .. - }) - | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. }) - if !param_ty => - { + }) if !param_ty => { // Missing generic type parameter bound. if suggest_arbitrary_trait_bound( self.tcx, @@ -5105,24 +5101,13 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( _ => None, }; - let pred = obligation.predicate; - let (_, base) = obligation.cause.code().peel_derives_with_predicate(); - let post = if let ty::PredicateKind::Clause(clause) = pred.kind().skip_binder() - && let ty::ClauseKind::Trait(pred) = clause - && let Some(base) = base - && base.skip_binder() != pred - { - format!(", which is required by `{base}`") - } else { - String::new() - }; let desc = match ty_desc { Some(desc) => format!(" {desc}"), None => String::new(), }; if let ty::PredicatePolarity::Positive = trait_predicate.polarity() { format!( - "{pre_message}the trait `{}` is not implemented for{desc} `{}`{post}", + "{pre_message}the trait `{}` is not implemented for{desc} `{}`", trait_predicate.print_modifiers_and_trait_path(), tcx.short_ty_string(trait_predicate.self_ty().skip_binder(), &mut None), ) @@ -5130,7 +5115,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( // "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is // not implemented for `T`". // FIXME: add note explaining explicit negative trait bounds. - format!("{pre_message}the trait bound `{trait_predicate}` is not satisfied{post}") + format!("{pre_message}the trait bound `{trait_predicate}` is not satisfied") } } } @@ -5237,12 +5222,6 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>( let ty::ClauseKind::Projection(proj) = clause else { return; }; - // avoid ICEing since effects desugared associated types don't have names. - // this path should only be hit for `~const` on invalid places, so they - // will have an informative error already. - if tcx.is_effects_desugared_assoc_ty(proj.projection_term.def_id) { - return; - } let name = tcx.item_name(proj.projection_term.def_id); let mut predicates = generics.predicates.iter().peekable(); let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None; diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 5793ac2fc31..c53689b211d 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -7,13 +7,13 @@ use rustc_infer::infer::canonical::{ Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues, }; use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::traits::ObligationCause; use rustc_infer::traits::solve::Goal; -use rustc_infer::traits::{ObligationCause, Reveal}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; -use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode}; -use tracing::trace; +use rustc_type_ir::TypingMode; +use rustc_type_ir::solve::{Certainty, NoSolution}; use crate::traits::specialization_graph; @@ -47,7 +47,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn build_with_canonical<V>( interner: TyCtxt<'tcx>, - solver_mode: SolverMode, canonical: &CanonicalQueryInput<'tcx, V>, ) -> (Self, V, CanonicalVarValues<'tcx>) where @@ -56,10 +55,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< let (infcx, value, vars) = interner .infer_ctxt() .with_next_trait_solver(true) - .intercrate(match solver_mode { - SolverMode::Normal => false, - SolverMode::Coherence => true, - }) .build_with_canonical(DUMMY_SP, canonical); (SolverDelegate(infcx), value, vars) } @@ -195,7 +190,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn fetch_eligible_assoc_item( &self, - param_env: ty::ParamEnv<'tcx>, goal_trait_ref: ty::TraitRef<'tcx>, trait_assoc_def_id: DefId, impl_def_id: DefId, @@ -211,12 +205,12 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< // and the obligation is monomorphic, otherwise passes such as // transmute checking and polymorphic MIR optimizations could // get a result which isn't correct for all monomorphizations. - if param_env.reveal() == Reveal::All { - let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); - !poly_trait_ref.still_further_specializable() - } else { - trace!(?node_item.item.def_id, "not eligible due to default"); - false + match self.typing_mode_unchecked() { + TypingMode::Coherence | TypingMode::Analysis { .. } => false, + TypingMode::PostAnalysis => { + let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); + !poly_trait_ref.still_further_specializable() + } } }; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 934fe9ec47c..52ba5621d31 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -10,6 +10,7 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::{Region, RegionVid}; use tracing::debug; +use ty::TypingMode; use super::*; use crate::errors::UnableToConstructConstantValue; @@ -79,7 +80,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let trait_ref = ty::TraitRef::new(tcx, trait_did, [ty]); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut selcx = SelectionContext::new(&infcx); for polarity in [ty::PredicatePolarity::Positive, ty::PredicatePolarity::Negative] { let result = selcx.select(&Obligation::new( @@ -99,7 +100,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } } - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut fresh_preds = FxIndexSet::default(); // Due to the way projections are handled by SelectionContext, we need to run diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index f8fb297e36c..3cd11d7c8e8 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -18,7 +18,7 @@ use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; pub use rustc_next_trait_solver::coherence::*; use rustc_next_trait_solver::solve::SolverDelegateEvalExt; use rustc_span::symbol::sym; @@ -195,9 +195,8 @@ fn overlap<'tcx>( let infcx = tcx .infer_ctxt() .skip_leak_check(skip_leak_check.is_yes()) - .intercrate(true) .with_next_trait_solver(tcx.next_trait_solver_in_coherence()) - .build(); + .build(TypingMode::Coherence); let selcx = &mut SelectionContext::new(&infcx); if track_ambiguity_causes.is_yes() { selcx.enable_tracking_intercrate_ambiguity_causes(); @@ -419,7 +418,7 @@ fn impl_intersection_has_negative_obligation( // N.B. We need to unify impl headers *with* intercrate mode, even if proving negative predicates // do not need intercrate mode enabled. - let ref infcx = tcx.infer_ctxt().intercrate(true).with_next_trait_solver(true).build(); + let ref infcx = tcx.infer_ctxt().with_next_trait_solver(true).build(TypingMode::Coherence); let root_universe = infcx.universe(); assert_eq!(root_universe, ty::UniverseIndex::ROOT); @@ -570,7 +569,9 @@ fn try_prove_negated_where_clause<'tcx>( // the *existence* of a negative goal, not the non-existence of a positive goal. // Without this, we over-eagerly register coherence ambiguity candidates when // impl candidates do exist. - let ref infcx = root_infcx.fork_with_intercrate(false); + // FIXME(#132279): `TypingMode::non_body_analysis` is a bit questionable here as it + // would cause us to reveal opaque types to leak their auto traits. + let ref infcx = root_infcx.fork_with_typing_mode(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new(infcx); ocx.register_obligation(Obligation::new( infcx.tcx, @@ -714,7 +715,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { // It is only relevant that a goal is unknowable if it would have otherwise // failed. - let non_intercrate_infcx = infcx.fork_with_intercrate(false); + // FIXME(#132279): Forking with `TypingMode::non_body_analysis` is a bit questionable + // as it would allow us to reveal opaque types, potentially causing unexpected + // cycles. + let non_intercrate_infcx = infcx.fork_with_typing_mode(TypingMode::non_body_analysis()); if non_intercrate_infcx.predicate_may_hold(&Obligation::new( infcx.tcx, ObligationCause::dummy(), diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index a068f25fe35..0eaacbcfbea 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -14,11 +14,11 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{ self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, Upcast, + TypeVisitableExt, TypeVisitor, TypingMode, Upcast, }; use rustc_span::Span; use rustc_span::symbol::Symbol; -use rustc_target::abi::Abi; +use rustc_target::abi::BackendRepr; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -523,8 +523,8 @@ fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: // e.g., `Rc<()>` let unit_receiver_ty = receiver_for_self_ty(tcx, receiver_ty, tcx.types.unit, method_def_id); - match tcx.layout_of(param_env.and(unit_receiver_ty)).map(|l| l.abi) { - Ok(Abi::Scalar(..)) => (), + match tcx.layout_of(param_env.and(unit_receiver_ty)).map(|l| l.backend_repr) { + Ok(BackendRepr::Scalar(..)) => (), abi => { tcx.dcx().span_delayed_bug( tcx.def_span(method_def_id), @@ -538,8 +538,8 @@ fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: // e.g., `Rc<dyn Trait>` let trait_object_receiver = receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method_def_id); - match tcx.layout_of(param_env.and(trait_object_receiver)).map(|l| l.abi) { - Ok(Abi::ScalarPair(..)) => (), + match tcx.layout_of(param_env.and(trait_object_receiver)).map(|l| l.backend_repr) { + Ok(BackendRepr::ScalarPair(..)) => (), abi => { tcx.dcx().span_delayed_bug( tcx.def_span(method_def_id), @@ -718,7 +718,7 @@ fn receiver_is_dispatchable<'tcx>( Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate) }; - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); // the receiver is dispatchable iff the obligation holds infcx.predicate_must_hold_modulo_regions(&obligation) } diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs new file mode 100644 index 00000000000..cb36f1a62db --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -0,0 +1,154 @@ +use rustc_hir as hir; +use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt}; +use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation}; +use rustc_middle::span_bug; +use rustc_middle::ty::fast_reject::DeepRejectCtxt; +use rustc_middle::ty::{self, TypingMode}; +use rustc_type_ir::solve::NoSolution; +use thin_vec::ThinVec; + +use super::SelectionContext; + +pub type HostEffectObligation<'tcx> = Obligation<'tcx, ty::HostEffectPredicate<'tcx>>; + +pub enum EvaluationFailure { + Ambiguous, + NoSolution, +} + +pub fn evaluate_host_effect_obligation<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { + if matches!(selcx.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) { + span_bug!( + obligation.cause.span, + "should not select host obligation in old solver in intercrate mode" + ); + } + + match evaluate_host_effect_from_bounds(selcx, obligation) { + Ok(result) => return Ok(result), + Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), + Err(EvaluationFailure::NoSolution) => {} + } + + match evaluate_host_effect_from_selection_candiate(selcx, obligation) { + Ok(result) => return Ok(result), + Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), + Err(EvaluationFailure::NoSolution) => {} + } + + Err(EvaluationFailure::NoSolution) +} + +fn match_candidate<'tcx>( + infcx: &InferCtxt<'tcx>, + obligation: &HostEffectObligation<'tcx>, + candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, NoSolution> { + if !candidate.skip_binder().constness.satisfies(obligation.predicate.constness) { + return Err(NoSolution); + } + + let candidate = infcx.instantiate_binder_with_fresh_vars( + obligation.cause.span, + BoundRegionConversionTime::HigherRankedType, + candidate, + ); + + let mut nested = infcx + .at(&obligation.cause, obligation.param_env) + .eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)? + .into_obligations(); + + for nested in &mut nested { + nested.set_depth_from_parent(obligation.recursion_depth); + } + + Ok(nested) +} + +fn evaluate_host_effect_from_bounds<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { + let infcx = selcx.infcx; + let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); + let mut candidate = None; + + for predicate in obligation.param_env.caller_bounds() { + let bound_predicate = predicate.kind(); + if let ty::ClauseKind::HostEffect(data) = predicate.kind().skip_binder() { + let data = bound_predicate.rebind(data); + if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id { + continue; + } + + if !drcx.args_may_unify( + obligation.predicate.trait_ref.args, + data.skip_binder().trait_ref.args, + ) { + continue; + } + + let is_match = infcx.probe(|_| match_candidate(infcx, obligation, data).is_ok()); + + if is_match { + if candidate.is_some() { + return Err(EvaluationFailure::Ambiguous); + } else { + candidate = Some(data); + } + } + } + } + + if let Some(data) = candidate { + Ok(match_candidate(infcx, obligation, data) + .expect("candidate matched before, so it should match again")) + } else { + Err(EvaluationFailure::NoSolution) + } +} + +fn evaluate_host_effect_from_selection_candiate<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { + let tcx = selcx.tcx(); + selcx.infcx.commit_if_ok(|_| { + match selcx.select(&obligation.with(tcx, obligation.predicate.trait_ref)) { + Ok(None) => Err(EvaluationFailure::Ambiguous), + Err(_) => Err(EvaluationFailure::NoSolution), + Ok(Some(source)) => match source { + ImplSource::UserDefined(impl_) => { + if tcx.constness(impl_.impl_def_id) != hir::Constness::Const { + return Err(EvaluationFailure::NoSolution); + } + + let mut nested = impl_.nested; + nested.extend( + tcx.const_conditions(impl_.impl_def_id) + .instantiate(tcx, impl_.args) + .into_iter() + .map(|(trait_ref, _)| { + obligation.with( + tcx, + trait_ref + .to_host_effect_clause(tcx, obligation.predicate.constness), + ) + }), + ); + + for nested in &mut nested { + nested.set_depth_from_parent(obligation.recursion_depth); + } + + Ok(nested) + } + _ => Err(EvaluationFailure::NoSolution), + }, + } + }) +} diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 1754418156d..29e60e3c428 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -13,10 +13,11 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt}; +use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; use thin_vec::ThinVec; use tracing::{debug, debug_span, instrument}; +use super::effects::{self, HostEffectObligation}; use super::project::{self, ProjectAndUnifyResult}; use super::select::SelectionContext; use super::{ @@ -402,8 +403,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ) } - ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => { - ProcessResult::Changed(Default::default()) + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => { + let host_obligation = obligation.with(infcx.tcx, data); + + self.process_host_obligation( + host_obligation, + &mut pending_obligation.stalled_on, + ) } ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => { @@ -754,7 +760,9 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { stalled_on: &mut Vec<TyOrConstInferVar>, ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { let infcx = self.selcx.infcx; - if obligation.predicate.is_global() && !self.selcx.is_intercrate() { + if obligation.predicate.is_global() + && !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence) + { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. if infcx.predicate_must_hold_considering_regions(obligation) { @@ -807,11 +815,13 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { stalled_on: &mut Vec<TyOrConstInferVar>, ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { let tcx = self.selcx.tcx(); - - if obligation.predicate.is_global() && !self.selcx.is_intercrate() { + let infcx = self.selcx.infcx; + if obligation.predicate.is_global() + && !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence) + { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. - if self.selcx.infcx.predicate_must_hold_considering_regions(obligation) { + if infcx.predicate_must_hold_considering_regions(obligation) { if let Some(key) = ProjectionCacheKey::from_poly_projection_obligation( &mut self.selcx, &project_obligation, @@ -819,8 +829,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { // If `predicate_must_hold_considering_regions` succeeds, then we've // evaluated all sub-obligations. We can therefore mark the 'root' // obligation as complete, and skip evaluating sub-obligations. - self.selcx - .infcx + infcx .inner .borrow_mut() .projection_cache() @@ -854,6 +863,27 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { } } } + + fn process_host_obligation( + &mut self, + host_obligation: HostEffectObligation<'tcx>, + stalled_on: &mut Vec<TyOrConstInferVar>, + ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { + match effects::evaluate_host_effect_obligation(&mut self.selcx, &host_obligation) { + Ok(nested) => ProcessResult::Changed(mk_pending(nested)), + Err(effects::EvaluationFailure::Ambiguous) => { + stalled_on.clear(); + stalled_on.extend(args_infer_vars( + &self.selcx, + ty::Binder::dummy(host_obligation.predicate.trait_ref.args), + )); + ProcessResult::Unchanged + } + Err(effects::EvaluationFailure::NoSolution) => { + ProcessResult::Error(FulfillmentErrorCode::Select(SelectionError::Unimplemented)) + } + } + } } /// Returns the set of inference variables contained in `args`. diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 3e65194577e..3b17fa6b032 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; -use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use super::outlives_bounds::InferCtxtExt; use crate::regions::InferCtxtRegionExt; @@ -143,7 +143,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( let mut infringing_inner_tys = vec![]; for inner_ty in inner_tys { // We use an ocx per inner ty for better diagnostics - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); ocx.register_bound( @@ -200,7 +200,7 @@ pub fn all_fields_implement_trait<'tcx>( for variant in adt.variants() { for field in &variant.fields { // Do this per-field to get better error messages. - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); let unnormalized_ty = field.ty(tcx, args); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index cdf24887e76..436c0fabd29 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -6,6 +6,7 @@ pub mod auto_trait; pub(crate) mod coherence; pub mod const_evaluatable; mod dyn_compatibility; +pub mod effects; mod engine; mod fulfill; pub mod misc; @@ -33,7 +34,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, Upcast, + self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, TypingMode, + Upcast, }; use rustc_span::Span; use rustc_span::def_id::DefId; @@ -273,7 +275,7 @@ fn do_normalize_predicates<'tcx>( // by wfcheck anyway, so I'm not sure we have to check // them here too, and we will remove this function when // we move over to lazy normalization *anyway*. - let infcx = tcx.infer_ctxt().ignoring_regions().build(); + let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let predicates = ocx.normalize(&cause, elaborated_env, predicates); @@ -409,7 +411,7 @@ pub fn normalize_param_env_or_error<'tcx>( debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal()); - if !normalize::needs_normalization(&elaborated_env, unnormalized_env.reveal()) { + if !elaborated_env.has_aliases() { return elaborated_env; } @@ -474,11 +476,11 @@ pub fn normalize_param_env_or_error<'tcx>( /// Normalizes the predicates and checks whether they hold in an empty environment. If this /// returns true, then either normalize encountered an error or one of the predicates did not -/// hold. Used when creating vtables to check for unsatisfiable methods. +/// hold. Used when creating vtables to check for unsatisfiable methods. This should not be +/// used during analysis. pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause<'tcx>>) -> bool { debug!("impossible_predicates(predicates={:?})", predicates); - - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); let param_env = ty::ParamEnv::reveal_all(); let ocx = ObligationCtxt::new(&infcx); let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates); @@ -567,8 +569,11 @@ fn is_impossible_associated_item( // since that method *may* have some substitutions where the predicates hold. // // This replicates the logic we use in coherence. - let infcx = - tcx.infer_ctxt().ignoring_regions().with_next_trait_solver(true).intercrate(true).build(); + let infcx = tcx + .infer_ctxt() + .ignoring_regions() + .with_next_trait_solver(true) + .build(TypingMode::Coherence); let param_env = ty::ParamEnv::empty(); let fresh_args = infcx.fresh_args_for_item(tcx.def_span(impl_def_id), impl_def_id); diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 12e00ec79ac..954dfe93387 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -1,15 +1,16 @@ //! Deeply normalize types using the old trait solver. use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_infer::infer::InferOk; use rustc_infer::infer::at::At; +use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_infer::traits::{ FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine, }; use rustc_macros::extension; -use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal}; +use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, + TypingMode, }; use tracing::{debug, instrument}; @@ -109,16 +110,19 @@ where } pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>( + infcx: &InferCtxt<'tcx>, + param_env_for_debug_assertion: ty::ParamEnv<'tcx>, value: &T, - reveal: Reveal, ) -> bool { let mut flags = ty::TypeFlags::HAS_ALIAS; // Opaques are treated as rigid with `Reveal::UserFacing`, // so we can ignore those. - match reveal { - Reveal::UserFacing => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE), - Reveal::All => {} + match infcx.typing_mode(param_env_for_debug_assertion) { + TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => { + flags.remove(ty::TypeFlags::HAS_TY_OPAQUE) + } + TypingMode::PostAnalysis => {} } value.has_type_flags(flags) @@ -154,7 +158,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { "Normalizing {value:?} without wrapping in a `Binder`" ); - if !needs_normalization(&value, self.param_env.reveal()) { + if !needs_normalization(self.selcx.infcx, self.param_env, &value) { value } else { value.fold_with(self) @@ -178,7 +182,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !needs_normalization(&ty, self.param_env.reveal()) { + if !needs_normalization(self.selcx.infcx, self.param_env, &ty) { return ty; } @@ -213,10 +217,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx match kind { ty::Opaque => { // Only normalize `impl Trait` outside of type inference, usually in codegen. - match self.param_env.reveal() { - Reveal::UserFacing => ty.super_fold_with(self), - - Reveal::All => { + match self.selcx.infcx.typing_mode(self.param_env) { + TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => { + ty.super_fold_with(self) + } + TypingMode::PostAnalysis => { let recursion_limit = self.cx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { self.selcx.infcx.err_ctxt().report_overflow_error( @@ -403,7 +408,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { let tcx = self.selcx.tcx(); if tcx.features().generic_const_exprs() - || !needs_normalization(&constant, self.param_env.reveal()) + || !needs_normalization(self.selcx.infcx, self.param_env, &constant) { constant } else { @@ -420,7 +425,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx #[inline] fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { + if p.allow_normalization() && needs_normalization(self.selcx.infcx, self.param_env, &p) { p.super_fold_with(self) } else { p diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 0803dd74b89..aab854e9caf 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -16,7 +16,7 @@ use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedD use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt}; -use rustc_middle::ty::{self, Term, Ty, TyCtxt, Upcast}; +use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::sym; use tracing::{debug, instrument}; @@ -334,11 +334,6 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( ) -> Result<Option<Term<'tcx>>, InProgress> { let infcx = selcx.infcx; debug_assert!(!selcx.infcx.next_trait_solver()); - // Don't use the projection cache in intercrate mode - - // the `infcx` may be re-used between intercrate in non-intercrate - // mode, which could lead to using incorrect cache results. - let use_cache = !selcx.is_intercrate(); - let projection_term = infcx.resolve_vars_if_possible(projection_term); let cache_key = ProjectionCacheKey::new(projection_term, param_env); @@ -349,13 +344,8 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( // would not benefit from caching when proving `T: Trait<U=Foo>` // bounds. It might be the case that we want two distinct caches, // or else another kind of cache entry. - - let cache_result = if use_cache { - infcx.inner.borrow_mut().projection_cache().try_start(cache_key) - } else { - Ok(()) - }; - match cache_result { + let cache_entry = infcx.inner.borrow_mut().projection_cache().try_start(cache_key); + match cache_entry { Ok(()) => debug!("no cache"), Err(ProjectionCacheEntry::Ambiguous) => { // If we found ambiguity the last time, that means we will continue @@ -378,10 +368,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( // Cache that normalizing this projection resulted in a cycle. This // should ensure that, unless this happens within a snapshot that's // rolled back, fulfillment or evaluation will notice the cycle. - - if use_cache { - infcx.inner.borrow_mut().projection_cache().recur(cache_key); - } + infcx.inner.borrow_mut().projection_cache().recur(cache_key); return Err(InProgress); } Err(ProjectionCacheEntry::Recur) => { @@ -445,26 +432,20 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( let mut deduped = SsoHashSet::with_capacity(result.obligations.len()); result.obligations.retain(|obligation| deduped.insert(obligation.clone())); - if use_cache { - infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); - } + infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); obligations.extend(result.obligations); Ok(Some(result.value)) } Ok(Projected::NoProgress(projected_ty)) => { let result = Normalized { value: projected_ty, obligations: PredicateObligations::new() }; - if use_cache { - infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); - } + infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); // No need to extend `obligations`. Ok(Some(result.value)) } Err(ProjectionError::TooManyCandidates) => { debug!("opt_normalize_projection_type: too many candidates"); - if use_cache { - infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); - } + infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); Ok(None) } Err(ProjectionError::TraitSelectionError(_)) => { @@ -473,10 +454,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( // just return `ty::err` but add the obligation `T : // Trait`, which when processed will cause the error to be // reported later - - if use_cache { - infcx.inner.borrow_mut().projection_cache().error(cache_key); - } + infcx.inner.borrow_mut().projection_cache().error(cache_key); let result = normalize_to_error(selcx, param_env, projection_term, cause, depth); obligations.extend(result.obligations); Ok(Some(result.value)) @@ -997,18 +975,21 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // and the obligation is monomorphic, otherwise passes such as // transmute checking and polymorphic MIR optimizations could // get a result which isn't correct for all monomorphizations. - if obligation.param_env.reveal() == Reveal::All { - // NOTE(eddyb) inference variables can resolve to parameters, so - // assume `poly_trait_ref` isn't monomorphic, if it contains any. - let poly_trait_ref = selcx.infcx.resolve_vars_if_possible(trait_ref); - !poly_trait_ref.still_further_specializable() - } else { - debug!( - assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id), - ?obligation.predicate, - "assemble_candidates_from_impls: not eligible due to default", - ); - false + match selcx.infcx.typing_mode(obligation.param_env) { + TypingMode::Coherence | TypingMode::Analysis { .. } => { + debug!( + assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id), + ?obligation.predicate, + "assemble_candidates_from_impls: not eligible due to default", + ); + false + } + TypingMode::PostAnalysis => { + // NOTE(eddyb) inference variables can resolve to parameters, so + // assume `poly_trait_ref` isn't monomorphic, if it contains any. + let poly_trait_ref = selcx.infcx.resolve_vars_if_possible(trait_ref); + !poly_trait_ref.still_further_specializable() + } } } } 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 bb44645a4ce..9e1a2a3e7d2 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -87,7 +87,6 @@ impl<'tcx> InferCtxt<'tcx> { Ok(result) }) } else { - assert!(!self.intercrate); let c_pred = self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values); self.tcx.at(obligation.cause.span).evaluate_obligation(c_pred) diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 01e6516302c..a8d701a750d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -9,7 +9,7 @@ use rustc_macros::extension; pub use rustc_middle::traits::query::NormalizationResult; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor, TypingMode}; use rustc_span::DUMMY_SP; use tracing::{debug, info, instrument}; @@ -21,7 +21,7 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::normalize::needs_normalization; use crate::traits::{ - BoundVarReplacer, Normalized, ObligationCause, PlaceholderReplacer, Reveal, ScrubbedTraitError, + BoundVarReplacer, Normalized, ObligationCause, PlaceholderReplacer, ScrubbedTraitError, }; #[extension(pub trait QueryNormalizeExt<'tcx>)] @@ -89,7 +89,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { } } - if !needs_normalization(&value, self.param_env.reveal()) { + if !needs_normalization(self.infcx, self.param_env, &value) { return Ok(Normalized { value, obligations: PredicateObligations::new() }); } @@ -191,7 +191,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> { - if !needs_normalization(&ty, self.param_env.reveal()) { + if !needs_normalization(self.infcx, self.param_env, &ty) { return Ok(ty); } @@ -215,10 +215,12 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> { let res = match kind { ty::Opaque => { // Only normalize `impl Trait` outside of type inference, usually in codegen. - match self.param_env.reveal() { - Reveal::UserFacing => ty.try_super_fold_with(self)?, + match self.infcx.typing_mode(self.param_env) { + TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => { + ty.try_super_fold_with(self)? + } - Reveal::All => { + TypingMode::PostAnalysis => { let args = data.args.try_fold_with(self)?; let recursion_limit = self.cx().recursion_limit(); @@ -332,7 +334,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> { &mut self, constant: ty::Const<'tcx>, ) -> Result<ty::Const<'tcx>, Self::Error> { - if !needs_normalization(&constant, self.param_env.reveal()) { + if !needs_normalization(self.infcx, self.param_env, &constant) { return Ok(constant); } @@ -351,7 +353,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> { &mut self, p: ty::Predicate<'tcx>, ) -> Result<ty::Predicate<'tcx>, Self::Error> { - if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { + if p.allow_normalization() && needs_normalization(self.infcx, self.param_env, &p) { p.try_super_fold_with(self) } else { Ok(p) diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index e027586563e..03fde1d1598 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -16,7 +16,7 @@ use rustc_infer::traits::{ Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError, }; use rustc_middle::ty::fast_reject::DeepRejectCtxt; -use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument, trace}; @@ -790,7 +790,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // // Note that this is only sound as projection candidates of opaque types // are always applicable for auto traits. - } else if self.infcx.intercrate { + } else if let TypingMode::Coherence = + self.infcx.typing_mode(obligation.param_env) + { // We do not emit auto trait candidates for opaque types in coherence. // Doing so can result in weird dependency cycles. candidates.ambiguous = true; @@ -930,7 +932,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Option<ty::PolyExistentialTraitRef<'tcx>> { // Don't drop any candidates in intercrate mode, as it's incomplete. // (Not that it matters, since `Unsize` is not a stable trait.) - if self.infcx.intercrate { + // + // FIXME(@lcnr): This should probably only trigger during analysis, + // disabling candidates during codegen is also questionable. + if let TypingMode::Coherence = self.infcx.typing_mode(param_env) { return None; } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ec4114fd9d7..b1e5e526315 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2,6 +2,7 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection +use std::assert_matches::assert_matches; use std::cell::{Cell, RefCell}; use std::fmt::{self, Display}; use std::ops::ControlFlow; @@ -28,7 +29,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, - Upcast, + TypingMode, Upcast, }; use rustc_span::Symbol; use rustc_span::symbol::sym; @@ -49,7 +50,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt}; -use crate::traits::{ProjectionCacheKey, Unimplemented}; +use crate::traits::{ProjectionCacheKey, Unimplemented, effects}; mod _match; mod candidate_assembly; @@ -222,7 +223,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Enables tracking of intercrate ambiguity causes. See /// the documentation of [`Self::intercrate_ambiguity_causes`] for more. pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { - assert!(self.is_intercrate()); + assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence); assert!(self.intercrate_ambiguity_causes.is_none()); self.intercrate_ambiguity_causes = Some(FxIndexSet::default()); debug!("selcx: enable_tracking_intercrate_ambiguity_causes"); @@ -234,7 +235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub fn take_intercrate_ambiguity_causes( &mut self, ) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> { - assert!(self.is_intercrate()); + assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence); self.intercrate_ambiguity_causes.take().unwrap_or_default() } @@ -242,10 +243,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx } - pub fn is_intercrate(&self) -> bool { - self.infcx.intercrate - } - /////////////////////////////////////////////////////////////////////////// // Selection // @@ -645,11 +642,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluate_trait_predicate_recursively(previous_stack, obligation) } - ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => { - // FIXME(effects): It should be relatively straightforward to implement - // old trait solver support for `HostEffect` bounds; or at least basic - // support for them. - todo!() + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => { + self.infcx.enter_forall(bound_predicate.rebind(data), |data| { + match effects::evaluate_host_effect_obligation( + self, + &obligation.with(self.tcx(), data), + ) { + Ok(nested) => { + self.evaluate_predicates_recursively(previous_stack, nested) + } + Err(effects::EvaluationFailure::Ambiguous) => Ok(EvaluatedToAmbig), + Err(effects::EvaluationFailure::NoSolution) => Ok(EvaluatedToErr), + } + }) } ty::PredicateKind::Subtype(p) => { @@ -1021,7 +1026,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: PolyTraitObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { - if !self.is_intercrate() + if !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) && obligation.is_global() && obligation.param_env.caller_bounds().iter().all(|bound| bound.has_param()) { @@ -1304,14 +1309,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option<EvaluationResult> { - // Neither the global nor local cache is aware of intercrate - // mode, so don't do any caching. In particular, we might - // re-use the same `InferCtxt` with both an intercrate - // and non-intercrate `SelectionContext` - if self.is_intercrate() { - return None; - } - let tcx = self.tcx(); if self.can_use_global_caches(param_env) { if let Some(res) = tcx.evaluation_cache.get(&(param_env, trait_pred), tcx) { @@ -1334,14 +1331,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - // Neither the global nor local cache is aware of intercrate - // mode, so don't do any caching. In particular, we might - // re-use the same `InferCtxt` with both an intercrate - // and non-intercrate `SelectionContext` - if self.is_intercrate() { - return; - } - if self.can_use_global_caches(param_env) && !trait_pred.has_infer() { debug!(?trait_pred, ?result, "insert_evaluation_cache global"); // This may overwrite the cache with the same value @@ -1468,13 +1457,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> { - debug!("is_knowable(intercrate={:?})", self.is_intercrate()); - - if !self.is_intercrate() { - return Ok(()); + let obligation = &stack.obligation; + match self.infcx.typing_mode(obligation.param_env) { + TypingMode::Coherence => {} + TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Ok(()), } - let obligation = &stack.obligation; + debug!("is_knowable()"); + let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); // Okay to skip binder because of the nature of the @@ -1494,25 +1484,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return false; } - // Avoid using the global cache during coherence and just rely - // on the local cache. This effectively disables caching - // during coherence. It is really just a simplification to - // avoid us having to fear that coherence results "pollute" - // the master cache. Since coherence executes pretty quickly, - // it's not worth going to more trouble to increase the - // hit-rate, I don't think. - if self.is_intercrate() { - return false; - } - - // Avoid using the global cache when we're defining opaque types - // as their hidden type may impact the result of candidate selection. - if !self.infcx.defining_opaque_types().is_empty() { - return false; + match self.infcx.typing_mode(param_env) { + // Avoid using the global cache during coherence and just rely + // on the local cache. It is really just a simplification to + // avoid us having to fear that coherence results "pollute" + // the master cache. Since coherence executes pretty quickly, + // it's not worth going to more trouble to increase the + // hit-rate, I don't think. + TypingMode::Coherence => false, + // Avoid using the global cache when we're defining opaque types + // as their hidden type may impact the result of candidate selection. + TypingMode::Analysis { defining_opaque_types } => defining_opaque_types.is_empty(), + // The global cache is only used if there are no opaque types in + // the defining scope or we're outside of analysis. + // + // FIXME(#132279): This is still incorrect as we treat opaque types + // and default associated items differently between these two modes. + TypingMode::PostAnalysis => true, } - - // Otherwise, we can use the global cache. - true } fn check_candidate_cache( @@ -1520,13 +1509,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> { - // Neither the global nor local cache is aware of intercrate - // mode, so don't do any caching. In particular, we might - // re-use the same `InferCtxt` with both an intercrate - // and non-intercrate `SelectionContext` - if self.is_intercrate() { - return None; - } let tcx = self.tcx(); let pred = cache_fresh_trait_pred.skip_binder(); @@ -1558,13 +1540,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &self, result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>, ) -> bool { - // Neither the global nor local cache is aware of intercrate - // mode, so don't do any caching. In particular, we might - // re-use the same `InferCtxt` with both an intercrate - // and non-intercrate `SelectionContext` - if self.is_intercrate() { - return false; - } match result { Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_infer(), _ => true, @@ -2533,7 +2508,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { })?; nested_obligations.extend(obligations); - if !self.is_intercrate() && impl_trait_header.polarity == ty::ImplPolarity::Reservation { + if impl_trait_header.polarity == ty::ImplPolarity::Reservation + && !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) + { debug!("reservation impls only apply in intercrate mode"); return Err(()); } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 0e45f7a195f..5bf3dbcbc32 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -19,7 +19,9 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::bug; use rustc_middle::query::LocalCrate; use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::{self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{ + self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt, TypingMode, +}; use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym}; use specialization_graph::GraphExt; @@ -184,7 +186,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, let penv = tcx.param_env(impl1_def_id); // Create an infcx, taking the predicates of impl1 as assumptions: - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); // Attempt to prove that impl2 applies, given all of the above. fulfill_implication( diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index ed221e2a183..bb56d6eaf54 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -9,7 +9,8 @@ use rustc_infer::traits::util::PredicateSet; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry, + self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, + VtblEntry, }; use rustc_span::{DUMMY_SP, Span, sym}; use smallvec::{SmallVec, smallvec}; @@ -439,7 +440,7 @@ fn trait_refs_are_compatible<'tcx>( return false; } - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); let param_env = ty::ParamEnv::reveal_all(); let ocx = ObligationCtxt::new(&infcx); let hr_source_principal = diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 11182198246..d8c1c50d79a 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::traits::CodegenObligationError; -use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{ ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, @@ -30,7 +30,7 @@ pub(crate) fn codegen_select_candidate<'tcx>( // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - let infcx = tcx.infer_ctxt().ignoring_regions().build(); + let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::from_param_env(param_env)); let mut selcx = SelectionContext::new(&infcx); let obligation_cause = ObligationCause::dummy(); diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 3e2794f6489..d79059a39a1 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -1,7 +1,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode}; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Normalized, ObligationCause}; use tracing::debug; @@ -22,7 +22,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Par goal: ParamEnvAnd<'tcx, T>, ) -> Result<T, NoSolution> { let ParamEnvAnd { param_env, value } = goal; - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let cause = ObligationCause::dummy(); match infcx.at(&cause, param_env).query_normalize(value) { Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => { diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 94ca4c13d08..f19a567cd84 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -339,9 +339,7 @@ pub(crate) mod rustc { // 2. enums that delegate their layout to a variant // 3. enums with multiple variants match layout.variants() { - Variants::Single { .. } - if layout.abi.is_uninhabited() && layout.size == Size::ZERO => - { + Variants::Single { .. } if layout.is_uninhabited() && layout.size == Size::ZERO => { // The layout representation of uninhabited, ZST enums is // defined to be like that of the `!` type, as opposed of a // typical enum. Consequently, they cannot be descended into diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 48149a08de8..722ef5f4569 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,7 +1,7 @@ use std::iter; use rustc_abi::Primitive::Pointer; -use rustc_abi::{Abi, PointerKind, Scalar, Size}; +use rustc_abi::{BackendRepr, PointerKind, Scalar, Size}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_middle::bug; @@ -469,7 +469,7 @@ fn fn_abi_sanity_check<'tcx>( // careful. Scalar/ScalarPair is fine, since backends will generally use // `layout.abi` and ignore everything else. We should just reject `Aggregate` // entirely here, but some targets need to be fixed first. - if matches!(arg.layout.abi, Abi::Aggregate { .. }) { + if matches!(arg.layout.backend_repr, BackendRepr::Memory { .. }) { // For an unsized type we'd only pass the sized prefix, so there is no universe // in which we ever want to allow this. assert!( @@ -500,7 +500,7 @@ fn fn_abi_sanity_check<'tcx>( // Similar to `Direct`, we need to make sure that backends use `layout.abi` and // ignore the rest of the layout. assert!( - matches!(arg.layout.abi, Abi::ScalarPair(..)), + matches!(arg.layout.backend_repr, BackendRepr::ScalarPair(..)), "PassMode::Pair for type {}", arg.layout.ty ); @@ -658,9 +658,9 @@ fn fn_abi_adjust_for_abi<'tcx>( fn unadjust<'tcx>(arg: &mut ArgAbi<'tcx, Ty<'tcx>>) { // This still uses `PassMode::Pair` for ScalarPair types. That's unlikely to be intended, // but who knows what breaks if we change this now. - if matches!(arg.layout.abi, Abi::Aggregate { .. }) { + if matches!(arg.layout.backend_repr, BackendRepr::Memory { .. }) { assert!( - arg.layout.abi.is_sized(), + arg.layout.backend_repr.is_sized(), "'unadjusted' ABI does not support unsized arguments" ); } @@ -731,8 +731,8 @@ fn make_thin_self_ptr<'tcx>( // FIXME (mikeyhew) change this to use &own if it is ever added to the language Ty::new_mut_ptr(tcx, layout.ty) } else { - match layout.abi { - Abi::ScalarPair(..) | Abi::Scalar(..) => (), + match layout.backend_repr { + BackendRepr::ScalarPair(..) | BackendRepr::Scalar(..) => (), _ => bug!("receiver type has unsupported layout: {:?}", layout), } diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 16fd28201c2..3655fa5ae0e 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -143,7 +143,6 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty container: ty::TraitContainer, fn_has_self_parameter: has_self, opt_rpitit_info: None, - is_effects_desugaring: false, } } @@ -163,7 +162,6 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A container: ty::ImplContainer, fn_has_self_parameter: has_self, opt_rpitit_info: None, - is_effects_desugaring: false, } } @@ -190,7 +188,7 @@ fn associated_types_for_impl_traits_in_associated_fn( impl<'tcx> Visitor<'tcx> for RPITVisitor { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if let hir::TyKind::OpaqueDef(opaq, _) = ty.kind + if let hir::TyKind::OpaqueDef(opaq) = ty.kind && self.rpits.insert(opaq.def_id) { for bound in opaq.bounds { @@ -246,7 +244,7 @@ fn associated_type_for_impl_trait_in_trait( ) -> LocalDefId { let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) = - tcx.opaque_type_origin(opaque_ty_def_id) + tcx.local_opaque_ty_origin(opaque_ty_def_id) else { bug!("expected opaque for {opaque_ty_def_id:?}"); }; @@ -275,7 +273,6 @@ fn associated_type_for_impl_trait_in_trait( fn_def_id: fn_def_id.to_def_id(), opaque_def_id: opaque_ty_def_id.to_def_id(), }), - is_effects_desugaring: false, }); // Copy visility of the containing function. @@ -284,8 +281,6 @@ fn associated_type_for_impl_trait_in_trait( // Copy defaultness of the containing function. trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id)); - trait_assoc_ty.is_type_alias_impl_trait(false); - // There are no inferred outlives for the synthesized associated type. trait_assoc_ty.inferred_outlives_of(&[]); @@ -327,7 +322,6 @@ fn associated_type_for_impl_trait_in_impl( container: ty::ImplContainer, fn_has_self_parameter: false, opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }), - is_effects_desugaring: false, }); // Copy visility of the containing function. diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index 51b908881eb..c26b41d8960 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -3,7 +3,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_trait_selection::traits; fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { @@ -29,7 +29,7 @@ fn is_item_raw<'tcx>( ) -> bool { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(item, None); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id) } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 9b764133f2c..e258b6dae0b 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -6,7 +6,7 @@ use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError}; use rustc_middle::ty::util::AsyncDropGlueMorphology; -use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_span::sym; use rustc_trait_selection::traits; use rustc_type_ir::ClosureKind; @@ -130,7 +130,7 @@ fn resolve_associated_item<'tcx>( .unwrap_or_else(|| { bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id); }); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); let param_env = param_env.with_reveal_all_normalized(tcx); let args = rcvr_args.rebase_onto(tcx, trait_def_id, impl_data.args); let args = translate_args( diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 94b80e2694d..5ca7afe2453 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -5,8 +5,9 @@ use hir::def_id::DefId; use rustc_abi::Integer::{I8, I32}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ - Abi, AbiAndPrefAlign, AddressSpace, Align, FieldsShape, HasDataLayout, LayoutCalculatorError, - LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, + AbiAndPrefAlign, AddressSpace, Align, BackendRepr, FieldsShape, HasDataLayout, + LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, + Variants, WrappingRange, }; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; @@ -173,7 +174,9 @@ fn layout_of_uncached<'tcx>( let mut layout = LayoutData::clone(&layout.0); match *pat { ty::PatternKind::Range { start, end, include_end } => { - if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi { + if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) = + &mut layout.backend_repr + { if let Some(start) = start { scalar.valid_range_mut().start = start .try_to_bits(tcx, param_env) @@ -275,7 +278,7 @@ fn layout_of_uncached<'tcx>( return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); } - let Abi::Scalar(metadata) = metadata_layout.abi else { + let BackendRepr::Scalar(metadata) = metadata_layout.backend_repr else { return Err(error(cx, LayoutError::Unknown(pointee))); }; @@ -330,9 +333,9 @@ fn layout_of_uncached<'tcx>( .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?; let abi = if count != 0 && ty.is_privately_uninhabited(tcx, param_env) { - Abi::Uninhabited + BackendRepr::Uninhabited } else { - Abi::Aggregate { sized: true } + BackendRepr::Memory { sized: true } }; let largest_niche = if count != 0 { element.largest_niche } else { None }; @@ -340,7 +343,7 @@ fn layout_of_uncached<'tcx>( tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count }, - abi, + backend_repr: abi, largest_niche, align: element.align, size, @@ -353,7 +356,7 @@ fn layout_of_uncached<'tcx>( tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count: 0 }, - abi: Abi::Aggregate { sized: false }, + backend_repr: BackendRepr::Memory { sized: false }, largest_niche: None, align: element.align, size: Size::ZERO, @@ -364,7 +367,7 @@ fn layout_of_uncached<'tcx>( ty::Str => tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, - abi: Abi::Aggregate { sized: false }, + backend_repr: BackendRepr::Memory { sized: false }, largest_niche: None, align: dl.i8_align, size: Size::ZERO, @@ -384,8 +387,8 @@ fn layout_of_uncached<'tcx>( &ReprOptions::default(), StructKind::AlwaysSized, )?; - match unit.abi { - Abi::Aggregate { ref mut sized } => *sized = false, + match unit.backend_repr { + BackendRepr::Memory { ref mut sized } => *sized = false, _ => bug!(), } tcx.mk_layout(unit) @@ -500,7 +503,7 @@ fn layout_of_uncached<'tcx>( // Compute the ABI of the element type: let e_ly = cx.layout_of(e_ty)?; - let Abi::Scalar(e_abi) = e_ly.abi else { + let BackendRepr::Scalar(e_abi) = e_ly.backend_repr else { // This error isn't caught in typeck, e.g., if // the element type of the vector is generic. tcx.dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty }); @@ -516,12 +519,12 @@ fn layout_of_uncached<'tcx>( // 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. - (Abi::Aggregate { sized: true }, AbiAndPrefAlign { + (BackendRepr::Memory { sized: true }, AbiAndPrefAlign { abi: Align::max_for_offset(size), pref: dl.vector_align(size).pref, }) } else { - (Abi::Vector { element: e_abi, count: e_len }, dl.vector_align(size)) + (BackendRepr::Vector { element: e_abi, count: e_len }, dl.vector_align(size)) }; let size = size.align_to(align.abi); @@ -535,7 +538,7 @@ fn layout_of_uncached<'tcx>( tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields, - abi, + backend_repr: abi, largest_niche: e_ly.largest_niche, size, align, @@ -985,10 +988,12 @@ fn coroutine_layout<'tcx>( size = size.align_to(align.abi); - let abi = if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi.is_uninhabited()) { - Abi::Uninhabited + let abi = if prefix.backend_repr.is_uninhabited() + || variants.iter().all(|v| v.backend_repr.is_uninhabited()) + { + BackendRepr::Uninhabited } else { - Abi::Aggregate { sized: true } + BackendRepr::Memory { sized: true } }; let layout = tcx.mk_layout(LayoutData { @@ -999,7 +1004,7 @@ fn coroutine_layout<'tcx>( variants, }, fields: outer_fields, - abi, + backend_repr: abi, // Suppress niches inside coroutines. If the niche is inside a field that is aliased (due to // self-referentiality), getting the discriminant can cause aliasing violations. // `UnsafeCell` blocks niches for the same reason, but we don't yet have `UnsafePinned` that diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 6cf114b74c1..f43feb552b2 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -10,7 +10,7 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa // Type-level uninhabitedness should always imply ABI uninhabitedness. if layout.ty.is_privately_uninhabited(tcx, cx.param_env) { - assert!(layout.abi.is_uninhabited()); + assert!(layout.is_uninhabited()); } if layout.size.bytes() % layout.align.abi.bytes() != 0 { @@ -66,12 +66,12 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { // Verify the ABI mandated alignment and size. - let align = layout.abi.inherent_align(cx).map(|align| align.abi); - let size = layout.abi.inherent_size(cx); + let align = layout.backend_repr.inherent_align(cx).map(|align| align.abi); + let size = layout.backend_repr.inherent_size(cx); let Some((align, size)) = align.zip(size) else { assert_matches!( - layout.layout.abi(), - Abi::Uninhabited | Abi::Aggregate { .. }, + layout.layout.backend_repr(), + BackendRepr::Uninhabited | BackendRepr::Memory { .. }, "ABI unexpectedly missing alignment and/or size in {layout:#?}" ); return; @@ -88,12 +88,12 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa ); // Verify per-ABI invariants - match layout.layout.abi() { - Abi::Scalar(_) => { + match layout.layout.backend_repr() { + BackendRepr::Scalar(_) => { // Check that this matches the underlying field. let inner = skip_newtypes(cx, layout); assert!( - matches!(inner.layout.abi(), Abi::Scalar(_)), + matches!(inner.layout.backend_repr(), BackendRepr::Scalar(_)), "`Scalar` type {} is newtype around non-`Scalar` type {}", layout.ty, inner.ty @@ -132,7 +132,7 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa "`Scalar` field with bad align in {inner:#?}", ); assert!( - matches!(field.abi, Abi::Scalar(_)), + matches!(field.backend_repr, BackendRepr::Scalar(_)), "`Scalar` field with bad ABI in {inner:#?}", ); } @@ -141,11 +141,11 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa } } } - Abi::ScalarPair(scalar1, scalar2) => { + BackendRepr::ScalarPair(scalar1, scalar2) => { // Check that the underlying pair of fields matches. let inner = skip_newtypes(cx, layout); assert!( - matches!(inner.layout.abi(), Abi::ScalarPair(..)), + matches!(inner.layout.backend_repr(), BackendRepr::ScalarPair(..)), "`ScalarPair` type {} is newtype around non-`ScalarPair` type {}", layout.ty, inner.ty @@ -208,8 +208,8 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa "`ScalarPair` first field with bad align in {inner:#?}", ); assert_matches!( - field1.abi, - Abi::Scalar(_), + field1.backend_repr, + BackendRepr::Scalar(_), "`ScalarPair` first field with bad ABI in {inner:#?}", ); let field2_offset = size1.align_to(align2); @@ -226,16 +226,16 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa "`ScalarPair` second field with bad align in {inner:#?}", ); assert_matches!( - field2.abi, - Abi::Scalar(_), + field2.backend_repr, + BackendRepr::Scalar(_), "`ScalarPair` second field with bad ABI in {inner:#?}", ); } - Abi::Vector { element, .. } => { + BackendRepr::Vector { element, .. } => { assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`. // FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair. } - Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check. + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => {} // Nothing to check. } } @@ -262,9 +262,7 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa ) } // Skip empty variants. - if variant.size == Size::ZERO - || variant.fields.count() == 0 - || variant.abi.is_uninhabited() + if variant.size == Size::ZERO || variant.fields.count() == 0 || variant.is_uninhabited() { // These are never actually accessed anyway, so we can skip the coherence check // for them. They also fail that check, since they have @@ -276,13 +274,13 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa // The top-level ABI and the ABI of the variants should be coherent. let scalar_coherent = |s1: Scalar, s2: Scalar| s1.size(cx) == s2.size(cx) && s1.align(cx) == s2.align(cx); - let abi_coherent = match (layout.abi, variant.abi) { - (Abi::Scalar(s1), Abi::Scalar(s2)) => scalar_coherent(s1, s2), - (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => { + let abi_coherent = match (layout.backend_repr, variant.backend_repr) { + (BackendRepr::Scalar(s1), BackendRepr::Scalar(s2)) => scalar_coherent(s1, s2), + (BackendRepr::ScalarPair(a1, b1), BackendRepr::ScalarPair(a2, b2)) => { scalar_coherent(a1, a2) && scalar_coherent(b1, b2) } - (Abi::Uninhabited, _) => true, - (Abi::Aggregate { .. }, _) => true, + (BackendRepr::Uninhabited, _) => true, + (BackendRepr::Memory { .. }, _) => true, _ => false, }; if !abi_coherent { diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 5e2232ff47d..34f461aac58 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -139,7 +139,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { } // TAITs outside their defining scopes are ignored. - let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local()); + let origin = self.tcx.local_opaque_ty_origin(alias_ty.def_id.expect_local()); trace!(?origin); match origin { rustc_hir::OpaqueTyOrigin::FnReturn { .. } diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs index 1ead7b731e7..0b4efab1d9c 100644 --- a/compiler/rustc_ty_utils/src/structural_match.rs +++ b/compiler/rustc_ty_utils/src/structural_match.rs @@ -1,7 +1,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; /// This method returns true if and only if `adt_ty` itself has been marked as @@ -11,7 +11,7 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; /// Note that this does *not* recursively check if the substructure of `adt_ty` /// implements the trait. fn has_structural_eq_impl<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = ObligationCause::dummy(); let ocx = ObligationCtxt::new(infcx); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index aa499995bcb..731d42fc006 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -155,7 +155,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { if tcx.is_conditionally_const(def_id) { predicates.extend( tcx.const_conditions(def_id).instantiate_identity(tcx).into_iter().map( - |(trait_ref, _)| trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + |(trait_ref, _)| trait_ref.to_host_effect_clause(tcx, ty::BoundConstness::Maybe), ), ); } diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 3fb7d87bcc4..24b2ebc1fbe 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -8,7 +8,7 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use crate::inherent::*; -use crate::{self as ty, Interner, UniverseIndex}; +use crate::{self as ty, Interner, TypingMode, UniverseIndex}; #[derive_where(Clone; I: Interner, V: Clone)] #[derive_where(Hash; I: Interner, V: Hash)] @@ -19,7 +19,7 @@ use crate::{self as ty, Interner, UniverseIndex}; #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub struct CanonicalQueryInput<I: Interner, V> { pub canonical: Canonical<I, V>, - pub defining_opaque_types: I::DefiningOpaqueTypes, + pub typing_mode: TypingMode<I>, } /// A "canonicalized" type `V` is one where all free inference diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 72d392ecd7b..3fbce7886ed 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -160,7 +160,7 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> { cx.implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| { elaboratable.child( trait_ref - .to_host_effect_clause(cx, data.host) + .to_host_effect_clause(cx, data.constness) .instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)), ) }), diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 7c6a3c65ebf..aadb64f45d7 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -1,9 +1,75 @@ +use derive_where::derive_where; +#[cfg(feature = "nightly")] +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; + use crate::fold::TypeFoldable; +use crate::inherent::*; use crate::relate::RelateResult; use crate::relate::combine::PredicateEmittingRelation; -use crate::solve::SolverMode; +use crate::solve::Reveal; use crate::{self as ty, Interner}; +/// The current typing mode of an inference context. We unfortunately have some +/// slightly different typing rules depending on the current context. See the +/// doc comment for each variant for how and why they are used. +/// +/// In most cases you can get the correct typing mode automically via: +/// - `mir::Body::typing_mode` +/// - `rustc_lint::LateContext::typing_mode` +/// +/// If neither of these functions are available, feel free to reach out to +/// t-types for help. +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub enum TypingMode<I: Interner> { + /// When checking whether impls overlap, we check whether any obligations + /// are guaranteed to never hold when unifying the impls. This requires us + /// to be complete: we must never fail to prove something which may actually + /// hold. + /// + /// In this typing mode we bail with ambiguity in case its not knowable + /// whether a trait goal may hold, e.g. because the trait may get implemented + /// in a downstream or sibling crate. + /// + /// We also have to be careful when generalizing aliases inside of higher-ranked + /// types to not unnecessarily constrain any inference variables. + Coherence, + /// Analysis includes type inference, checking that items are well-formed, and + /// pretty much everything else which may emit proper type errors to the user. + /// + /// We only normalize opaque types which may get defined by the current body, + /// which are stored in `defining_opaque_types`. + Analysis { defining_opaque_types: I::DefiningOpaqueTypes }, + /// After analysis, mostly during codegen and MIR optimizations, we're able to + /// reveal all opaque types. + PostAnalysis, +} + +impl<I: Interner> TypingMode<I> { + /// Analysis outside of a body does not define any opaque types. + pub fn non_body_analysis() -> TypingMode<I> { + TypingMode::Analysis { defining_opaque_types: Default::default() } + } + + /// While typechecking a body, we need to be able to define the opaque + /// types defined by that body. + pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> { + TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) } + } + + /// FIXME(#132279): Using this function is questionable as the `param_env` + /// does not track `defining_opaque_types` and whether we're in coherence mode. + /// Many uses of this function should also use a not-yet implemented typing mode + /// which reveals already defined opaque types in the future. This function will + /// get completely removed at some point. + pub fn from_param_env(param_env: I::ParamEnv) -> TypingMode<I> { + match param_env.reveal() { + Reveal::UserFacing => TypingMode::non_body_analysis(), + Reveal::All => TypingMode::PostAnalysis, + } + } +} + pub trait InferCtxtLike: Sized { type Interner: Interner; fn cx(&self) -> Self::Interner; @@ -16,7 +82,10 @@ pub trait InferCtxtLike: Sized { true } - fn solver_mode(&self) -> SolverMode; + fn typing_mode( + &self, + param_env_for_debug_assertion: <Self::Interner as Interner>::ParamEnv, + ) -> TypingMode<Self::Interner>; fn universe(&self) -> ty::UniverseIndex; fn create_next_universe(&self) -> ty::UniverseIndex; @@ -43,8 +112,6 @@ pub trait InferCtxtLike: Sized { vid: ty::RegionVid, ) -> <Self::Interner as Interner>::Region; - fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes; - fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty; fn next_const_infer(&self) -> <Self::Interner as Interner>::Const; fn fresh_args_for_item( diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6a8113b38b7..36ddddccfa2 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::TraitSolverLangItem; use crate::relate::Relate; -use crate::solve::{ - CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode, -}; +use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, search_graph}; @@ -130,11 +128,7 @@ pub trait Interner: type Clause: Clause<Self>; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags; - fn with_global_cache<R>( - self, - mode: SolverMode, - f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R, - ) -> R; + fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R; fn evaluation_is_concurrent(&self) -> bool; @@ -298,6 +292,11 @@ pub trait Interner: self, binder: ty::Binder<Self, T>, ) -> ty::Binder<Self, T>; + + fn opaque_types_defined_by( + self, + defining_anchor: Self::LocalDefId, + ) -> Self::DefiningOpaqueTypes; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` @@ -414,12 +413,8 @@ impl<I: Interner> search_graph::Cx for I { fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, I::DepNodeIndex) { I::with_cached_task(self, task) } - fn with_global_cache<R>( - self, - mode: SolverMode, - f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R, - ) -> R { - I::with_global_cache(self, mode, f) + fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R { + I::with_global_cache(self, f) } fn evaluation_is_concurrent(&self) -> bool { self.evaluation_is_concurrent() diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs index ac35215fbaa..0e94e989b97 100644 --- a/compiler/rustc_type_ir/src/outlives.rs +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -110,6 +110,18 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> { ty::Coroutine(_, args) => { args.as_coroutine().tupled_upvars_ty().visit_with(self); + // Coroutines may not outlive a region unless the resume + // ty outlives a region. This is because the resume ty may + // store data that lives shorter than this outlives region + // across yield points, which may subsequently be accessed + // after the coroutine is resumed again. + // + // Conceptually, you may think of the resume arg as an upvar + // of `&mut Option<ResumeArgTy>`, since it is kinda like + // storage shared between the callee of the coroutine and the + // coroutine body. + args.as_coroutine().resume_ty().visit_with(self); + // We ignore regions in the coroutine interior as we don't // want these to affect region inference } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index c3164550348..0cade1d6885 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -112,9 +112,9 @@ impl<I: Interner> ty::Binder<I, TraitRef<I>> { self.skip_binder().def_id } - pub fn to_host_effect_clause(self, cx: I, host: HostPolarity) -> I::Clause { + pub fn to_host_effect_clause(self, cx: I, constness: BoundConstness) -> I::Clause { self.map_bound(|trait_ref| { - ty::ClauseKind::HostEffect(HostEffectPredicate { trait_ref, host }) + ty::ClauseKind::HostEffect(HostEffectPredicate { trait_ref, constness }) }) .upcast(cx) } @@ -757,7 +757,7 @@ impl<I: Interner> fmt::Debug for NormalizesTo<I> { #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub struct HostEffectPredicate<I: Interner> { pub trait_ref: ty::TraitRef<I>, - pub host: HostPolarity, + pub constness: BoundConstness, } impl<I: Interner> HostEffectPredicate<I> { @@ -785,28 +785,8 @@ impl<I: Interner> ty::Binder<I, HostEffectPredicate<I>> { } #[inline] - pub fn host(self) -> HostPolarity { - self.skip_binder().host - } -} - -#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] -pub enum HostPolarity { - /// May be called in const environments if the callee is const. - Maybe, - /// Always allowed to be called in const environments. - Const, -} - -impl HostPolarity { - pub fn satisfies(self, goal: HostPolarity) -> bool { - match (self, goal) { - (HostPolarity::Const, HostPolarity::Const | HostPolarity::Maybe) => true, - (HostPolarity::Maybe, HostPolarity::Maybe) => true, - (HostPolarity::Maybe, HostPolarity::Const) => false, - } + pub fn constness(self) -> BoundConstness { + self.skip_binder().constness } } @@ -831,8 +811,8 @@ pub struct CoercePredicate<I: Interner> { pub b: I::Ty, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum BoundConstness { /// `Type: const Trait` /// @@ -841,14 +821,22 @@ pub enum BoundConstness { /// `Type: ~const Trait` /// /// Requires resolving to const only when we are in a const context. - ConstIfConst, + Maybe, } impl BoundConstness { + pub fn satisfies(self, goal: BoundConstness) -> bool { + match (self, goal) { + (BoundConstness::Const, BoundConstness::Const | BoundConstness::Maybe) => true, + (BoundConstness::Maybe, BoundConstness::Maybe) => true, + (BoundConstness::Maybe, BoundConstness::Const) => false, + } + } + pub fn as_str(self) -> &'static str { match self { Self::Const => "const", - Self::ConstIfConst => "~const", + Self::Maybe => "~const", } } } @@ -857,14 +845,7 @@ impl fmt::Display for BoundConstness { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Const => f.write_str("const"), - Self::ConstIfConst => f.write_str("~const"), + Self::Maybe => f.write_str("~const"), } } } - -impl<I> Lift<I> for BoundConstness { - type Lifted = BoundConstness; - fn lift_to_interner(self, _: I) -> Option<Self::Lifted> { - Some(self) - } -} diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 17a3912730f..53751f7711a 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -6,9 +6,9 @@ use super::{ }; use crate::error::TypeError; use crate::inherent::*; -use crate::solve::{Goal, SolverMode}; +use crate::solve::Goal; use crate::visit::TypeVisitableExt as _; -use crate::{self as ty, InferCtxtLike, Interner, Upcast}; +use crate::{self as ty, InferCtxtLike, Interner, TypingMode, Upcast}; pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>: TypeRelation<I> @@ -128,19 +128,19 @@ where } (ty::Alias(ty::Opaque, _), _) | (_, ty::Alias(ty::Opaque, _)) => { - match infcx.solver_mode() { - SolverMode::Normal => { - assert!(!infcx.next_trait_solver()); - structurally_relate_tys(relation, a, b) - } + assert!(!infcx.next_trait_solver()); + match infcx.typing_mode(relation.param_env()) { // During coherence, opaque types should be treated as *possibly* - // equal to any other type (except for possibly itinfcx). This is an + // equal to any other type. This is an // extremely heavy hammer, but can be relaxed in a forwards-compatible // way later. - SolverMode::Coherence => { + TypingMode::Coherence => { relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]); Ok(a) } + TypingMode::Analysis { .. } | TypingMode::PostAnalysis => { + structurally_relate_tys(relation, a, b) + } } } diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 3fd2bb61ba5..5010fc09adc 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -22,7 +22,6 @@ use rustc_index::{Idx, IndexVec}; use tracing::debug; use crate::data_structures::HashMap; -use crate::solve::SolverMode; mod global_cache; use global_cache::CacheData; @@ -48,11 +47,7 @@ pub trait Cx: Copy { fn get_tracked<T: Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T; fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex); - fn with_global_cache<R>( - self, - mode: SolverMode, - f: impl FnOnce(&mut GlobalCache<Self>) -> R, - ) -> R; + fn with_global_cache<R>(self, f: impl FnOnce(&mut GlobalCache<Self>) -> R) -> R; fn evaluation_is_concurrent(&self) -> bool; } @@ -358,7 +353,6 @@ struct ProvisionalCacheEntry<X: Cx> { } pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> { - mode: SolverMode, root_depth: AvailableDepth, /// The stack of goals currently being computed. /// @@ -374,9 +368,8 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> { } impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { - pub fn new(mode: SolverMode, root_depth: usize) -> SearchGraph<D> { + pub fn new(root_depth: usize) -> SearchGraph<D> { Self { - mode, root_depth: AvailableDepth(root_depth), stack: Default::default(), provisional_cache: Default::default(), @@ -384,10 +377,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { } } - pub fn solver_mode(&self) -> SolverMode { - self.mode - } - /// Lazily update the stack entry for the parent goal. /// This behavior is shared between actually evaluating goals /// and using existing global cache entries to make sure they @@ -829,7 +818,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { input: X::Input, available_depth: AvailableDepth, ) -> Option<X::Result> { - cx.with_global_cache(self.mode, |cache| { + cx.with_global_cache(|cache| { cache .get(cx, input, available_depth, |nested_goals| { Self::candidate_is_applicable( @@ -852,7 +841,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { input: X::Input, available_depth: AvailableDepth, ) -> Option<X::Result> { - cx.with_global_cache(self.mode, |cache| { + cx.with_global_cache(|cache| { let CacheData { result, additional_depth, encountered_overflow, nested_goals } = cache .get(cx, input, available_depth, |nested_goals| { Self::candidate_is_applicable( @@ -1041,7 +1030,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { ) { let additional_depth = final_entry.reached_depth.as_usize() - self.stack.len(); debug!(?final_entry, ?result, "insert global cache"); - cx.with_global_cache(self.mode, |cache| { + cx.with_global_cache(|cache| { cache.insert( cx, input, diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index b3f8390bbf0..fe455873051 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -58,19 +58,6 @@ pub enum Reveal { All, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SolverMode { - /// Ordinary trait solving, using everywhere except for coherence. - Normal, - /// Trait solving during coherence. There are a few notable differences - /// between coherence and ordinary trait solving. - /// - /// Most importantly, trait solving during coherence must not be incomplete, - /// i.e. return `Err(NoSolution)` for goals for which a solution exists. - /// This means that we must not make any guesses or arbitrary choices. - Coherence, -} - pub type CanonicalInput<I, T = <I as Interner>::Predicate> = ty::CanonicalQueryInput<I, QueryInput<I, T>>; pub type CanonicalResponse<I> = Canonical<I, Response<I>>; |
