From 1e990a084e61f8c425a8f6eb46eac698141c32d0 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 27 Sep 2026 13:29:52 -0400 Subject: [PATCH 1/6] wip on polymorphization --- compiler/rustc_abi/src/callconv.rs | 2 + compiler/rustc_abi/src/layout.rs | 39 +++-- compiler/rustc_abi/src/layout/simple.rs | 12 +- compiler/rustc_abi/src/layout/ty.rs | 9 +- compiler/rustc_abi/src/lib.rs | 70 ++++++-- compiler/rustc_abi/src/wrapping_range.rs | 4 +- compiler/rustc_borrowck/src/lib.rs | 2 + .../src/discriminant.rs | 2 + compiler/rustc_codegen_gcc/src/type_of.rs | 2 +- .../src/debuginfo/metadata.rs | 11 +- .../src/debuginfo/metadata/enums/cpp_like.rs | 2 + .../src/debuginfo/metadata/enums/mod.rs | 4 +- .../src/debuginfo/metadata/enums/native.rs | 1 + compiler/rustc_codegen_llvm/src/type_of.rs | 9 +- .../rustc_codegen_ssa/src/debuginfo/mod.rs | 2 + .../src/debuginfo/type_names.rs | 4 + compiler/rustc_codegen_ssa/src/mir/block.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 19 +++ compiler/rustc_codegen_ssa/src/mir/operand.rs | 1 + compiler/rustc_codegen_ssa/src/mir/place.rs | 1 + compiler/rustc_codegen_ssa/src/mir/retag.rs | 3 +- .../src/const_eval/type_info.rs | 2 + .../src/const_eval/valtrees.rs | 2 + .../src/interpret/discriminant.rs | 2 + .../src/interpret/intrinsics.rs | 6 +- .../rustc_const_eval/src/interpret/stack.rs | 2 +- .../src/interpret/validity.rs | 7 +- .../rustc_const_eval/src/interpret/visitor.rs | 3 +- .../src/util/check_validity_requirement.rs | 3 +- .../rustc_const_eval/src/util/type_name.rs | 7 +- .../src/coherence/inherent_impls.rs | 3 +- .../src/coherence/orphan.rs | 1 + .../src/hir_ty_lowering/mod.rs | 1 + .../src/variance/constraints.rs | 6 +- compiler/rustc_hir_typeck/src/cast.rs | 1 + compiler/rustc_hir_typeck/src/method/probe.rs | 1 + .../src/infer/canonical/canonicalizer.rs | 3 +- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_lint/src/reference_casting.rs | 1 + .../rustc_lint/src/types/improper_ctypes.rs | 1 + compiler/rustc_middle/src/arena.rs | 1 + compiler/rustc_middle/src/query/keys.rs | 1 + compiler/rustc_middle/src/ty/codec.rs | 13 ++ compiler/rustc_middle/src/ty/context.rs | 11 +- .../src/ty/context/impl_interner.rs | 1 + compiler/rustc_middle/src/ty/error.rs | 1 + .../rustc_middle/src/ty/inhabitedness/mod.rs | 3 +- compiler/rustc_middle/src/ty/instance.rs | 150 +++++++++++++++++- compiler/rustc_middle/src/ty/layout.rs | 14 +- compiler/rustc_middle/src/ty/mod.rs | 6 +- compiler/rustc_middle/src/ty/offload_meta.rs | 9 +- compiler/rustc_middle/src/ty/print/mod.rs | 1 + compiler/rustc_middle/src/ty/print/pretty.rs | 7 + .../src/ty/significant_drop_order.rs | 1 + .../rustc_middle/src/ty/structural_impls.rs | 3 + compiler/rustc_middle/src/ty/sty.rs | 42 ++++- compiler/rustc_middle/src/ty/trait_def.rs | 1 + compiler/rustc_middle/src/ty/util.rs | 18 ++- .../src/move_paths/builder.rs | 2 + .../src/dataflow_const_prop.rs | 1 + compiler/rustc_mir_transform/src/gvn.rs | 1 + .../src/unreachable_enum_branching.rs | 1 + compiler/rustc_monomorphize/src/collector.rs | 7 +- .../src/canonical/canonicalizer.rs | 1 + .../rustc_next_trait_solver/src/coherence.rs | 1 + .../src/solve/assembly/mod.rs | 2 + .../src/solve/assembly/structural_traits.rs | 15 +- .../src/solve/eval_ctxt/mod.rs | 1 + .../src/solve/normalizes_to.rs | 10 +- .../src/solve/trait_goals.rs | 2 + compiler/rustc_passes/src/check_export.rs | 4 +- compiler/rustc_pattern_analysis/src/rustc.rs | 1 + compiler/rustc_privacy/src/lib.rs | 2 +- compiler/rustc_public/src/abi.rs | 10 +- .../src/unstable/convert/stable/abi.rs | 2 + .../src/unstable/convert/stable/ty.rs | 2 + .../src/cfi/typeid/itanium_cxx_abi/encode.rs | 4 + .../cfi/typeid/itanium_cxx_abi/transform.rs | 7 +- compiler/rustc_serialize/src/serialize.rs | 16 ++ compiler/rustc_session/src/options.rs | 3 + compiler/rustc_symbol_mangling/src/export.rs | 1 + compiler/rustc_symbol_mangling/src/lib.rs | 11 +- compiler/rustc_symbol_mangling/src/v0.rs | 21 ++- .../rustc_target/src/callconv/loongarch.rs | 2 + compiler/rustc_target/src/callconv/mips64.rs | 3 + compiler/rustc_target/src/callconv/mod.rs | 29 ++-- .../rustc_target/src/callconv/powerpc64.rs | 1 + compiler/rustc_target/src/callconv/riscv.rs | 2 + compiler/rustc_target/src/callconv/sparc64.rs | 2 + compiler/rustc_target/src/callconv/x86_64.rs | 1 + .../traits/fulfillment_errors.rs | 1 + .../src/traits/effects.rs | 8 +- .../src/traits/project.rs | 4 +- .../src/traits/query/dropck_outlives.rs | 3 +- .../src/traits/select/candidate_assembly.rs | 8 +- .../src/traits/select/confirmation.rs | 1 + .../src/traits/select/mod.rs | 5 + .../rustc_trait_selection/src/traits/wf.rs | 1 + compiler/rustc_transmute/src/layout/tree.rs | 6 +- compiler/rustc_ty_utils/src/layout.rs | 28 +++- .../rustc_ty_utils/src/layout/invariant.rs | 20 ++- compiler/rustc_ty_utils/src/needs_drop.rs | 1 + compiler/rustc_ty_utils/src/ty.rs | 3 +- compiler/rustc_type_ir/src/fast_reject.rs | 4 + compiler/rustc_type_ir/src/flags.rs | 1 + compiler/rustc_type_ir/src/inherent.rs | 1 + compiler/rustc_type_ir/src/interner.rs | 1 + compiler/rustc_type_ir/src/outlives.rs | 2 + compiler/rustc_type_ir/src/relate.rs | 3 + compiler/rustc_type_ir/src/ty_kind.rs | 4 + compiler/rustc_type_ir/src/walk.rs | 1 + src/librustdoc/clean/mod.rs | 1 + src/librustdoc/clean/types.rs | 1 + .../passes/collect_intra_doc_links.rs | 1 + src/librustdoc/passes/collect_trait_impls.rs | 1 + .../clippy/clippy_lints/src/dereference.rs | 1 + src/tools/clippy/clippy_utils/src/ty/mod.rs | 3 + src/tools/miri/src/helpers.rs | 2 +- 118 files changed, 696 insertions(+), 127 deletions(-) diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index c6f1819405f68..1ab94bce7b208 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -98,6 +98,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { start: Size| -> Result<(HomogeneousAggregate, Size), Heterogeneous> { let is_union = match layout.fields { + FieldsShape::Opaque => return Err(Heterogeneous), FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") } @@ -148,6 +149,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?; match &self.variants { + Variants::Opaque => return Err(Heterogeneous), Variants::Single { .. } | Variants::Empty => {} Variants::Multiple { variants, .. } => { // Treat enum variants like union members. diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index fa03fb87d02d1..6936c526f04c5 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -198,7 +198,9 @@ impl LayoutCalculator { size, max_repr_align: None, unadjusted_abi_align: element.align.abi, - randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)), + randomization_seed: element + .randomization_seed + .map(|s| s.wrapping_add(Hash64::new(count))), }) } @@ -504,7 +506,7 @@ impl LayoutCalculator { let combined_seed = only_variant .iter() .map(|v| v.randomization_seed) - .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); + .try_fold(repr.field_shuffle_seed, |acc, seed| seed.map(|s| acc.wrapping_add(s))); Ok(LayoutData { variants: Variants::Single { index: only_variant_idx }, @@ -608,7 +610,7 @@ impl LayoutCalculator { let mut align = dl.aggregate_align; let mut max_repr_align = repr.align; let mut unadjusted_abi_align = align; - let mut combined_seed = repr.field_shuffle_seed; + let mut combined_seed = Some(repr.field_shuffle_seed); let mut variants_info = IndexVec::::with_capacity(variants.len()); let mut variant_layouts = variants @@ -621,7 +623,9 @@ impl LayoutCalculator { align = align.max(st.align.abi); max_repr_align = max_repr_align.max(st.max_repr_align); unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); - combined_seed = combined_seed.wrapping_add(st.randomization_seed); + combined_seed = combined_seed + .zip(st.randomization_seed) + .map(|(combined, variant)| combined.wrapping_add(variant)); Some(VariantLayout::from_layout(st)) }) @@ -790,7 +794,7 @@ impl LayoutCalculator { let mut align = dl.aggregate_align; let mut max_repr_align = repr.align; let mut unadjusted_abi_align = align; - let mut combined_seed = repr.field_shuffle_seed; + let mut combined_seed = Some(repr.field_shuffle_seed); let mut size = Size::ZERO; @@ -834,7 +838,9 @@ impl LayoutCalculator { align = align.max(st.align.abi); max_repr_align = max_repr_align.max(st.max_repr_align); unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); - combined_seed = combined_seed.wrapping_add(st.randomization_seed); + combined_seed = combined_seed + .zip(st.randomization_seed) + .map(|(combined, variant)| combined.wrapping_add(variant)); Ok(VariantLayout::from_layout(st)) }) .collect::, _>>()?; @@ -1101,9 +1107,9 @@ impl LayoutCalculator { let optimizing = &mut in_memory_order.raw[..end]; let fields_excluding_tail = &fields.raw[..end]; // unsizable tail fields are excluded so that we use the same seed for the sized and unsized layouts. - let field_seed = fields_excluding_tail - .iter() - .fold(Hash64::ZERO, |acc, f| acc.wrapping_add(f.randomization_seed)); + let field_seed = fields_excluding_tail.iter().fold(Some(Hash64::ZERO), |acc, f| { + acc.zip(f.randomization_seed).map(|(acc, seed)| acc.wrapping_add(seed)) + }); if optimize_field_order && fields.len() > 1 { // If `-Z randomize-layout` was enabled for the type definition we can shuffle @@ -1121,9 +1127,11 @@ impl LayoutCalculator { use rand::seq::SliceRandom; // `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field // ordering. - let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64( - field_seed.wrapping_add(repr.field_shuffle_seed).as_u64(), - ); + let rng_seed = field_seed + .expect("-Zrandomize-layout is incompatible with -Zpolymorphize") + .wrapping_add(repr.field_shuffle_seed) + .as_u64(); + let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64(rng_seed); // Shuffle the ordering of the fields. optimizing.shuffle(&mut rng); @@ -1373,6 +1381,7 @@ impl LayoutCalculator { offsets } FieldsShape::Primitive + | FieldsShape::Opaque | FieldsShape::Array { .. } | FieldsShape::Union(..) => { panic!("encountered a non-arbitrary layout during enum layout") @@ -1409,7 +1418,7 @@ impl LayoutCalculator { unadjusted_abi_align }; - let seed = field_seed.wrapping_add(repr.field_shuffle_seed); + let seed = field_seed.map(|field| field.wrapping_add(repr.field_shuffle_seed)); Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, @@ -1519,6 +1528,8 @@ where align: AbiAlign::new(align), max_repr_align: None, unadjusted_abi_align: elt.align.abi, - randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count.as_u64())), + randomization_seed: elt + .randomization_seed + .map(|s| s.wrapping_add(Hash64::new(count.as_u64()))), }) } diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs index 1fffb84ec21cb..a3d08566307bb 100644 --- a/compiler/rustc_abi/src/layout/simple.rs +++ b/compiler/rustc_abi/src/layout/simple.rs @@ -25,7 +25,7 @@ impl LayoutData { size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: dl.i8_align, - randomization_seed: Hash64::new(0), + randomization_seed: Some(Hash64::new(0)), } } @@ -42,7 +42,7 @@ impl LayoutData { size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: dl.i8_align, - randomization_seed: Hash64::ZERO, + randomization_seed: Some(Hash64::ZERO), } } @@ -84,7 +84,7 @@ impl LayoutData { align, max_repr_align: None, unadjusted_abi_align: align.abi, - randomization_seed: Hash64::new(randomization_seed), + randomization_seed: Some(Hash64::new(randomization_seed)), } } @@ -117,7 +117,7 @@ impl LayoutData { size, max_repr_align: None, unadjusted_abi_align: align, - randomization_seed: Hash64::new(combined_seed), + randomization_seed: Some(Hash64::new(combined_seed)), } } @@ -145,7 +145,7 @@ impl LayoutData { unadjusted_abi_align: dl.i8_align, // Variant layouts never flow back into actual layout computations, // so dummy values are fine here. - randomization_seed: Hash64::ZERO, + randomization_seed: Some(Hash64::ZERO), } } @@ -171,7 +171,7 @@ impl LayoutData { unadjusted_abi_align: parent.unadjusted_abi_align, // Variant layouts never flow back into actual layout computations, // so dummy values are fine here. - randomization_seed: Hash64::ZERO, + randomization_seed: Some(Hash64::ZERO), } } } diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index 58d20b9bd3532..eb0cb1920b5d4 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -115,6 +115,7 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display { cx: &C, offset: Size, ) -> Option; + fn is_erased_ty(this: TyAndLayout<'a, Self>) -> bool; fn is_adt(this: TyAndLayout<'a, Self>) -> bool; fn is_enum(this: TyAndLayout<'a, Self>) -> bool; fn is_never(this: TyAndLayout<'a, Self>) -> bool; @@ -377,9 +378,9 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { { match self.variants { Variants::Multiple { .. } => true, - Variants::Empty => false, + Variants::Opaque | Variants::Empty => false, Variants::Single { .. } => match &self.fields { - FieldsShape::Primitive | FieldsShape::Union(_) => false, + FieldsShape::Opaque | FieldsShape::Primitive | FieldsShape::Union(_) => false, FieldsShape::Array { count, .. } => { *count > 0 && self.field(cx, 0).has_variant_dependent_padding(cx) } @@ -474,7 +475,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { // Visit the fields of this value. For enum values the fields include the discriminant. match &self.fields { - FieldsShape::Primitive => { + FieldsShape::Opaque | FieldsShape::Primitive => { out.add_range(base_offset, self.size); } &FieldsShape::Union(field_count) => { @@ -507,7 +508,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { // Visit the fields of each variant. match &self.variants { - Variants::Empty | Variants::Single { index: _ } => { /* done */ } + Variants::Opaque | Variants::Empty | Variants::Single { index: _ } => { /* done */ } Variants::Multiple { variants, .. } => { for variant in variants.indices() { let variant = self.for_variant(cx, variant); diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 2e1f77e77b29e..d389f45693c65 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1224,7 +1224,7 @@ impl Align { /// /// An example of a rare thing actually affected by preferred alignment is aligning of statics. /// It is of effectively no consequence for layout in structs and on the stack. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable_NoContext, Decodable_NoContext)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub struct AbiAlign { pub abi: Align, @@ -1416,7 +1416,18 @@ impl Integer { } /// Floating-point types. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive( + Copy, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Debug, + Encodable_NoContext, + Decodable_NoContext +)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub enum Float { F16, @@ -1503,7 +1514,7 @@ impl Numeric { } /// Fundamental unit of memory access and layout. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable_NoContext, Decodable_NoContext)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub enum Primitive { /// The `bool` is the signedness of the `Integer` type. @@ -1570,7 +1581,7 @@ impl Primitive { } /// Information about one scalar component of a Rust type. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable_NoContext, Decodable_NoContext)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub enum Scalar { Initialized { @@ -1696,9 +1707,12 @@ impl Scalar { // NOTE: This struct is generic over the FieldIdx for rust-analyzer usage. /// Describes how the fields of a type are located in memory. -#[derive(PartialEq, Eq, Hash, Clone, Debug)] +#[derive(PartialEq, Eq, Hash, Clone, Debug, Encodable_NoContext, Decodable_NoContext)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub enum FieldsShape { + /// There may or may not be fields, and we know nothing about them. Used for `ty::Erased`. + Opaque, + /// Scalar primitives and `!`, which never have fields. Primitive, @@ -1737,6 +1751,7 @@ impl FieldsShape { #[inline] pub fn count(&self) -> usize { match *self { + FieldsShape::Opaque => 0, FieldsShape::Primitive => 0, FieldsShape::Union(count) => count.get(), FieldsShape::Array { count, .. } => count.try_into().unwrap(), @@ -1747,6 +1762,9 @@ impl FieldsShape { #[inline] pub fn offset(&self, i: usize) -> Size { match *self { + FieldsShape::Opaque => { + unreachable!("FieldsShape::offset: `Opaque`s have no fields") + } FieldsShape::Primitive => { unreachable!("FieldsShape::offset: `Primitive`s have no fields") } @@ -1769,10 +1787,14 @@ impl FieldsShape { // Primitives don't really have fields in the way that structs do, // but having this return an empty iterator for them is unhelpful // since that makes them look kinda like ZSTs, which they're not. - let pseudofield_count = if let FieldsShape::Primitive = self { 1 } else { self.count() }; + let pseudofield_count = + if let FieldsShape::Primitive | FieldsShape::Opaque = self { 1 } else { self.count() }; (0..pseudofield_count).map(move |i| match self { - FieldsShape::Primitive | FieldsShape::Union(_) | FieldsShape::Array { .. } => i, + FieldsShape::Primitive + | FieldsShape::Opaque + | FieldsShape::Union(_) + | FieldsShape::Array { .. } => i, FieldsShape::Arbitrary { in_memory_order, .. } => in_memory_order[i as u32].index(), }) } @@ -1781,7 +1803,18 @@ impl FieldsShape { /// An identifier that specifies the address space that some operation /// should operate on. Special address spaces have an effect on code generation, /// depending on the target and the address spaces it implements. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Encodable_NoContext, + Decodable_NoContext +)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub struct AddressSpace(pub u32); @@ -1798,7 +1831,7 @@ impl AddressSpace { } /// How many scalable vectors are in a `BackendRepr::ScalableVector`? -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable_NoContext, Decodable_NoContext)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub struct NumScalableVectors(pub u8); @@ -1847,7 +1880,7 @@ impl IntoDiagArg for NumScalableVectors { /// /// 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)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable_NoContext, Decodable_NoContext)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub enum BackendRepr { Scalar(Scalar), @@ -2027,9 +2060,12 @@ impl BackendRepr { /// Describes the variants of a type. // NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage. -#[derive(PartialEq, Eq, Hash, Clone, Debug)] +#[derive(PartialEq, Eq, Hash, Clone, Debug, Encodable_NoContext, Decodable_NoContext)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub enum Variants { + /// We don't know how many variants there are, nor anything about them. + Opaque, + /// The type has no valid variants. Must be uninhabited. /// /// This is the case for: @@ -2069,7 +2105,7 @@ pub enum Variants { } // NOTE: This struct is generic over the VariantIdx for rust-analyzer usage. -#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, Encodable_NoContext, Decodable_NoContext)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub enum TagEncoding { /// The tag directly stores the discriminant, but possibly with a smaller layout @@ -2110,7 +2146,7 @@ pub enum TagEncoding { }, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable_NoContext, Decodable_NoContext)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub struct Niche { pub offset: Size, @@ -2218,7 +2254,7 @@ pub enum NicheOptimizations { } // NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage. -#[derive(PartialEq, Eq, Hash, Clone)] +#[derive(PartialEq, Eq, Hash, Clone, Encodable_NoContext, Decodable_NoContext)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub struct LayoutData { /// Says where the fields are located within the layout. @@ -2274,7 +2310,8 @@ pub struct LayoutData { /// transmuted to `Foo` we aim to create probalistically distinct seeds so that Foo can choose /// to reorder its fields based on that information. The current implementation is a conservative /// approximation of this goal. - pub randomization_seed: Hash64, + // TODO: making randomization_seed an Option is maybe hacky? + pub randomization_seed: Option, } impl LayoutData { @@ -2296,6 +2333,7 @@ impl LayoutData { /// Returns `true` if the given variant is uninhabited. pub fn is_variant_uninhabited(&self, variant: VariantIdx) -> bool { match self.variants { + Variants::Opaque => false, Variants::Empty => true, Variants::Single { index } => variant != index || self.uninhabited, Variants::Multiple { ref variants, .. } => { @@ -2483,7 +2521,7 @@ pub enum AbiFromStrErr { /// /// See for more context. // NOTE: This struct is generic over the FieldIdx for rust-analyzer usage. -#[derive(PartialEq, Eq, Hash, Clone, Debug)] +#[derive(PartialEq, Eq, Hash, Clone, Debug, Encodable_NoContext, Decodable_NoContext)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub struct VariantLayout { // FIXME: ideally we'd remove these as variants should not have their own diff --git a/compiler/rustc_abi/src/wrapping_range.rs b/compiler/rustc_abi/src/wrapping_range.rs index 1e97224899dcf..e3beab4eee22c 100644 --- a/compiler/rustc_abi/src/wrapping_range.rs +++ b/compiler/rustc_abi/src/wrapping_range.rs @@ -1,6 +1,8 @@ use std::ops::RangeFull; use std::{fmt, iter}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext}; + use crate::Size; #[cfg(feature = "nightly")] use crate::StableHash; @@ -14,7 +16,7 @@ use crate::StableHash; /// 254 (-2), 255 (-1), 0, 1, 2 /// /// This is intended specifically to mirror LLVM’s `!range` metadata semantics. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable_NoContext, Decodable_NoContext)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub struct WrappingRange { pub start: u128, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 96fc9b2e37651..0242ece9b25b9 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1942,6 +1942,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { | ty::UnsafeBinder(_) | ty::Alias(_, _) | ty::Param(_) + | ty::Erased(..) | ty::Bound(_, _) | ty::Infer(_) | ty::Error(_) @@ -1984,6 +1985,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { | ty::UnsafeBinder(_) | ty::Alias(_, _) | ty::Param(_) + | ty::Erased(..) | ty::Bound(_, _) | ty::Infer(_) | ty::Error(_) diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index fd4f1d8c61e55..e34ebe382342d 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -18,6 +18,7 @@ pub(crate) fn codegen_set_discriminant<'tcx>( return; } match layout.variants { + Variants::Opaque => unreachable!(), Variants::Empty => unreachable!("we already handled uninhabited types"), Variants::Single { index } => { assert_eq!(index, variant_index); @@ -86,6 +87,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>( } let (tag_scalar, tag_field, tag_encoding) = match &layout.variants { + Variants::Opaque => unreachable!(), Variants::Empty => unreachable!("we already handled uninhabited types"), Variants::Single { index } => { let discr_val = layout diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 833ba9efe4efb..470a802bde274 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -126,7 +126,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( }; match layout.fields { - FieldsShape::Primitive | FieldsShape::Union(_) => { + FieldsShape::Opaque | FieldsShape::Primitive | FieldsShape::Union(_) => { let fill = cx.type_padding_filler(layout.size, layout.align.abi); let packed = false; let attributes = struct_attributes(packed, Some(layout.align.abi)); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index e14cdeb1505d0..e420e101e6ddd 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -462,9 +462,13 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>( debug!("type_di_node: {:?} kind: {:?}", t, t.kind()); let DINodeCreationResult { di_node, already_stored_in_typemap } = match *t.kind() { - ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { - build_basic_type_di_node(cx, t) - } + ty::Never + | ty::Erased(..) + | ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) => build_basic_type_di_node(cx, t), ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t), ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t, span), ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id, span), @@ -763,6 +767,7 @@ fn build_basic_type_di_node<'ll, 'tcx>( let (name, encoding) = match t.kind() { ty::Never => ("!", DW_ATE_unsigned), + ty::Erased(..) => ("{erased}", DW_ATE_unsigned), ty::Tuple(elements) if elements.is_empty() => { if cpp_like_debuginfo { return build_tuple_type_di_node(cx, UniqueTypeId::for_ty(cx.tcx, t)); 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 fe7f38fb195bc..fde3b8017e2f8 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 @@ -213,6 +213,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( ), |cx, enum_type_di_node| { match enum_type_and_layout.variants { + Variants::Opaque => return smallvec![], Variants::Empty => { // We don't generate any members for uninhabited types. return smallvec![]; @@ -301,6 +302,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>( } Variants::Single { .. } | Variants::Empty + | Variants::Opaque | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => { bug!( "Encountered coroutine with non-direct-tag layout: {:?}", 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 c2aa981582aaf..46a3858fafb11 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -400,7 +400,9 @@ fn compute_discriminant_value<'ll, 'tcx>( variant_index: VariantIdx, ) -> DiscrResult { match enum_type_and_layout.layout.variants() { - &Variants::Single { .. } | &Variants::Empty => DiscrResult::NoDiscriminant, + &Variants::Opaque | &Variants::Single { .. } | &Variants::Empty => { + DiscrResult::NoDiscriminant + } &Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => DiscrResult::Value( enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val, ), 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 c9cac61a8bbe1..8151350fdf107 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -356,6 +356,7 @@ fn build_discr_member_di_node<'ll, 'tcx>( let containing_scope = enum_or_coroutine_type_di_node; match enum_or_coroutine_type_and_layout.layout.variants() { + &Variants::Opaque => unreachable!(), // A single-variant or no-variant enum has no discriminant. &Variants::Single { .. } | &Variants::Empty => None, diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 0624d8db460c0..46cb4d1a64617 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -79,7 +79,7 @@ fn uncached_llvm_type<'a, 'tcx>( // FIXME(eddyb) producing readable type names for trait objects can result // in problematically distinct types due to HRTB and subtyping (see #47638). // ty::Dynamic(..) | - ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str + ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str|ty::Erased(..) // For performance reasons we use names only when emitting LLVM IR. if !cx.sess().fewer_names() => { @@ -102,7 +102,11 @@ fn uncached_llvm_type<'a, 'tcx>( }; match layout.fields { - FieldsShape::Primitive | FieldsShape::Union(_) => { + // TODO: this used to special-case on ty.is_erased(). now it doesn't do that (good!) + // but we should check elsewhere in the codebase for similar + // Erased types are represented opaquely since we don't know the types + // and exact layouts of their fields. + FieldsShape::Opaque | FieldsShape::Primitive | FieldsShape::Union(_) => { let fill = cx.type_padding_filler(layout.size, layout.align.abi); let packed = false; match name { @@ -134,6 +138,7 @@ fn struct_llfields<'a, 'tcx>( layout: TyAndLayout<'tcx>, ) -> (Vec<&'a Type>, bool) { debug!("struct_llfields: {:#?}", layout); + let field_count = layout.fields.count(); let mut packed = false; diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs index a449a86a12c28..673c5030d6f5b 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs @@ -65,6 +65,8 @@ fn tag_base_type_opt<'tcx>( }); match enum_type_and_layout.layout.variants() { + Variants::Opaque => None, + // A single-variant or no-variant enum has no discriminant. Variants::Single { .. } | Variants::Empty => None, diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 9cf68c6e3909c..053659db3ad0a 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -447,6 +447,10 @@ fn push_debuginfo_type_name<'tcx>( push_close_angle_bracket(cpp_like_debuginfo, output); } } + ty::Erased(_) => { + output.push_str("{erased}") + // TODO: should we include the layout as well? + } ty::Param(_) | ty::Error(_) | ty::Infer(_) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index c1c690791f195..aaa130f98266f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1859,7 +1859,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } - FieldsShape::Primitive | FieldsShape::Union(_) => { /* nothing to visit */ } + FieldsShape::Opaque | FieldsShape::Primitive | FieldsShape::Union(_) => { + /* nothing to visit */ + } } // If this is not a multi-variant enum, we're done. diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 8e3533deb5dfc..1109d8fb57818 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -214,6 +214,25 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // got here (`deduce_param_attrs`). That means we can *not* apply arbitrary further MIR // transforms as that may invalidate those deduced facts! + // TODO: this is a hacky temporary thing, remove or make proper + // DEBUG: dump the fully-instantiated (monomorphized) MIR going into codegen. + // Gate: set DUMP_MONO_MIR to a substring filter (empty string = dump everything). + if let Some(filter) = std::env::var_os("DUMP_MONO_MIR") { + ty::print::with_no_trimmed_paths!({ + let name = instance.to_string(); + if name.contains(&*filter.to_string_lossy()) { + let mono = instance.instantiate_mir_and_normalize_erasing_regions( + tcx, + ty::TypingEnv::fully_monomorphized(), + ty::EarlyBinder::bind(tcx, (*mir).clone()), + ); + let mut buf = Vec::new(); + let _ = mir::pretty::MirWriter::new(tcx).write_mir_fn(&mono, &mut buf); + eprintln!("=== mono MIR for {name} ===\n{}", String::from_utf8_lossy(&buf)); + } + }); + } + let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); debug!("fn_abi: {:?}", fn_abi); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index e887572ccc197..cbcc41ba072ad 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -474,6 +474,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } let (tag_scalar, tag_encoding, tag_field, variants) = match self.layout.variants { + Variants::Opaque => unreachable!(), Variants::Empty => unreachable!("we already handled uninhabited types"), Variants::Single { index } => { let discr_val = diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 6c6d20568a9f9..835b003548395 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -491,6 +491,7 @@ pub(super) fn codegen_tag_value<'tcx, V>( } Ok(match layout.variants { + Variants::Opaque => unreachable!(), Variants::Empty => unreachable!("we already handled uninhabited types"), Variants::Single { index } => { assert_eq!(index, variant_index); diff --git a/compiler/rustc_codegen_ssa/src/mir/retag.rs b/compiler/rustc_codegen_ssa/src/mir/retag.rs index 6a3316fa93992..b1ccaf63f5c14 100644 --- a/compiler/rustc_codegen_ssa/src/mir/retag.rs +++ b/compiler/rustc_codegen_ssa/src/mir/retag.rs @@ -100,7 +100,7 @@ impl<'a, 'tcx, V> RetagPlan { is_fn_entry: bool, ) -> Option> { let field_plans = match &layout.fields { - FieldsShape::Union(_) | FieldsShape::Primitive => None, + FieldsShape::Union(_) | FieldsShape::Primitive | FieldsShape::Opaque => None, FieldsShape::Arbitrary { .. } => { let mut field_plans = FxIndexMap::default(); for ix in layout.fields.index_by_increasing_offset() { @@ -121,6 +121,7 @@ impl<'a, 'tcx, V> RetagPlan { let mut variant_plans = FxIndexMap::default(); match &layout.variants { + Variants::Opaque => {} Variants::Single { .. } | Variants::Empty => {} Variants::Multiple { variants, .. } => { for ix in variants.indices() { diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index 0df2e9b5fd0ae..2798d0f3c7451 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -155,6 +155,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { | ty::Never | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(..) @@ -252,6 +253,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { | ty::Tuple(..) | ty::Alias(..) | ty::Param(..) + | ty::Erased(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 6cb327f1efca6..631623ad45e0c 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -202,6 +202,7 @@ fn const_to_valtree_inner<'tcx>( | ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) | ty::Param(_) + | ty::Erased(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(_) @@ -369,6 +370,7 @@ pub fn valtree_to_const_value<'tcx>( | ty::Infer(ty::FreshFloatTy(_)) | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(_) diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index b3d4193bb8577..055cca1e4e193 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -66,6 +66,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // We use "tag" to refer to how the discriminant is encoded in memory, which can be either // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`). let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout().variants { + Variants::Opaque => unreachable!(), Variants::Empty => { throw_ub!(UninhabitedEnumVariantRead(None)); } @@ -258,6 +259,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } match layout.variants { + abi::Variants::Opaque => unreachable!(), abi::Variants::Empty => unreachable!("we already handled uninhabited types"), abi::Variants::Single { .. } => { // The tag of a `Single` enum is like the tag of the niched diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index b8b372ad1dab1..60a661a3a964b 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -260,7 +260,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ty::Adt(adt, _) => { ConstValue::from_target_usize(adt.variants().len() as u64, &tcx) } - ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => { + ty::Alias(..) + | ty::Param(_) + | ty::Erased(..) + | ty::Placeholder(_) + | ty::Infer(_) => { throw_inval!(TooGeneric) } ty::Pat(..) => unreachable!(), diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 8a731e25d8f4b..e2dd474d8f795 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -536,7 +536,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ty::UnsafeBinder(ty) => is_very_trivially_sized(ty.skip_binder()), - ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false, + ty::Alias(..) | ty::Param(_) | ty::Erased(..) | ty::Placeholder(..) => false, ty::Infer(ty::TyVar(_)) => false, diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index edfd8b9488e74..541df7a122b6d 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -376,6 +376,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { ) -> PathElem<'tcx> { // First, check if we are projecting to a variant. match layout.variants { + Variants::Opaque => unreachable!(), Variants::Multiple { tag_field, .. } => { if tag_field.as_usize() == field { return match layout.ty.kind() { @@ -423,6 +424,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { ty::Adt(def, ..) if def.is_enum() => { // we might be projecting *to* a variant, or to a field *in* a variant. match layout.variants { + Variants::Opaque => unreachable!(), Variants::Single { index } => { // Inside a variant PathElem::Field(def.variant(index).fields[FieldIdx::from_usize(field)].name) @@ -991,6 +993,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { | ty::Placeholder(..) | ty::Bound(..) | ty::Param(..) + | ty::Erased(..) | ty::Alias(..) | ty::CoroutineWitness(..) => bug!("Encountered invalid type {:?}", ty), } @@ -1189,7 +1192,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } // Just recursively add all the fields of everything to the output. match &layout.fields { - FieldsShape::Primitive => { + FieldsShape::Opaque | FieldsShape::Primitive => { out.add_range(base_offset, layout.size); } &FieldsShape::Union(fields) => { @@ -1223,7 +1226,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } // Don't forget potential other variants. match &layout.variants { - Variants::Single { .. } | Variants::Empty => { + Variants::Opaque | Variants::Single { .. } | Variants::Empty => { // Fully handled above. } Variants::Multiple { variants, .. } => { diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index c80a082674141..55b92e04d51e6 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -141,7 +141,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { // Visit the fields of this value. match &v.layout().fields { - FieldsShape::Primitive => {} + FieldsShape::Opaque | FieldsShape::Primitive => {} &FieldsShape::Union(fields) => { self.visit_union(v, fields)?; } @@ -160,6 +160,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { } match v.layout().variants { + Variants::Opaque => {} // If this is a multi-variant layout, find the right variant and proceed // with *its* fields. Variants::Multiple { .. } => { 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 f7065557f4127..12d0eeb82c590 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -150,7 +150,7 @@ fn check_validity_requirement_lax<'tcx>( // If we have not found an error yet, we need to recursively descend into fields. match &this.fields { - FieldsShape::Primitive | FieldsShape::Union { .. } => {} + FieldsShape::Opaque | FieldsShape::Primitive | FieldsShape::Union { .. } => {} FieldsShape::Array { .. } => { // Arrays never have scalar layout in LLVM, so if the array is not actually // accessed, there is no LLVM UB -- therefore we can skip this. @@ -166,6 +166,7 @@ fn check_validity_requirement_lax<'tcx>( } match &this.variants { + Variants::Opaque => {} Variants::Empty => return Ok(false), Variants::Single { .. } => { // All fields of this single variant have already been checked above, there is nothing diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index d0cd1f57479c0..0db30adfdaf57 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -45,7 +45,12 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { | ty::UnsafeBinder(_) => self.pretty_print_type(ty), // Placeholders (all printed as `_` to uniformize them). - ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { + ty::Param(_) + | ty::Erased(..) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(_) + | ty::Error(_) => { write!(self, "_")?; Ok(()) } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 591ff35becf81..c52fa36098786 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -209,7 +209,8 @@ impl<'tcx> InherentCollect<'tcx> { .. }, ) - | ty::Param(_) => { + | ty::Param(_) + | ty::Erased(..) => { Err(self.tcx.dcx().emit_err(diagnostics::InherentNominal { span: item_span })) } ty::FnDef(..) diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index d2c3a08eb714f..92685e9f6ee80 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -248,6 +248,7 @@ pub(crate) fn orphan_check_impl( | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) + | ty::Erased(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => { 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 4fa02926f15d8..fe3c28e73184c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -3608,6 +3608,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { | ty::CoroutineWitness(_, _) | ty::Never | ty::Param(_) + | ty::Erased(..) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Slice(..) => Ty::new_error( diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index cfab2ed340910..ebba3959bbef0 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -318,7 +318,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // types, where we use Error as the Self type } - ty::Placeholder(..) | ty::CoroutineWitness(..) | ty::Bound(..) | ty::Infer(..) => { + ty::Placeholder(..) + | ty::CoroutineWitness(..) + | ty::Erased(..) + | ty::Bound(..) + | ty::Infer(..) => { bug!("unexpected type encountered in variance inference: {}", ty); } } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 14cb73e28c871..a4e5f41393203 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -144,6 +144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Param(p) => Some(PointerKind::OfParam(p)), // Insufficient type information. ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => None, + ty::Erased(..) => bug!("erased type not expected here"), ty::Bool | ty::Char diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index c74047590331c..6ee9c177d02c5 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -950,6 +950,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::Error(..) | ty::FnDef(..) | ty::FnPtr(..) + | ty::Erased(..) | ty::Infer(..) | ty::Pat(..) | ty::Placeholder(..) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index f1f2077f81937..90d10190c19fb 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -421,7 +421,8 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { | ty::Alias(..) | ty::Foreign(..) | ty::Pat(..) - | ty::Param(..) => { + | ty::Param(..) + | ty::Erased(..) => { if t.flags().intersects(self.needs_canonical_flags) { t.super_fold_with(self) } else { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 34ac92faef88c..ad3bd05f785bd 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -880,6 +880,7 @@ fn test_unstable_options_tracking_hash() { ); tracked!(plt, Some(true)); tracked!(polonius, Polonius::Legacy); + tracked!(polymorphize, true); tracked!(precise_enum_drop_elaboration, false); tracked!(profiler_runtime, "abc".to_string()); tracked!(reg_struct_return, true); diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index d61dfb5b03932..8cf642aeb97fc 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -309,6 +309,7 @@ fn is_ty_fully_unsafe_celled<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool | ty::Dynamic(..) | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(_) diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index 04b381261e428..3b596d5b48e46 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -971,6 +971,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }, ty::Param(..) + | ty::Erased(..) | ty::Alias( _, ty::AliasTy { diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index d2e6c4bbe2466..737401fa55ac4 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -14,6 +14,7 @@ use crate::ty::{self, Ty, TyCtxt}; rustc_arena::declare_arena! { layout: rustc_abi::LayoutData, + param_layout: rustc_middle::ty::ParamLayoutData, proxy_coroutine_layout: rustc_middle::mir::CoroutineLayout<'tcx>, fn_abi: rustc_target::callconv::FnAbi<'tcx, Ty<'tcx>>, adt_def: rustc_middle::ty::AdtDefData, diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 2bfe80f444090..8d85cf2456ffd 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -468,6 +468,7 @@ fn def_id_of_type_cached<'a>(ty: Ty<'a>, visited: &mut SsoHashSet>) -> Op | ty::UnsafeBinder(_) | ty::Placeholder(..) | ty::Param(_) + | ty::Erased(..) | ty::Infer(_) | ty::Bound(..) | ty::Error(_) diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 81462e214b20f..d3aa67ceb9fd8 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -251,6 +251,19 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable for mir::Place<'tcx> { } } +impl<'tcx, S: TyEncoder<'tcx>> Encodable for ty::ParamLayout<'tcx> { + fn encode(&self, s: &mut S) { + self.0.0.encode(s); + } +} + +impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::ParamLayout<'tcx> { + fn decode(decoder: &mut D) -> Self { + let data = ty::ParamLayoutData::decode(decoder); + decoder.interner().mk_param_layout(data) + } +} + impl<'tcx, D: TyDecoder<'tcx>> Decodable for CanonicalVarKinds<'tcx> { fn decode(decoder: &mut D) -> Self { let len = decoder.read_usize(); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index fdc706f4b043b..08af8441bd8a7 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -73,9 +73,9 @@ use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Clause, ClausePolarity, Clauses, Const, ConstKind, FnSigKind, GenericArg, GenericArgs, GenericArgsRef, GenericParamDefKind, List, - ListWithCachedTypeInfo, ParamConst, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, - Predicate, PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, - TyVid, ValTree, ValTreeKind, Visibility, + ListWithCachedTypeInfo, ParamConst, ParamLayout, ParamLayoutData, Pattern, PatternKind, + PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions, + TraitObjectVisitor, Ty, TyKind, TyVid, ValTree, ValTreeKind, Visibility, }; impl<'tcx> rustc_type_ir::inherent::DefId> for DefId { @@ -157,6 +157,7 @@ pub struct CtxtInterners<'tcx> { const_allocation: InternedSet<'tcx, Allocation>, bound_variable_kinds: InternedSet<'tcx, List>>, layout: InternedSet<'tcx, LayoutData>, + param_layout: InternedSet<'tcx, ParamLayoutData>, adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData>>, predefined_opaques_in_body: InternedSet<'tcx, List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>>, @@ -196,6 +197,7 @@ impl<'tcx> CtxtInterners<'tcx> { const_allocation: InternedSet::with_capacity(N), bound_variable_kinds: InternedSet::with_capacity(N * 2), layout: InternedSet::with_capacity(N), + param_layout: InternedSet::with_capacity(N), adt_def: InternedSet::with_capacity(N), external_constraints: InternedSet::with_capacity(N), predefined_opaques_in_body: InternedSet::with_capacity(N), @@ -1730,6 +1732,7 @@ nop_lift! { const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx> } nop_lift! { predicate; Predicate<'a> => Predicate<'tcx> } nop_lift! { predicate; Clause<'a> => Clause<'tcx> } nop_lift! { layout; Layout<'a> => Layout<'tcx> } +nop_lift! { param_layout; ParamLayout<'a> => ParamLayout<'tcx> } nop_lift! { valtree; ValTree<'a> => ValTree<'tcx> } impl<'a, 'tcx> Lift> for Interned<'a, RegionKind<'a>> { @@ -1866,6 +1869,7 @@ impl<'tcx> TyCtxt<'tcx> { Tuple, Bound, Param, + Erased, Infer, Alias, Pat, @@ -2017,6 +2021,7 @@ direct_interners! { pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>, const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutData): Layout -> Layout<'tcx>, + param_layout: pub mk_param_layout(ParamLayoutData): ParamLayout -> ParamLayout<'tcx>, adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, external_constraints: pub mk_external_constraints(ExternalConstraintsData>): ExternalConstraints -> ExternalConstraints<'tcx>, diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index a6688b668aab3..383a1d0008f8c 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -109,6 +109,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type Pat = Pattern<'tcx>; type PatList = &'tcx List>; type Safety = hir::Safety; + type ParamLayout = ty::ParamLayout<'tcx>; type Consts = &'tcx List>; type ParamConst = ty::ParamConst; diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index fb4e30b161d44..6bfcb3cfe30d0 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -227,6 +227,7 @@ impl<'tcx> Ty<'tcx> { } ty::Alias(_, ty::AliasTy { kind: ty::Free { .. }, .. }) => "type alias".into(), ty::Param(_) => "type parameter".into(), + ty::Erased(..) => "erased type parameter".into(), ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }) => "opaque type".into(), } } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 03c5c21de02c9..e768ec4dbabe7 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -294,7 +294,8 @@ impl<'tcx> OpsemInhabitedCtx<'tcx> { | ty::FnPtr(..) | ty::FnDef(..) => true, ty::Dynamic(..) => true, // We can't reason about traits, assume they are inhabited - ty::Slice(..) => true, // Slices can always be empty + ty::Erased(..) => true, // We can't reason about erased types, assume they are inhabited + ty::Slice(..) => true, // Slices can always be empty ty::Never => false, // Types where we recurse diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 1a00293f8ffc6..cc3aafa882147 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -1,5 +1,7 @@ +use std::ops::ControlFlow; use std::{assert_matches, fmt}; +use rustc_abi::{Layout, LayoutData}; use rustc_attr_ir::lang_items::LangItem; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; @@ -16,8 +18,8 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::print::{FmtPrinter, Print}; use crate::ty::{ - self, AssocContainer, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + self, AssocContainer, EarlyBinder, GenericArgs, GenericArgsRef, ParamTy, Ty, TyCtxt, + TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; /// An `InstanceKind` along with the args that are needed to substitute the instance. @@ -991,6 +993,150 @@ impl<'tcx> Instance<'tcx> { tcx.try_normalize_erasing_regions(typing_env, v.instantiate_identity()) } } + + // TODO: this and/or is_ty_param_polymorphizable should probably be queries, + // used less ad hoc, and located somewhere else + #[instrument(level = "debug", skip(tcx), ret)] + pub fn polymorphize(&self, tcx: TyCtxt<'tcx>) -> Self { + if !tcx.sess.opts.unstable_opts.polymorphize { + return *self; + } + let InstanceKind::Item(def_id) = self.def else { + return *self; + }; + if tcx.intrinsic(def_id).is_some() { + // Intrinsics sometimes do weird stuff with generics, where they are generic + // but rustc will ICE if they are called with unexpected types. + // TODO: is there any way this is visible from generic user code that doesn't use intrinsics? + return *self; + } + // A lot of private/perma-unstable code for atomics completely breaks parametricity + // by ICEing if generic params are not instantiated with specific types. + // Don't polymorphize those. + // TODO: this is horrifically hacky, need better solution. probably lang items, + // or maybe marker traits that bound the generics (and the traits are lang items) + if tcx.opt_item_name(def_id).map_or(false, |n| n.as_str().contains("atomic_")) { + return *self; + } + + let generics = tcx.generics_of(def_id); + let clauses: Vec<_> = tcx + .clauses_of(def_id) + .instantiate_identity(tcx) + .into_iter() + .map(|(c, _)| c.skip_norm_wip()) + .collect(); + let args = + tcx.mk_args_from_iter(self.args.iter().enumerate().map( + |(idx, arg)| match arg.kind() { + ty::GenericArgKind::Type(ty) => { + let param_ty = ParamTy::for_def(generics.param_at(idx, tcx)); + let layout = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) + .unwrap() + .layout; + if is_ty_param_polymorphizable(tcx, &clauses, param_ty) + // FIXME: pass drop glue in sidecar to relax this + && !ty.needs_drop(tcx, ty::TypingEnv::fully_monomorphized()) + // FIXME: track metadata layout in ParamLayout to relax this + && layout.is_sized() + // FIXME: figure out how to handle uninhabited types -- should they be erased? + // (causes issues with comparing layout inhabitedness w/ opsem inhabitedness) + && !layout.uninhabited + { + let param_layout = make_param_layout(tcx, layout); + let erased_ty = tcx.mk_ty_from_kind(ty::Erased(param_layout)); + erased_ty.into() + } else { + arg + } + } + ty::GenericArgKind::Lifetime(_) | ty::GenericArgKind::Const(_) => arg, + }, + )); + Self { def: self.def, args } + } +} + +fn make_param_layout<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) -> ty::ParamLayout<'tcx> { + let LayoutData { + fields: _, + variants: _, + backend_repr, + largest_niche, + uninhabited: _, + align: rustc_abi::AbiAlign { abi: align }, + size, + max_repr_align: _, + unadjusted_abi_align: _, + randomization_seed: _, + } = *layout.0.0; + tcx.mk_param_layout(ty::ParamLayoutData { backend_repr, largest_niche, align, size }) +} + +#[instrument(level = "debug", ret, skip(tcx))] +fn is_ty_param_polymorphizable<'tcx>( + tcx: TyCtxt<'tcx>, + clauses: &[ty::Clause<'tcx>], + param_ty: ParamTy, +) -> bool { + for clause in clauses { + // FIXME: is skip_binder appropriate? + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(trait_predicate) => { + let is_for_param = trait_predicate.self_ty().is_param(param_ty.index); + if is_for_param + && tcx.is_lang_item(trait_predicate.def_id(), LangItem::Sized) + { + // FIXME: what about rest of Sized hierarchy? + debug!("found Sized bound -> doesn't matter"); + } else if has_param(param_ty, trait_predicate) { + debug!("polymorphization disqualified by {clause:?}"); + return false; + } + } + ty::ClauseKind::Projection(projection_predicate) => { + if has_param(param_ty, projection_predicate) { + debug!("polymorphization disqualified by {clause:?}"); + return false; + } + } + ty::ClauseKind::ConstArgHasType(_, ty) => { + if has_param(param_ty, ty) { + debug!("polymorphization disqualified by {clause:?}"); + return false; + } + } + ty::ClauseKind::RegionOutlives(..) + // TODO: maybe disqualify T: 'static since that's needed for TypeId on stable? + // might allow ignoring TypeId for now without breaking stuff. + | ty::ClauseKind::TypeOutlives(..) + | ty::ClauseKind::WellFormed(..) + | ty::ClauseKind::HostEffect(..) + | ty::ClauseKind::ConstEvaluatable(..) + | ty::ClauseKind::UnstableFeature(..) => {} + } + } + true +} + +fn has_param<'tcx, T: TypeVisitable>>(param_ty: ParamTy, t: T) -> bool { + t.visit_with(&mut HasParamVisitor { param_ty }).is_break() +} + +struct HasParamVisitor { + param_ty: ParamTy, +} + +impl<'tcx> TypeVisitor> for HasParamVisitor { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { + if t.is_param(self.param_ty.index) { + return ControlFlow::Break(()); + } + t.super_visit_with(self) + } } fn needs_fn_once_adapter_shim( diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 4ee2e5c7e3fdd..1950ad144d267 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -807,6 +807,8 @@ where variant_index: VariantIdx, ) -> TyAndLayout<'tcx> { let layout = match this.variants { + Variants::Opaque => bug!("`ty_and_layout_for_variant` on opaque layout"), + // If all variants but one are uninhabited, the variant layout is the enum layout. Variants::Single { index } if index == variant_index => { return this; @@ -986,7 +988,7 @@ where ), ty::Coroutine(def_id, args) => match this.variants { - Variants::Empty => unreachable!(), + Variants::Opaque | Variants::Empty => unreachable!(), Variants::Single { index } => TyMaybeWithLayout::Ty( args.as_coroutine() .state_tys(def_id, tcx) @@ -1009,6 +1011,7 @@ where // ADTs. ty::Adt(def, args) => { match this.variants { + Variants::Opaque => unreachable!(), Variants::Single { index } => { let field = &def.variant(index).fields[FieldIdx::from_usize(i)]; TyMaybeWithLayout::Ty(field.ty(tcx, args).skip_norm_wip()) @@ -1027,6 +1030,8 @@ where | ty::Bound(..) | ty::Placeholder(..) | ty::Param(_) + // TODO: probably need to support this + | ty::Erased(..) | ty::Infer(_) | ty::Error(_) => bug!("TyAndLayout::field: unexpected type `{}`", this.ty), } @@ -1122,8 +1127,11 @@ where }) } + ty::Erased(..) => None, + _ => { let mut data_variant = match &this.variants { + Variants::Opaque => unreachable!(), // Within the discriminant field, only the niche itself is // always initialized, so we only check for a pointer at its // offset. @@ -1226,6 +1234,10 @@ where pointee_info } + fn is_erased_ty(this: TyAndLayout<'tcx>) -> bool { + this.ty.is_erased() + } + fn is_adt(this: TyAndLayout<'tcx>) -> bool { matches!(this.ty.kind(), ty::Adt(..)) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 1f2ffb17cc2c7..e42b35916e3f5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -98,9 +98,9 @@ pub use self::sty::{ Alias, AliasTy, AliasTyKind, Article, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig, FnSigKind, FreeAliasTy, InherentAliasTy, InlineConstArgs, InlineConstArgsParts, - OpaqueAliasTy, ParamConst, ParamTy, PlaceholderConst, PlaceholderRegion, PlaceholderType, - PolyFnSig, ProjectionAliasTy, TyKind, TypeAndMut, TypingMode, TypingModeEqWrapper, - Unnormalized, UpvarArgs, + OpaqueAliasTy, ParamConst, ParamLayout, ParamLayoutData, ParamTy, PlaceholderConst, + PlaceholderRegion, PlaceholderType, PolyFnSig, ProjectionAliasTy, TyKind, TypeAndMut, + TypingMode, TypingModeEqWrapper, Unnormalized, UpvarArgs, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ diff --git a/compiler/rustc_middle/src/ty/offload_meta.rs b/compiler/rustc_middle/src/ty/offload_meta.rs index a58e517e05f61..ed248a54330de 100644 --- a/compiler/rustc_middle/src/ty/offload_meta.rs +++ b/compiler/rustc_middle/src/ty/offload_meta.rs @@ -120,9 +120,12 @@ impl MappingFlags { } // FIXME: This should not treat aliases this way. - ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Alias(_, _) | ty::Param(_) => { - MappingFlags::TO - } + ty::Adt(_, _) + | ty::Tuple(_) + | ty::Array(_, _) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Erased(..) => MappingFlags::TO, ty::RawPtr(_, Not) | ty::Ref(_, _, Not) => MappingFlags::TO, diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 451a75e52d2d9..c0f82b4c71b3e 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -339,6 +339,7 @@ fn characteristic_def_id_of_type_cached<'a>( | ty::Alias(..) | ty::Placeholder(..) | ty::Param(_) + | ty::Erased(..) | ty::Infer(_) | ty::Bound(..) | ty::Error(_) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index cafe93c591090..c81b0f43627b5 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -825,6 +825,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } ty::Error(_) => write!(self, "{{type error}}")?, ty::Param(ref param_ty) => param_ty.print(self)?, + ty::Erased(layout) => { + layout.print(self)?; + } ty::Bound(debruijn, bound_ty) => match bound_ty.kind { ty::BoundTyKind::Anon => { rustc_type_ir::debug_bound_var(self, debruijn, bound_ty.var)? @@ -3398,6 +3401,10 @@ define_print_and_forward_display! { write!(p, "{}", self.name)?; } + ty::ParamLayout<'tcx> { + write!(p, "{{size={} align={} ...}}", self.0.size.bytes(), self.0.align.bytes())?; + } + ty::Term<'tcx> { match self.kind() { ty::TermKind::Ty(ty) => ty.print(p)?, diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs index c5b50163fbbb1..1a1ae96f2fc7c 100644 --- a/compiler/rustc_middle/src/ty/significant_drop_order.rs +++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs @@ -133,6 +133,7 @@ pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { | ty::FnPtr(_, _) | ty::Tuple(_) | ty::Dynamic(_, _) + | ty::Erased(..) | ty::Alias(_, _) | ty::Bound(_, _) | ty::Pat(_, _) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 300c70e04ede6..aa70990e3e562 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -367,6 +367,7 @@ impl<'tcx> TypeSuperFoldable> for Ty<'tcx> { | ty::Error(_) | ty::Infer(_) | ty::Param(..) + | ty::Erased(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Never @@ -406,6 +407,7 @@ impl<'tcx> TypeSuperFoldable> for Ty<'tcx> { | ty::Error(_) | ty::Infer(_) | ty::Param(..) + | ty::Erased(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Never @@ -461,6 +463,7 @@ impl<'tcx> TypeSuperVisitable> for Ty<'tcx> { | ty::Bound(..) | ty::Placeholder(..) | ty::Param(..) + | ty::Erased(..) | ty::Never | ty::Foreign(..) => V::Result::output(), } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 925915c88cdb4..4a193e3ba5d6e 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -7,12 +7,19 @@ use std::debug_assert_matches; use std::ops::{ControlFlow, Range}; use hir::def::{CtorKind, DefKind}; -use rustc_abi::{FIRST_VARIANT, FieldIdx, NumScalableVectors, ScalableElt, VariantIdx}; +use rustc_abi::{ + Align, BackendRepr, FIRST_VARIANT, FieldIdx, Niche, NumScalableVectors, ScalableElt, Size, + VariantIdx, +}; use rustc_attr_ir::lang_items::LangItem; +use rustc_data_structures::intern::Interned; use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_macros::{StableHash, TyDecodable, TyEncodable, TypeFoldable, extension}; +use rustc_macros::{ + Decodable_NoContext, Encodable_NoContext, StableHash, TyDecodable, TyEncodable, TypeFoldable, + extension, +}; use rustc_span::{DUMMY_SP, Span, Symbol, bug, kw, sym}; use rustc_type_ir::TyKind::*; use rustc_type_ir::solve::SizedTraitKind; @@ -360,6 +367,17 @@ impl ParamConst { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, StableHash)] +pub struct ParamLayout<'tcx>(pub Interned<'tcx, ParamLayoutData>); + +#[derive(Clone, Debug, PartialEq, Eq, Hash, StableHash, Encodable_NoContext, Decodable_NoContext)] +pub struct ParamLayoutData { + pub backend_repr: BackendRepr, + pub largest_niche: Option, + pub align: Align, + pub size: Size, +} + /// Constructors for `Ty` impl<'tcx> Ty<'tcx> { /// Avoid using this in favour of more specific `new_*` methods, where possible. @@ -1245,6 +1263,11 @@ impl<'tcx> Ty<'tcx> { } } + #[inline] + pub fn is_erased(self) -> bool { + matches!(self.kind(), ty::Erased(..)) + } + #[inline] pub fn is_slice(self) -> bool { matches!(self.kind(), Slice(_)) @@ -1712,7 +1735,7 @@ impl<'tcx> Ty<'tcx> { ty::Adt(adt, _) if adt.is_enum() => adt.repr().discr_type().to_ty(tcx), ty::Coroutine(_, args) => args.as_coroutine().discr_ty(tcx), - ty::Param(_) | ty::Alias(..) | ty::Infer(ty::TyVar(_)) => { + ty::Param(_) | ty::Erased(..) | ty::Alias(..) | ty::Infer(ty::TyVar(_)) => { let assoc_items = tcx.associated_item_def_ids( tcx.require_lang_item(LangItem::DiscriminantKind, DUMMY_SP), ); @@ -1805,7 +1828,7 @@ impl<'tcx> Ty<'tcx> { // We don't know the metadata of `self`, but it must be equal to the // metadata of `tail`. - ty::Param(_) | ty::Alias(..) => Err(tail), + ty::Param(_) | ty::Erased(..) | ty::Alias(..) => Err(tail), ty::UnsafeBinder(_) => unimplemented!("FIXME(unsafe_binder)"), @@ -1984,6 +2007,7 @@ impl<'tcx> Ty<'tcx> { SizedTraitKind::Sized => false, SizedTraitKind::MetaSized => true, }, + ty::Erased(..) => true, ty::Foreign(..) => match sizedness { SizedTraitKind::Sized | SizedTraitKind::MetaSized => false, @@ -2058,9 +2082,12 @@ impl<'tcx> Ty<'tcx> { // Needs normalization or revealing to determine, so no is the safe answer. ty::Alias(..) => false, - ty::Param(..) | ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(..) => { - false - } + ty::Param(..) + | ty::Erased(..) + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(..) + | ty::Error(..) => false, } } @@ -2074,6 +2101,7 @@ impl<'tcx> Ty<'tcx> { | ty::Str | ty::Never | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(_) | ty::Bound(..) => true, diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 114e5331b8b9b..5b7ff5025eb9e 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -174,6 +174,7 @@ impl<'tcx> TyCtxt<'tcx> { | ty::CoroutineClosure(..) | ty::Coroutine(_, _) | ty::Never + | ty::Erased(..) | ty::Tuple(_) | ty::UnsafeBinder(_) => { let simp = ty::fast_reject::simplify_type( diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 0974e0a332ecd..6f0c9a8c3984e 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1217,6 +1217,7 @@ impl<'tcx> Ty<'tcx> { | ty::Infer(_) | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(_) => false, } } @@ -1267,6 +1268,7 @@ impl<'tcx> Ty<'tcx> { | ty::Infer(_) | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(_) => false, } } @@ -1321,6 +1323,7 @@ impl<'tcx> Ty<'tcx> { | ty::Infer(_) | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(_) => false, } } @@ -1486,9 +1489,12 @@ impl<'tcx> Ty<'tcx> { // // FIXME(ecstaticmorse): Maybe we should `bug` here? This should probably only be // called for known, fully-monomorphized types. - ty::Alias(..) | ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) => { - false - } + ty::Alias(..) + | ty::Param(_) + | ty::Erased(..) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(_) => false, ty::Foreign(_) | ty::CoroutineWitness(..) | ty::Error(_) | ty::UnsafeBinder(_) => false, } @@ -1551,8 +1557,14 @@ pub fn needs_drop_components_with_async<'tcx>( | ty::Str => Ok(SmallVec::new()), // Foreign types can never have destructors. + // FIXME: here, foreign types are ignored, but in the NeedsDropTypes iterator, + // foreign types are considered to be needing drop always. noticed in the course + // of an unrelated change. ty::Foreign(..) => Ok(SmallVec::new()), + // TODO: this should be changed once Erased types can have drop impls + ty::Erased(..) => Ok(SmallVec::new()), + // FIXME(zetanumbers): Temporary workaround for async drop of dynamic types ty::Dynamic(..) | ty::Error(_) => { if asyncness.is_async() { diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 26628a05188d7..4d6845d2d2b95 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -168,6 +168,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { | ty::UnsafeBinder(_) | ty::Alias(_, _) | ty::Param(_) + | ty::Erased(..) | ty::Bound(_, _) | ty::Infer(_) | ty::Error(_) @@ -208,6 +209,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { | ty::UnsafeBinder(_) | ty::Alias(_, _) | ty::Param(_) + | ty::Erased(..) | ty::Bound(_, _) | ty::Infer(_) | ty::Error(_) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index e52a9a847b119..4ee3e40d578ed 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -865,6 +865,7 @@ fn try_write_constant<'tcx>( | ty::Foreign(..) | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Closure(..) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index e1b1f6f9ff68c..2157236b3ec0e 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1743,6 +1743,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { | ty::Infer(_) | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(_) => true, } } diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs index d33574b93c43e..6ac4e8652e7e9 100644 --- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs @@ -55,6 +55,7 @@ fn variant_discriminants<'tcx>( tcx: TyCtxt<'tcx>, ) -> FxHashSet { match &layout.variants { + Variants::Opaque => unreachable!(), Variants::Empty => { // Uninhabited, no valid discriminant. FxHashSet::default() diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index bfe3ba91bb6bc..4e7f7465265a5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1097,7 +1097,10 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> return true; } - if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(tcx).is_some() { + // TODO: polymorphize should not be ad hoc like this + if tcx.is_reachable_non_generic(def_id) + || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some() + { // We can link to the item in question, no instance needed in this crate. return false; } @@ -1230,7 +1233,7 @@ fn create_fn_mono_item<'tcx>( crate::util::dump_closure_profile(tcx, instance); } - respan(source, MonoItem::Fn(instance)) + respan(source, MonoItem::Fn(instance.polymorphize(tcx))) } /// Creates a `MonoItem` for each method that is referenced by the vtable for diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index ea19d36f5d0cf..41c88bc18fe23 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -405,6 +405,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { | ty::Tuple(_) | ty::Alias(_, _) | ty::Bound(_, _) + | ty::Erased(..) | ty::Error(_) => { return t.super_fold_with(self); } diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs index ad6fc98601f69..aaa04d86f1d01 100644 --- a/compiler/rustc_next_trait_solver/src/coherence.rs +++ b/compiler/rustc_next_trait_solver/src/coherence.rs @@ -348,6 +348,7 @@ where | ty::UnsafeBinder(_) => self.found_non_local_ty(ty), ty::Param(..) => panic!("unexpected ty param"), + ty::Erased(..) => panic!("unexpected erased param type"), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => { match self.in_crate { 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 ae538441499e0..932933a20975f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -819,6 +819,7 @@ where | ty::Never | ty::Tuple(_) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(..) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Error(_) => return Ok(()), @@ -963,6 +964,7 @@ where | ty::Never | ty::Tuple(_) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(..) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Error(_) => return, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index c92fdea176670..2554be01cf461 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -51,6 +51,7 @@ where ty::Dynamic(..) | ty::Param(..) + | ty::Erased(..) | ty::Alias( ty::IsRigid::Yes, ty::AliasTy { @@ -141,6 +142,7 @@ where | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never + | ty::Erased(..) | ty::Error(_) => Ok(ty::Binder::dummy(vec![])), // impl {Meta,}Sized for str, [T], dyn Trait @@ -226,6 +228,7 @@ where | ty::Adt(_, _) | ty::Alias(ty::IsRigid::Yes, _) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(..) => Err(NoSolution), // impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone @@ -401,6 +404,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable Err(NoSolution), @@ -577,6 +581,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable Err(NoSolution), @@ -747,6 +752,7 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable( | ty::Pat(_, _) | ty::Alias(ty::IsRigid::Yes, _) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(..) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Error(_) @@ -835,9 +841,12 @@ pub(in crate::solve) fn const_conditions_for_destruct( // if their inner type implements it. ty::UnsafeBinder(_) => Err(NoSolution), - ty::Dynamic(..) | ty::Param(_) | ty::Alias(..) | ty::Placeholder(_) | ty::Foreign(_) => { - Err(NoSolution) - } + ty::Dynamic(..) + | ty::Param(_) + | ty::Erased(..) + | ty::Alias(..) + | ty::Placeholder(_) + | ty::Foreign(_) => Err(NoSolution), ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { 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 044dc89978124..50d440188931e 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 @@ -696,6 +696,7 @@ where | ty::Tuple(..) | ty::UnsafeBinder(_) | ty::Param(..) + | ty::Erased(..) | ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs index 4203ae8c509cc..03b514454e368 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs @@ -750,7 +750,10 @@ where .skip_norm_wip() } - ty::Alias(ty::IsRigid::Yes, _) | ty::Param(_) | ty::Placeholder(..) => { + ty::Alias(ty::IsRigid::Yes, _) + | ty::Param(_) + | ty::Erased(..) + | ty::Placeholder(..) => { // This is the "fallback impl" for type parameters, unnormalizable projections // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`. // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't @@ -1015,7 +1018,10 @@ where // Given an alias, parameter, or placeholder we add an impl candidate normalizing to a rigid // alias. In case there's a where-bound further constraining this alias it is preferred over // this impl candidate anyways. It's still a bit scuffed. - ty::Alias(ty::IsRigid::Yes, _) | ty::Param(_) | ty::Placeholder(..) => { + ty::Alias(ty::IsRigid::Yes, _) + | ty::Param(_) + | ty::Erased(..) + | ty::Placeholder(..) => { return ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { ecx.instantiate_normalizes_to_as_rigid(goal)?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) 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 32eecd4e44b38..85595bc6fdefe 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -755,6 +755,7 @@ where | ty::Adt(..) | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(..) | ty::Closure(..) | ty::CoroutineClosure(..) @@ -1397,6 +1398,7 @@ where // types, and therefore have no built-in auto impl. ty::Dynamic(..) | ty::Param(..) + | ty::Erased(..) | ty::Foreign(..) | ty::Alias( ty::IsRigid::Yes, diff --git a/compiler/rustc_passes/src/check_export.rs b/compiler/rustc_passes/src/check_export.rs index dbb6d4b72d432..44472919420de 100644 --- a/compiler/rustc_passes/src/check_export.rs +++ b/compiler/rustc_passes/src/check_export.rs @@ -320,7 +320,9 @@ impl<'tcx, 'a> TypeVisitor> for ExportableItemsChecker<'tcx, 'a> { return ControlFlow::Break(ty); } - ty::Alias(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => unreachable!(), + ty::Erased(..) | ty::Alias(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => { + unreachable!() + } } ControlFlow::Continue(()) } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 581f1061bb80c..c38290436951a 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -429,6 +429,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { | ty::UnsafeBinder(_) | ty::Alias(_, _) | ty::Param(_) + | ty::Erased(..) | ty::Error(_) => ConstructorSet::Unlistable, ty::CoroutineWitness(_, _) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => { bug!("Encountered unexpected type in `ConstructorSet::for_ty`: {ty:?}") diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 16a2ee9f22eaf..25c3f9b6bc99c 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -311,7 +311,7 @@ where | ty::Bound(..) | ty::Error(_) | ty::CoroutineWitness(..) => {} - ty::Placeholder(..) | ty::Infer(..) => { + ty::Erased(..) | ty::Placeholder(..) | ty::Infer(..) => { bug!("unexpected type: {:?}", ty) } } diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs index 25eb10230541a..252aa580c35e8 100644 --- a/compiler/rustc_public/src/abi.rs +++ b/compiler/rustc_public/src/abi.rs @@ -281,6 +281,9 @@ impl Layout { /// Describes the number and position of fields within a type's layout. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum FieldsShape { + /// Opaque layout. + Opaque, + /// Scalar primitives and `!`, which never have fields. Primitive, @@ -309,7 +312,7 @@ pub enum FieldsShape { impl FieldsShape { pub fn fields_by_offset_order(&self) -> Vec { match self { - FieldsShape::Primitive => vec![], + FieldsShape::Opaque | FieldsShape::Primitive => vec![], FieldsShape::Union(_) | FieldsShape::Array { .. } => (0..self.count()).collect(), FieldsShape::Arbitrary { offsets, .. } => { let mut indices = (0..offsets.len()).collect::>(); @@ -321,7 +324,7 @@ impl FieldsShape { pub fn count(&self) -> usize { match self { - FieldsShape::Primitive => 0, + FieldsShape::Opaque | FieldsShape::Primitive => 0, FieldsShape::Union(count) => count.get(), FieldsShape::Array { count, .. } => *count as usize, FieldsShape::Arbitrary { offsets, .. } => offsets.len(), @@ -331,6 +334,9 @@ impl FieldsShape { #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum VariantsShape { + /// Opaque layout. + Opaque, + /// A type with no valid variants. Must be uninhabited. Empty, diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index 39cffc194bc30..979ee4c20fa4f 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -284,6 +284,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape { cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { match self { + rustc_abi::FieldsShape::Opaque => FieldsShape::Opaque, rustc_abi::FieldsShape::Primitive => FieldsShape::Primitive, rustc_abi::FieldsShape::Union(count) => FieldsShape::Union(*count), rustc_abi::FieldsShape::Array { stride, count } => { @@ -305,6 +306,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Variants, ) -> Self::T { match self { + rustc_abi::Variants::Opaque => VariantsShape::Opaque, rustc_abi::Variants::Single { index } => { VariantsShape::Single { index: index.stable(tables, cx) } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index c3eebccb6b762..cd47ea932eb1e 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -495,6 +495,8 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { TyKind::Alias(alias_ty.kind.stable(tables, cx), alias_ty.stable(tables, cx)) } ty::Param(param_ty) => TyKind::Param(param_ty.stable(tables, cx)), + // TODO: should add new rustc_public::TyKind variant probably + ty::Erased(..) => todo!(), ty::Bound(ty::BoundVarIndexKind::Canonical, _) => { unreachable!() } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index ec21973d21e93..15f9be738d93c 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -257,6 +257,7 @@ fn encode_const_value<'tcx>( | ty::Dynamic(..) | ty::UnsafeBinder(..) | ty::Param(..) + | ty::Erased(..) | ty::Alias(..) | ty::Bound(..) | ty::Error(..) @@ -735,6 +736,9 @@ pub(crate) fn encode_ty<'tcx>( typeid.push_str(&s); } + // TODO + ty::Erased(..) => todo!(), + // Unexpected types ty::Alias(..) | ty::Bound(..) diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index e5b4628374ce5..29a794c4f9334 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -221,7 +221,12 @@ impl<'tcx> TypeFolder> for TransformTy<'tcx> { Unnormalized::new_wip(t), )), - ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => { + ty::Bound(..) + | ty::Error(..) + | ty::Infer(..) + | ty::Param(..) + | ty::Erased(..) + | ty::Placeholder(..) => { bug!("fold_ty: unexpected `{:?}`", t.kind()); } } diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index 32a301a28ae8e..af6f8b247e3b0 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -7,6 +7,7 @@ use std::hash::{BuildHasher, Hash}; use std::marker::{PhantomData, PointeeSized}; use std::num::{NonZero, ZeroablePrimitive}; use std::path; +use std::range::RangeInclusive; use std::rc::Rc; use std::sync::Arc; @@ -253,6 +254,21 @@ impl, D: Decoder> Decodable for NonZero> Encodable for RangeInclusive { + fn encode(&self, s: &mut S) { + self.start.encode(s); + self.last.encode(s); + } +} + +impl> Decodable for RangeInclusive { + fn decode(d: &mut D) -> Self { + let start = I::decode(d); + let last = I::decode(d); + Self { start, last } + } +} + impl Encodable for str { fn encode(&self, s: &mut S) { s.emit_str(self); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a29309c71e879..48962cd84210d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2781,6 +2781,9 @@ options! { Example: `-Zpointer-authentication=+calls,-init-fini`."), polonius: Polonius = (Polonius::default(), parse_polonius, [TRACKED], POLONIUS_HELP), + polymorphize: bool = (false, parse_bool, [TRACKED], + "whether to avoid monomorphization and generate polymorphic code where possible \ + (default: no)"), pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED], "a single extra argument to prepend the linker invocation (can be used several times)"), pre_link_args: Vec = (Vec::new(), parse_list, [UNTRACKED], diff --git a/compiler/rustc_symbol_mangling/src/export.rs b/compiler/rustc_symbol_mangling/src/export.rs index 9f9c30abe2c1b..a6ec0c8b4bda4 100644 --- a/compiler/rustc_symbol_mangling/src/export.rs +++ b/compiler/rustc_symbol_mangling/src/export.rs @@ -120,6 +120,7 @@ impl<'tcx> AbiStableHash<'tcx> for Ty<'tcx> { | ty::Tuple(_) | ty::Alias(_, _) | ty::Param(_) + | ty::Erased(..) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 93db093f630bd..82adc619aa706 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -144,6 +144,8 @@ pub fn mangle_offload_export<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) // instance from the local crate. In particular, it will also look up the // correct symbol name of instances from upstream crates. fn symbol_name_provider<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::SymbolName<'tcx> { + // TODO: not the right place for this probably + let instance = instance.polymorphize(tcx); let symbol_name = compute_symbol_name(tcx, instance, || { // This closure determines the instantiating crate for instances that // need an instantiating-crate-suffix for their symbol name, in order @@ -362,10 +364,11 @@ fn compute_symbol_name<'tcx>( } }; - debug_assert!( - rustc_demangle::try_demangle(&symbol).is_ok(), - "compute_symbol_name: `{symbol}` cannot be demangled" - ); + // TODO: handle erased params in demangling somehow + // debug_assert!( + // rustc_demangle::try_demangle(&symbol).is_ok(), + // "compute_symbol_name: `{symbol}` cannot be demangled" + // ); symbol } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index fb9f242f60085..004d9798e0bcc 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -8,7 +8,7 @@ use rustc_data_structures::base_n::ToBaseN; use rustc_data_structures::either::Either; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; -use rustc_data_structures::stable_hash::StableHasher; +use rustc_data_structures::stable_hash::{StableHash, StableHasher}; use rustc_hashes::Hash64; use rustc_hir as hir; use rustc_hir::def::CtorKind; @@ -324,6 +324,20 @@ impl<'tcx> V0SymbolMangler<'tcx> { } }) } + + fn print_param_layout( + &mut self, + param_layout: ty::ParamLayout<'tcx>, + ) -> Result<(), std::fmt::Error> { + // TODO: this hashing is a really hacky temporary approach + let hash: Hash64 = self.tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + param_layout.stable_hash(&mut hcx, &mut hasher); + hasher.finish() + }); + self.push_integer_62(hash.as_u64()); + Ok(()) + } } impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { @@ -534,6 +548,11 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { } ty::Tuple(_) if ty.is_unit() => unreachable!(), ty::Param(_) => unreachable!(), + // TODO: this needs more thought and design work + ty::Erased(param_layout) => { + self.push("C5EP"); + self.print_param_layout(param_layout)?; + } ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => bug!(), diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 3e9ff2b672a07..c5427c56eb2cc 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -90,6 +90,7 @@ where } BackendRepr::SimdScalableVector { .. } => panic!("scalable vectors are unsupported"), BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => match arg_layout.fields { + FieldsShape::Opaque => return Err(CannotUseFpConv), FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") } @@ -126,6 +127,7 @@ where } FieldsShape::Arbitrary { .. } => { match arg_layout.variants { + Variants::Opaque => return Err(CannotUseFpConv), Variants::Multiple { .. } => return Err(CannotUseFpConv), Variants::Single { .. } | Variants::Empty => (), } diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index e7cecb754a769..bffb06e2843e8 100644 --- a/compiler/rustc_target/src/callconv/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs @@ -180,6 +180,9 @@ where } } else { match arg.layout.fields { + FieldsShape::Opaque => { + arg.make_indirect(); + } FieldsShape::Primitive => unreachable!(), FieldsShape::Array { .. } => { // Arrays are passed indirectly diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index e14e285fc1185..86fea6b54e79b 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -966,19 +966,26 @@ where // Ensure there is no padding. && s1.size(cx) + s2.size(cx) == layout.size } - BackendRepr::Memory { .. } => match layout.fields { - FieldsShape::Primitive | FieldsShape::Union(_) => false, - // Array elements are at stride offsets with no inter-element gaps. - FieldsShape::Array { stride: _, count } => { - count == 0 || layout_is_noundef(layout.field(cx, 0), cx) + BackendRepr::Memory { .. } => { + if Ty::is_erased_ty(layout) { + return false; } - FieldsShape::Arbitrary { .. } => { - // With `Variants::Multiple`, `layout.fields` only covers shared - // bytes (niche/discriminant); per-variant data is absent, so - // full coverage cannot be proven. - matches!(layout.variants, Variants::Single { .. }) && fields_are_noundef(layout, cx) + match layout.fields { + FieldsShape::Opaque => false, + FieldsShape::Primitive | FieldsShape::Union(_) => false, + // Array elements are at stride offsets with no inter-element gaps. + FieldsShape::Array { stride: _, count } => { + count == 0 || layout_is_noundef(layout.field(cx, 0), cx) + } + FieldsShape::Arbitrary { .. } => { + // With `Variants::Multiple`, `layout.fields` only covers shared + // bytes (niche/discriminant); per-variant data is absent, so + // full coverage cannot be proven. + matches!(layout.variants, Variants::Single { .. }) + && fields_are_noundef(layout, cx) + } } - }, + } BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => false, } } diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs index ae56d57ba43aa..f8eaa93519418 100644 --- a/compiler/rustc_target/src/callconv/powerpc64.rs +++ b/compiler/rustc_target/src/callconv/powerpc64.rs @@ -34,6 +34,7 @@ where return false; } match layout.fields { + FieldsShape::Opaque => false, FieldsShape::Primitive => false, // A `repr(transparent)` union is guaranteed to be ABI-compatible with its single // non-1-ZST field, so look through it instead of rejecting it. diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index e79ce0557ce80..5a055befb5845 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -95,6 +95,7 @@ where return Err(CannotUseFpConv); } BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => match arg_layout.fields { + FieldsShape::Opaque => return Err(CannotUseFpConv), FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") } @@ -131,6 +132,7 @@ where } FieldsShape::Arbitrary { .. } => { match arg_layout.variants { + Variants::Opaque => return Err(CannotUseFpConv), Variants::Multiple { .. } => return Err(CannotUseFpConv), Variants::Single { .. } | Variants::Empty => (), } diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index 22b388cf54101..926afb8f2813a 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -70,6 +70,7 @@ fn classify<'a, Ty, C>( BackendRepr::SimdVector { .. } => {} BackendRepr::SimdScalableVector { .. } => {} BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => match arg_layout.fields { + FieldsShape::Opaque => {} FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") } @@ -83,6 +84,7 @@ fn classify<'a, Ty, C>( } FieldsShape::Array { .. } => {} FieldsShape::Arbitrary { .. } => match arg_layout.variants { + Variants::Opaque => {} Variants::Multiple { .. } => {} Variants::Single { .. } | Variants::Empty => { // Match Clang by ignoring whether a struct is packed and just considering diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index 57e997f45d4c5..37fa3fa2e4185 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -68,6 +68,7 @@ where } match &layout.variants { + Variants::Opaque => {} Variants::Single { .. } | Variants::Empty => {} Variants::Multiple { variants, .. } => { // Treat enum variants like union members. 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 3b21c5e5f19ba..7aaa3f0527c59 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 @@ -2027,6 +2027,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::CoroutineClosure(..) => Some(21), ty::Pat(..) => Some(22), ty::UnsafeBinder(..) => Some(23), + ty::Erased(..) => Some(24), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 5892e376126eb..9f65d53927813 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -381,6 +381,7 @@ fn evaluate_host_effect_for_copy_clone_goal<'tcx>( | ty::Adt(_, _) | ty::Alias(_, _) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(..) => Err(EvaluationFailure::NoSolution), ty::Bound(..) @@ -519,7 +520,12 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( // if their inner type implements it. ty::UnsafeBinder(_) => return Err(EvaluationFailure::NoSolution), - ty::Dynamic(..) | ty::Param(_) | ty::Alias(..) | ty::Placeholder(_) | ty::Foreign(_) => { + ty::Dynamic(..) + | ty::Param(_) + | ty::Erased(..) + | ty::Alias(..) + | ty::Placeholder(_) + | ty::Foreign(_) => { return Err(EvaluationFailure::NoSolution); } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6cea4a9300824..40ea6406f0f39 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1135,6 +1135,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // a known discriminant and may need to be normalized further or rely // on param env for discriminant projections ty::Param(_) + | ty::Erased(..) | ty::Alias(..) | ty::Bound(..) | ty::Placeholder(..) @@ -1195,7 +1196,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // We normalize from `Wrapper::Metadata` to `Tail::Metadata` if able. // Otherwise, type parameters, opaques, and unnormalized projections have // unit metadata if they're known (e.g. by the param_env) to be sized. - ty::Param(_) | ty::Alias(..) + ty::Param(_) | ty::Erased(..) | ty::Alias(..) if self_ty != tail || selcx.infcx.predicate_must_hold_modulo_regions( &obligation.with( @@ -1218,6 +1219,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // FIXME(compiler-errors): are Bound and Placeholder types ever known sized? ty::Param(_) + | ty::Erased(..) | ty::Alias(..) | ty::Bound(..) | ty::Placeholder(..) diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 31d2e8620af90..1e11e5cf61761 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -84,6 +84,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { ty::Dynamic(..) | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(..) | ty::Infer(_) | ty::Bound(..) @@ -404,7 +405,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( } // Types that can't be resolved. Pass them forward. - ty::Alias(..) | ty::Param(..) => { + ty::Alias(..) | ty::Param(..) | ty::Erased(..) => { constraints.dtorck_types.push(ty); } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 7228c55b404b4..1166e66c07f0d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -687,6 +687,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Alias(_, _) | ty::Infer(_) | ty::Param(..) + | ty::Erased(..) | ty::Bound(_, _) => {} // These can't possibly implement `FnPtr` as they are concrete types @@ -787,6 +788,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } ty::Param(..) + | ty::Erased(..) | ty::Alias( _, ty::AliasTy { @@ -1229,7 +1231,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // Fallback to whatever user-defined impls or param-env clauses exist in this case. - ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {} + ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Erased(..) | ty::Placeholder(..) => {} ty::Infer(ty::TyVar(_)) => { candidates.ambiguous = true; @@ -1268,6 +1270,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never + | ty::Erased(..) | ty::Error(_) => { candidates.vec.push(SizedCandidate); } @@ -1360,6 +1363,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Never | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Bound(_, _) | ty::Error(_) | ty::Infer(_) @@ -1401,6 +1405,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Tuple(..) | ty::Alias(..) | ty::Param(..) + | ty::Erased(..) | ty::Bound(..) | ty::Error(_) | ty::Infer( @@ -1443,6 +1448,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Foreign(..) | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(..) | ty::Closure(..) | ty::CoroutineClosure(..) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 81517955181ee..33845a735c00d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -1284,6 +1284,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Adt(..) | ty::Alias(..) | ty::Param(_) + | ty::Erased(..) | ty::Placeholder(..) | ty::Closure(..) | ty::CoroutineClosure(..) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 05b4ba6a7180c..253ce19bc61c6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2043,6 +2043,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never + // TODO: this is a bit sketchy since we checked sizedness of the layout before creating ty::Erased + // rather than whether the type implements Sized + | ty::Erased(..) | ty::Error(_) => ty::Binder::dummy(vec![]), ty::Str | ty::Slice(_) | ty::Dynamic(..) => match sizedness { @@ -2148,6 +2151,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Adt(..) | ty::Alias(..) | ty::Param(..) + | ty::Erased(..) | ty::Placeholder(..) | ty::Bound(..) | ty::Ref(_, _, ty::Mutability::Mut) @@ -2212,6 +2216,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Placeholder(..) | ty::Dynamic(..) | ty::Param(..) + | ty::Erased(..) | ty::Alias( _, ty::AliasTy { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index ba463184a41f8..dd05ae09c5de5 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -756,6 +756,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { | ty::CoroutineWitness(..) | ty::Never | ty::Param(_) + | ty::Erased(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Foreign(..) => { diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 43e2008c5a441..5e56d65f91418 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -385,7 +385,9 @@ pub(crate) mod rustc { assert_eq!(offsets.len(), members.len()); Self::from_variant(Def::Primitive, None, (ty, layout), layout.size, cx) } - FieldsShape::Array { .. } | FieldsShape::Union(_) => Err(Err::NotYetSupported), + FieldsShape::Opaque | FieldsShape::Array { .. } | FieldsShape::Union(_) => { + Err(Err::NotYetSupported) + } } } @@ -436,6 +438,7 @@ pub(crate) mod rustc { }; match *layout.variants() { + Variants::Opaque => unreachable!(), Variants::Empty => Ok(Self::uninhabited()), Variants::Single { index } => { // `Variants::Single` on enums with variants denotes that @@ -598,6 +601,7 @@ pub(crate) mod rustc { match ty.kind() { ty::Adt(def, args) => { match layout.variants { + Variants::Opaque => unreachable!(), Variants::Single { index } => { let field = &def.variant(index).fields[i]; field.ty(cx.tcx(), args).skip_norm_wip() diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 4ecfcde6cc364..4c100849f7e79 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -529,7 +529,7 @@ fn layout_of_uncached<'tcx>( let element = cx.layout_of(element)?; map_layout(cx.calc.layout_of_array_like(&element, None).map(|mut layout| { // a randomly chosen value to distinguish slices - layout.randomization_seed = Hash64::new(0x2dcba99c39784102); + layout.randomization_seed = Some(Hash64::new(0x2dcba99c39784102)); layout }))? } @@ -537,7 +537,7 @@ fn layout_of_uncached<'tcx>( let element = scalar(Int(I8, false)); map_layout(cx.calc.layout_of_array_like(&element, None).map(|mut layout| { // another random value - layout.randomization_seed = Hash64::new(0xc1325f37d127be22); + layout.randomization_seed = Some(Hash64::new(0xc1325f37d127be22)); layout }))? } @@ -598,7 +598,7 @@ fn layout_of_uncached<'tcx>( ) .map(|mut layout| { // this is similar to how ReprOptions populates its field_shuffle_seed - layout.randomization_seed = tcx.def_path_hash(def_id).0.to_smaller_hash(); + layout.randomization_seed = Some(tcx.def_path_hash(def_id).0.to_smaller_hash()); debug!("coroutine layout ({:?}): {:#?}", ty, layout); layout }); @@ -841,6 +841,8 @@ fn layout_of_uncached<'tcx>( cx.layout_of(ty)?.layout } + ty::Erased(param_layout) => layout_of_param_layout(tcx, param_layout), + // Types with no meaningful known layout. ty::Param(_) | ty::Placeholder(..) => { return Err(error(cx, LayoutError::TooGeneric(ty))); @@ -874,6 +876,25 @@ fn layout_of_uncached<'tcx>( }) } +fn layout_of_param_layout<'tcx>( + tcx: TyCtxt<'tcx>, + param_layout: ty::ParamLayout<'tcx>, +) -> Layout<'tcx> { + let ty::ParamLayoutData { backend_repr, largest_niche, align, size } = *param_layout.0.0; + tcx.mk_layout(LayoutData { + fields: FieldsShape::Opaque, + variants: Variants::Opaque, + backend_repr, + largest_niche, + uninhabited: false, + align: rustc_abi::AbiAlign::new(align), + size, + max_repr_align: None, + unadjusted_abi_align: align, + randomization_seed: None, + }) +} + fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx>, layout: TyAndLayout<'tcx>) { // Ignore layouts that are done with non-empty environments or // non-monomorphic layouts, as the user only wants to see the stuff @@ -959,6 +980,7 @@ fn variant_info_for_adt<'tcx>( }; match layout.variants { + Variants::Opaque => unreachable!(), Variants::Empty => (vec![], None), Variants::Single { index } => { diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 562a3ef387d9a..1c7cbba901822 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -62,8 +62,15 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou }) } - fn skip_newtypes<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) -> TyAndLayout<'tcx> { + fn skip_newtypes<'tcx>( + cx: &LayoutCx<'tcx>, + layout: &TyAndLayout<'tcx>, + ) -> Option> { match *layout.ty.kind() { + // Erased params have already had their layouts sanity-checked at construction. + // The sanity check fails for them because their layouts may have fields + // from the underlying type, but `ty::Erased` has no type info for fields. + ty::Erased(..) => return None, ty::UnsafeBinder(bound_ty) => { let ty = cx.tcx().instantiate_bound_regions_with_erased(bound_ty.into()); return skip_newtypes(cx, &TyAndLayout { ty, ..*layout }); @@ -73,12 +80,12 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou if matches!(layout.layout.variants(), Variants::Multiple { .. }) { // Definitely not a newtype of anything. - return *layout; + return Some(*layout); } let mut fields = non_zst_fields(cx, layout); let Some(first) = fields.next() else { // No fields here, so this could be a primitive or enum -- either way it's not a newtype around a thing - return *layout; + return Some(*layout); }; if fields.next().is_none() { let (offset, first) = first; @@ -90,7 +97,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou } } // No more newtypes here. - *layout + Some(*layout) } fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { @@ -119,7 +126,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou let align = align.unwrap(); let size = size.unwrap(); // Check that this matches the underlying field. - let inner = skip_newtypes(cx, layout); + let Some(inner) = skip_newtypes(cx, layout) else { return }; assert!( matches!(inner.layout.backend_repr(), BackendRepr::Scalar(_)), "`Scalar` type {} is newtype around non-`Scalar` type {}", @@ -171,7 +178,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou } BackendRepr::ScalarPair { a: scalar1, b: scalar2, b_offset } => { // Check that the underlying pair of fields matches. - let inner = skip_newtypes(cx, layout); + let Some(inner) = skip_newtypes(cx, layout) else { return }; assert!( matches!(inner.layout.backend_repr(), BackendRepr::ScalarPair { .. }), "`ScalarPair` type {} is newtype around non-`ScalarPair` type {}", @@ -286,6 +293,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou check_layout_abi(cx, layout); match &layout.variants { + Variants::Opaque => assert!(layout.ty.is_erased()), Variants::Empty => { assert!(layout.is_uninhabited()); } diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 094cf5aec0bd1..c1048fb0588ac 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -309,6 +309,7 @@ where | ty::Tuple(_) | ty::Bound(..) | ty::Never + | ty::Erased(..) | ty::Infer(_) | ty::Error(_) => { bug!("unexpected type returned by `needs_drop_components`: {component}") diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 5e78517661275..05a1290b47a6a 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -47,7 +47,7 @@ fn sizedness_constraint_for_ty<'tcx>( }, // Maybe `Sized` or `MetaSized` - ty::Param(..) | ty::Alias(..) | ty::Error(_) => Some(ty), + ty::Param(..) | ty::Erased(..) | ty::Alias(..) | ty::Error(_) => Some(ty), // We cannot instantiate the binder, so just return the *original* type back, // but only if the inner type has a sized constraint. Thus we skip the binder, @@ -389,6 +389,7 @@ fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId) | ty::Tuple(_) | ty::Alias(_, _) | ty::Param(_) + | ty::Erased(..) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index 398fddcd4a141..359b83a015575 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -131,6 +131,7 @@ pub fn simplify_type( TreatParams::AsRigid => Some(SimplifiedType::Placeholder), TreatParams::InstantiateWithInfer => None, }, + ty::Erased(..) => Some(SimplifiedType::Placeholder), ty::Alias(..) => match treat_params { // When treating `ty::Param` as a placeholder, projections also // don't unify with anything else as long as they are fully normalized. @@ -301,6 +302,7 @@ impl {} }; @@ -367,6 +369,8 @@ impl true, + ty::Erased(..) => true, + ty::Int(_) | ty::Uint(_) | ty::Float(_) diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 4af4f1479ec82..5a29577d4d2b0 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -260,6 +260,7 @@ impl FlagComputation { | ty::Uint(_) | ty::Never | ty::Str + | ty::Erased(..) | ty::Foreign(..) => {} ty::Error(_) => self.add_flags(TypeFlags::HAS_NON_REGION_ERROR), diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index cb68b8032f7e1..89accfbb2b1c9 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -197,6 +197,7 @@ pub trait Ty>: | ty::Tuple(_) | ty::Alias(_, _) | ty::Param(_) + | ty::Erased(..) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index e3bf97dfebd26..a4e4ce858aad9 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -200,6 +200,7 @@ pub trait Interner: + TypeVisitable + SliceLike; type Safety: Safety; + type ParamLayout: Copy + Debug + Hash + Eq; // Kinds of consts type Consts: Copy + Debug + Hash + Eq + SliceLike> + Default; diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs index 15741c926092e..8598188f80351 100644 --- a/compiler/rustc_type_ir/src/outlives.rs +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -140,6 +140,8 @@ impl TypeVisitor for OutlivesCollector<'_, I> { self.out.push(Component::Param(p)); } + ty::Erased(..) => {} + ty::Placeholder(p) => { self.out.push(Component::Placeholder(p)); } diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index e87b584ebcb6b..25d082a6c1db9 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -539,6 +539,9 @@ pub fn structurally_relate_tys>( Ok(Ty::new_unsafe_binder(cx, relation.binders(*a_binder, *b_binder)?)) } + // TOOD: is this right? should we be using relate instead of ==? + (ty::Erased(a_layout), ty::Erased(b_layout)) if a_layout == b_layout => Ok(a), + _ => Err(TypeError::Sorts(ExpectedFound::new(a, b))), } } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 35f8897afd4c4..9dd39558e8684 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -316,6 +316,8 @@ pub enum TyKind { /// A type parameter; for example, `T` in `fn f(x: T) {}`. Param(I::ParamTy), + Erased(I::ParamLayout), + /// Bound type variable, used to represent the `'a` in `for<'a> fn(&'a ())`. /// /// For canonical queries, we replace inference variables with bound variables, @@ -412,6 +414,7 @@ impl TyKind { | ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) + | ty::Erased(..) | ty::Never | ty::Tuple(_) => true, @@ -484,6 +487,7 @@ impl fmt::Debug for TyKind { } Alias(is_rigid, a) => f.debug_tuple("Alias").field(&is_rigid).field(&a).finish(), Param(p) => write!(f, "{p:?}"), + Erased(l) => write!(f, "{l:?}"), Bound(d, b) => crate::debug_bound_var(f, *d, b), Placeholder(p) => write!(f, "{p:?}"), Infer(t) => write!(f, "{:?}", t), diff --git a/compiler/rustc_type_ir/src/walk.rs b/compiler/rustc_type_ir/src/walk.rs index 11c81c47b4cf5..2a339972c20e0 100644 --- a/compiler/rustc_type_ir/src/walk.rs +++ b/compiler/rustc_type_ir/src/walk.rs @@ -82,6 +82,7 @@ fn push_inner(stack: &mut TypeWalkerStack, parent: I::GenericArg | ty::Str | ty::Infer(_) | ty::Param(_) + | ty::Erased(..) | ty::Never | ty::Error(_) | ty::Placeholder(..) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1e03a0b13f79f..d3984903e26e0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2417,6 +2417,7 @@ pub(crate) fn clean_middle_ty<'tcx>( ty::Closure(..) => panic!("Closure"), ty::CoroutineClosure(..) => panic!("CoroutineClosure"), ty::Coroutine(..) => panic!("Coroutine"), + ty::Erased(..) => panic!("Erased"), ty::Placeholder(..) => panic!("Placeholder"), ty::CoroutineWitness(..) => panic!("CoroutineWitness"), ty::Infer(..) => panic!("Infer"), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c34b33d9c92f5..b4820c783217f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1769,6 +1769,7 @@ impl PrimitiveType { | ty::Foreign(..) | ty::Infer(..) | ty::Param(..) + | ty::Erased(..) | ty::Placeholder(..) | ty::UnsafeBinder(..) => None, } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index ea131574b17e3..6b55a91117993 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -554,6 +554,7 @@ fn ty_to_res<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { | ty::Dynamic(..) | ty::UnsafeBinder(_) | ty::Param(_) + | ty::Erased(..) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 8720e09bd85cd..5ad1c2cfe0937 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -257,6 +257,7 @@ impl SelfTyHead { | ty::Coroutine(..) | ty::Placeholder(..) | ty::CoroutineWitness(..) + | ty::Erased(..) | ty::Infer(..) => panic!("unexpected impl self ty {bound_ty}"), ty::Error(_) => FatalError.raise(), diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 6257ec51eb8da..fd63aa51b8009 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -927,6 +927,7 @@ impl TyCoercionStability { continue; }, ty::Param(_) if for_return => Self::Deref, + ty::Erased(..) => unreachable!(), ty::Alias( _, ty::AliasTy { diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 0613d8d7453af..70d2e17305b02 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -591,7 +591,10 @@ fn is_uninit_value_valid_for_layout<'tcx>(cx: &LateContext<'tcx>, layout: TyAndL }, // Here validity is determined by the structural fields instead. BackendRepr::Memory { .. } => match &layout.layout.variants { + // FIXME: is this actually unreachable? + Variants::Opaque => unreachable!("opaque layouts should only appear post-clippy"), Variants::Single { .. } => match &layout.layout.fields { + FieldsShape::Opaque => unreachable!("FieldsShape::Opaque should only be for Variants::Opaque"), FieldsShape::Primitive => { debug_assert!(false, "Both Scalar primitives and ! should be handled above."); false diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index f923d5529c6b9..1459f40ab9a7c 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -589,7 +589,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `UnsafeCell` action. (self.unsafe_cell_action)(v) } - Variants::Single { .. } | Variants::Empty => { + Variants::Single { .. } | Variants::Empty | Variants::Opaque => { // Proceed further, try to find where exactly that `UnsafeCell` // is hiding. self.walk_value(v) From d0095c0a0df80263a736dd1083686db8f3f53337 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 28 Sep 2026 15:25:16 -0400 Subject: [PATCH 2/6] Make randomization_seed required again For now it's fine to just check if conflicting CLI flags are passed. Though it may still be good to ensure correctness by construction for layouts (wrt randomization) in the future. --- compiler/rustc_abi/src/layout.rs | 35 +++++++++---------------- compiler/rustc_abi/src/layout/simple.rs | 12 ++++----- compiler/rustc_abi/src/lib.rs | 3 +-- compiler/rustc_middle/src/ty/mod.rs | 5 ++++ compiler/rustc_ty_utils/src/layout.rs | 8 +++--- 5 files changed, 28 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 6936c526f04c5..226a7e2e9e1be 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -198,9 +198,7 @@ impl LayoutCalculator { size, max_repr_align: None, unadjusted_abi_align: element.align.abi, - randomization_seed: element - .randomization_seed - .map(|s| s.wrapping_add(Hash64::new(count))), + randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)), }) } @@ -506,7 +504,7 @@ impl LayoutCalculator { let combined_seed = only_variant .iter() .map(|v| v.randomization_seed) - .try_fold(repr.field_shuffle_seed, |acc, seed| seed.map(|s| acc.wrapping_add(s))); + .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); Ok(LayoutData { variants: Variants::Single { index: only_variant_idx }, @@ -610,7 +608,7 @@ impl LayoutCalculator { let mut align = dl.aggregate_align; let mut max_repr_align = repr.align; let mut unadjusted_abi_align = align; - let mut combined_seed = Some(repr.field_shuffle_seed); + let mut combined_seed = repr.field_shuffle_seed; let mut variants_info = IndexVec::::with_capacity(variants.len()); let mut variant_layouts = variants @@ -623,9 +621,7 @@ impl LayoutCalculator { align = align.max(st.align.abi); max_repr_align = max_repr_align.max(st.max_repr_align); unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); - combined_seed = combined_seed - .zip(st.randomization_seed) - .map(|(combined, variant)| combined.wrapping_add(variant)); + combined_seed = combined_seed.wrapping_add(st.randomization_seed); Some(VariantLayout::from_layout(st)) }) @@ -794,7 +790,7 @@ impl LayoutCalculator { let mut align = dl.aggregate_align; let mut max_repr_align = repr.align; let mut unadjusted_abi_align = align; - let mut combined_seed = Some(repr.field_shuffle_seed); + let mut combined_seed = repr.field_shuffle_seed; let mut size = Size::ZERO; @@ -838,9 +834,7 @@ impl LayoutCalculator { align = align.max(st.align.abi); max_repr_align = max_repr_align.max(st.max_repr_align); unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align); - combined_seed = combined_seed - .zip(st.randomization_seed) - .map(|(combined, variant)| combined.wrapping_add(variant)); + combined_seed = combined_seed.wrapping_add(st.randomization_seed); Ok(VariantLayout::from_layout(st)) }) .collect::, _>>()?; @@ -1107,9 +1101,9 @@ impl LayoutCalculator { let optimizing = &mut in_memory_order.raw[..end]; let fields_excluding_tail = &fields.raw[..end]; // unsizable tail fields are excluded so that we use the same seed for the sized and unsized layouts. - let field_seed = fields_excluding_tail.iter().fold(Some(Hash64::ZERO), |acc, f| { - acc.zip(f.randomization_seed).map(|(acc, seed)| acc.wrapping_add(seed)) - }); + let field_seed = fields_excluding_tail + .iter() + .fold(Hash64::ZERO, |acc, f| acc.wrapping_add(f.randomization_seed)); if optimize_field_order && fields.len() > 1 { // If `-Z randomize-layout` was enabled for the type definition we can shuffle @@ -1127,10 +1121,7 @@ impl LayoutCalculator { use rand::seq::SliceRandom; // `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field // ordering. - let rng_seed = field_seed - .expect("-Zrandomize-layout is incompatible with -Zpolymorphize") - .wrapping_add(repr.field_shuffle_seed) - .as_u64(); + let rng_seed = field_seed.wrapping_add(repr.field_shuffle_seed).as_u64(); let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64(rng_seed); // Shuffle the ordering of the fields. @@ -1418,7 +1409,7 @@ impl LayoutCalculator { unadjusted_abi_align }; - let seed = field_seed.map(|field| field.wrapping_add(repr.field_shuffle_seed)); + let seed = field_seed.wrapping_add(repr.field_shuffle_seed); Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, @@ -1528,8 +1519,6 @@ where align: AbiAlign::new(align), max_repr_align: None, unadjusted_abi_align: elt.align.abi, - randomization_seed: elt - .randomization_seed - .map(|s| s.wrapping_add(Hash64::new(count.as_u64()))), + randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count.as_u64())), }) } diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs index a3d08566307bb..1fffb84ec21cb 100644 --- a/compiler/rustc_abi/src/layout/simple.rs +++ b/compiler/rustc_abi/src/layout/simple.rs @@ -25,7 +25,7 @@ impl LayoutData { size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: dl.i8_align, - randomization_seed: Some(Hash64::new(0)), + randomization_seed: Hash64::new(0), } } @@ -42,7 +42,7 @@ impl LayoutData { size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: dl.i8_align, - randomization_seed: Some(Hash64::ZERO), + randomization_seed: Hash64::ZERO, } } @@ -84,7 +84,7 @@ impl LayoutData { align, max_repr_align: None, unadjusted_abi_align: align.abi, - randomization_seed: Some(Hash64::new(randomization_seed)), + randomization_seed: Hash64::new(randomization_seed), } } @@ -117,7 +117,7 @@ impl LayoutData { size, max_repr_align: None, unadjusted_abi_align: align, - randomization_seed: Some(Hash64::new(combined_seed)), + randomization_seed: Hash64::new(combined_seed), } } @@ -145,7 +145,7 @@ impl LayoutData { unadjusted_abi_align: dl.i8_align, // Variant layouts never flow back into actual layout computations, // so dummy values are fine here. - randomization_seed: Some(Hash64::ZERO), + randomization_seed: Hash64::ZERO, } } @@ -171,7 +171,7 @@ impl LayoutData { unadjusted_abi_align: parent.unadjusted_abi_align, // Variant layouts never flow back into actual layout computations, // so dummy values are fine here. - randomization_seed: Some(Hash64::ZERO), + randomization_seed: Hash64::ZERO, } } } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index d389f45693c65..1989dd384120f 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -2310,8 +2310,7 @@ pub struct LayoutData { /// transmuted to `Foo` we aim to create probalistically distinct seeds so that Foo can choose /// to reorder its fields based on that information. The current implementation is a conservative /// approximation of this goal. - // TODO: making randomization_seed an Option is maybe hacky? - pub randomization_seed: Option, + pub randomization_seed: Hash64, } impl LayoutData { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e42b35916e3f5..b950125f201cf 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1658,6 +1658,11 @@ impl<'tcx> TyCtxt<'tcx> { // If `-Z randomize-layout` was enabled for the type definition then we can // consider performing layout randomization if self.sess.opts.unstable_opts.randomize_layout { + // FIXME: figure out if these features are incompatible in cross-crate contexts too + assert!( + !self.sess.opts.unstable_opts.polymorphize, + "-Zpolymorphize is incompatible with -Zrandomize-layout" + ); flags.insert(ReprFlags::RANDOMIZE_LAYOUT); } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 4c100849f7e79..4c6905139bdd7 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -529,7 +529,7 @@ fn layout_of_uncached<'tcx>( let element = cx.layout_of(element)?; map_layout(cx.calc.layout_of_array_like(&element, None).map(|mut layout| { // a randomly chosen value to distinguish slices - layout.randomization_seed = Some(Hash64::new(0x2dcba99c39784102)); + layout.randomization_seed = Hash64::new(0x2dcba99c39784102); layout }))? } @@ -537,7 +537,7 @@ fn layout_of_uncached<'tcx>( let element = scalar(Int(I8, false)); map_layout(cx.calc.layout_of_array_like(&element, None).map(|mut layout| { // another random value - layout.randomization_seed = Some(Hash64::new(0xc1325f37d127be22)); + layout.randomization_seed = Hash64::new(0xc1325f37d127be22); layout }))? } @@ -598,7 +598,7 @@ fn layout_of_uncached<'tcx>( ) .map(|mut layout| { // this is similar to how ReprOptions populates its field_shuffle_seed - layout.randomization_seed = Some(tcx.def_path_hash(def_id).0.to_smaller_hash()); + layout.randomization_seed = tcx.def_path_hash(def_id).0.to_smaller_hash(); debug!("coroutine layout ({:?}): {:#?}", ty, layout); layout }); @@ -891,7 +891,7 @@ fn layout_of_param_layout<'tcx>( size, max_repr_align: None, unadjusted_abi_align: align, - randomization_seed: None, + randomization_seed: Hash64::ZERO, }) } From ecf78bfe914f8738e288de5f6965e5a006b1d9ac Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 8 Oct 2026 17:19:03 -0400 Subject: [PATCH 3/6] Add FIXME --- compiler/rustc_middle/src/ty/instance.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index cc3aafa882147..88ef1c212b08f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -1018,6 +1018,7 @@ impl<'tcx> Instance<'tcx> { if tcx.opt_item_name(def_id).map_or(false, |n| n.as_str().contains("atomic_")) { return *self; } + // FIXME: exclude all functions with non-Rust reprs anywhere in signature (including theirs) let generics = tcx.generics_of(def_id); let clauses: Vec<_> = tcx From d175313e6fa0fa5778acf92b314b854ba2e7caf3 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 10 Oct 2026 16:48:32 -0400 Subject: [PATCH 4/6] Keep params in erased types, but prevent them from escaping --- .../src/debuginfo/type_names.rs | 4 +-- compiler/rustc_middle/src/ty/instance.rs | 28 ++++++++++++++++++- compiler/rustc_middle/src/ty/print/pretty.rs | 8 +++++- compiler/rustc_middle/src/ty/sty.rs | 21 ++++++++++++++ compiler/rustc_monomorphize/src/collector.rs | 5 ++-- compiler/rustc_public/src/mir/mono.rs | 6 +++- compiler/rustc_symbol_mangling/src/v0.rs | 2 +- compiler/rustc_ty_utils/src/layout.rs | 2 +- compiler/rustc_type_ir/src/inherent.rs | 2 ++ compiler/rustc_type_ir/src/relate.rs | 6 +++- compiler/rustc_type_ir/src/ty_kind.rs | 10 +++++-- 11 files changed, 82 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 053659db3ad0a..dbe78ef7d2fb4 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -447,9 +447,9 @@ fn push_debuginfo_type_name<'tcx>( push_close_angle_bracket(cpp_like_debuginfo, output); } } - ty::Erased(_) => { + ty::Erased(..) => { output.push_str("{erased}") - // TODO: should we include the layout as well? + // TODO: should we include the param/layout as well? } ty::Param(_) | ty::Error(_) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 88ef1c212b08f..bd8a5674331fc 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -11,6 +11,7 @@ use rustc_hir::def_id::{CrateNum, DefId}; use rustc_macros::{Lift, StableHash, TyDecodable, TyEncodable}; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{DUMMY_SP, Span, bug, span_bug}; +use rustc_type_ir::{TypeFolder, TypeSuperFoldable}; use tracing::{debug, instrument}; use crate::diagnostics; @@ -994,6 +995,30 @@ impl<'tcx> Instance<'tcx> { } } + // TODO: this and polymorphize should probably be queries, + // used less ad hoc, and located somewhere else + #[instrument(level = "debug", skip(tcx), ret)] + pub fn erase_escaping(&self, tcx: TyCtxt<'tcx>) -> Self { + struct EraseEscapingFolder<'tcx> { + tcx: TyCtxt<'tcx>, + } + + impl<'tcx> TypeFolder> for EraseEscapingFolder<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match *t.kind() { + ty::Erased(_, layout) => Ty::new_erased(self.tcx, None, layout), + _ => t.super_fold_with(self), + } + } + } + + self.fold_with(&mut EraseEscapingFolder { tcx }) + } + // TODO: this and/or is_ty_param_polymorphizable should probably be queries, // used less ad hoc, and located somewhere else #[instrument(level = "debug", skip(tcx), ret)] @@ -1046,7 +1071,8 @@ impl<'tcx> Instance<'tcx> { && !layout.uninhabited { let param_layout = make_param_layout(tcx, layout); - let erased_ty = tcx.mk_ty_from_kind(ty::Erased(param_layout)); + let erased_ty = + tcx.mk_ty_from_kind(ty::Erased(Some(param_ty), param_layout)); erased_ty.into() } else { arg diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index c81b0f43627b5..e9c3317656fea 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -825,7 +825,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } ty::Error(_) => write!(self, "{{type error}}")?, ty::Param(ref param_ty) => param_ty.print(self)?, - ty::Erased(layout) => { + ty::Erased(param_ty, layout) => { + if let Some(param_ty) = param_ty { + param_ty.print(self)?; + } else { + write!(self, "None")?; + } + write!(self, "@")?; layout.print(self)?; } ty::Bound(debruijn, bound_ty) => match bound_ty.kind { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 4a193e3ba5d6e..c33073abac378 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -447,6 +447,15 @@ impl<'tcx> Ty<'tcx> { Ty::new(tcx, Param(ParamTy { index, name })) } + #[inline] + pub fn new_erased( + tcx: TyCtxt<'tcx>, + param: Option, + layout: ParamLayout<'tcx>, + ) -> Ty<'tcx> { + Ty::new(tcx, Erased(param, layout)) + } + #[inline] pub fn new_bound( tcx: TyCtxt<'tcx>, @@ -965,6 +974,14 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { Ty::new_param(tcx, param.index, param.name) } + fn new_erased( + tcx: TyCtxt<'tcx>, + param: Option, + layout: ty::ParamLayout<'tcx>, + ) -> Self { + Ty::new_erased(tcx, param, layout) + } + fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderType<'tcx>) -> Self { Ty::new_placeholder(tcx, placeholder) } @@ -1360,6 +1377,10 @@ impl<'tcx> Ty<'tcx> { ) } + pub fn erase_escaping(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + if let Erased(_, layout) = *self.kind() { Ty::new_erased(tcx, None, layout) } else { self } + } + #[inline] pub fn is_mutable_ptr(self) -> bool { matches!(self.kind(), RawPtr(_, hir::Mutability::Mut) | Ref(_, _, hir::Mutability::Mut)) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 4e7f7465265a5..caab4d5111afd 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1099,7 +1099,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> // TODO: polymorphize should not be ad hoc like this if tcx.is_reachable_non_generic(def_id) - || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some() + || instance.erase_escaping(tcx).polymorphize(tcx).upstream_monomorphization(tcx).is_some() { // We can link to the item in question, no instance needed in this crate. return false; @@ -1233,7 +1233,8 @@ fn create_fn_mono_item<'tcx>( crate::util::dump_closure_profile(tcx, instance); } - respan(source, MonoItem::Fn(instance.polymorphize(tcx))) + let instance = instance.erase_escaping(tcx).polymorphize(tcx); + respan(source, MonoItem::Fn(instance)) } /// Creates a `MonoItem` for each method that is referenced by the vtable for diff --git a/compiler/rustc_public/src/mir/mono.rs b/compiler/rustc_public/src/mir/mono.rs index b72e6ab3fa0d0..f51a97c763b26 100644 --- a/compiler/rustc_public/src/mir/mono.rs +++ b/compiler/rustc_public/src/mir/mono.rs @@ -30,13 +30,16 @@ pub struct Instance { pub enum InstanceKind { /// A user defined item. Item, + PolyItem, /// A compiler intrinsic function. Intrinsic, /// An LLVM intrinsic function. LlvmIntrinsic, /// A virtual function definition stored in a VTable. /// The `idx` field indicates the position in the VTable for this instance. - Virtual { idx: usize }, + Virtual { + idx: usize, + }, /// A compiler generated shim. Shim, } @@ -117,6 +120,7 @@ impl Instance { } InstanceKind::LlvmIntrinsic | InstanceKind::Item + | InstanceKind::PolyItem | InstanceKind::Virtual { .. } | InstanceKind::Shim => None, } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 004d9798e0bcc..2764f4e8cabf7 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -549,7 +549,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { ty::Tuple(_) if ty.is_unit() => unreachable!(), ty::Param(_) => unreachable!(), // TODO: this needs more thought and design work - ty::Erased(param_layout) => { + ty::Erased(_, param_layout) => { self.push("C5EP"); self.print_param_layout(param_layout)?; } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 4c6905139bdd7..614237dad0dd0 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -841,7 +841,7 @@ fn layout_of_uncached<'tcx>( cx.layout_of(ty)?.layout } - ty::Erased(param_layout) => layout_of_param_layout(tcx, param_layout), + ty::Erased(_, param_layout) => layout_of_param_layout(tcx, param_layout), // Types with no meaningful known layout. ty::Param(_) | ty::Placeholder(..) => { diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 89accfbb2b1c9..564232bb52dbc 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -46,6 +46,8 @@ pub trait Ty>: fn new_param(interner: I, param: I::ParamTy) -> Self; + fn new_erased(interner: I, param: Option, layout: I::ParamLayout) -> Self; + fn new_placeholder(interner: I, param: ty::PlaceholderType) -> Self; fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundTy) -> Self; diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 25d082a6c1db9..0c4a8cb444c0e 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -540,7 +540,11 @@ pub fn structurally_relate_tys>( } // TOOD: is this right? should we be using relate instead of ==? - (ty::Erased(a_layout), ty::Erased(b_layout)) if a_layout == b_layout => Ok(a), + (ty::Erased(a_param, a_layout), ty::Erased(b_param, b_layout)) + if a_param == b_param && a_layout == b_layout => + { + Ok(a) + } _ => Err(TypeError::Sorts(ExpectedFound::new(a, b))), } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 9dd39558e8684..296cdae07323e 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -316,7 +316,13 @@ pub enum TyKind { /// A type parameter; for example, `T` in `fn f(x: T) {}`. Param(I::ParamTy), - Erased(I::ParamLayout), + /// An erased type parameter. + /// + /// This represents all possible instantiations of the parameter for a given layout. + /// The [`I::ParamTy`] is present within its defining context (e.g., function or impl) so + /// that information related to trait methods can be looked up. It is `None` otherwise, + /// to avoid leaking parameters outside their scope. + Erased(Option, I::ParamLayout), /// Bound type variable, used to represent the `'a` in `for<'a> fn(&'a ())`. /// @@ -487,7 +493,7 @@ impl fmt::Debug for TyKind { } Alias(is_rigid, a) => f.debug_tuple("Alias").field(&is_rigid).field(&a).finish(), Param(p) => write!(f, "{p:?}"), - Erased(l) => write!(f, "{l:?}"), + Erased(p, l) => write!(f, "{p:?}@{l:?}"), Bound(d, b) => crate::debug_bound_var(f, *d, b), Placeholder(p) => write!(f, "{p:?}"), Infer(t) => write!(f, "{:?}", t), From b9a92cb10360cf42a501b1431793a069e44edb77 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 12 Oct 2026 22:21:52 -0400 Subject: [PATCH 5/6] Remove outdated hacky check It seems to be unneeded for now, but probably a principled solution to the underlying problem will need to be added later once we erase params with bounds. --- compiler/rustc_middle/src/ty/instance.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index bd8a5674331fc..6e96bfe13bbc3 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -1035,14 +1035,6 @@ impl<'tcx> Instance<'tcx> { // TODO: is there any way this is visible from generic user code that doesn't use intrinsics? return *self; } - // A lot of private/perma-unstable code for atomics completely breaks parametricity - // by ICEing if generic params are not instantiated with specific types. - // Don't polymorphize those. - // TODO: this is horrifically hacky, need better solution. probably lang items, - // or maybe marker traits that bound the generics (and the traits are lang items) - if tcx.opt_item_name(def_id).map_or(false, |n| n.as_str().contains("atomic_")) { - return *self; - } // FIXME: exclude all functions with non-Rust reprs anywhere in signature (including theirs) let generics = tcx.generics_of(def_id); From a816f9bc010e948c6d3d7c952a737a4c19bae606 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 12 Oct 2026 23:00:23 -0400 Subject: [PATCH 6/6] Make polymorphization a query --- compiler/rustc_middle/src/queries.rs | 4 + compiler/rustc_middle/src/query/erase.rs | 1 + compiler/rustc_middle/src/ty/instance.rs | 144 +----------------- compiler/rustc_monomorphize/src/collector.rs | 7 +- compiler/rustc_symbol_mangling/src/lib.rs | 4 +- compiler/rustc_ty_utils/src/lib.rs | 8 +- compiler/rustc_ty_utils/src/polymorphize.rs | 151 +++++++++++++++++++ 7 files changed, 170 insertions(+), 149 deletions(-) create mode 100644 compiler/rustc_ty_utils/src/polymorphize.rs diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index d0429df43d1dd..c683087500f2d 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -2851,6 +2851,10 @@ rustc_queries! { desc { "calculating all fake doc items" } } + query polymorphize_instance(instance: ty::Instance<'tcx>) -> ty::Instance<'tcx> { + desc { "polymorphizing an instance by erasing its concrete generic arguments" } + } + //----------------------------------------------------------------------------- // "Non-queries" are special dep kinds that are not queries. //----------------------------------------------------------------------------- diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index b0281a70eeb73..16baa8af5bb13 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -252,6 +252,7 @@ impl_erasable_for_types_with_no_type_params! { rustc_middle::ty::ConstConditions<'_>, rustc_middle::ty::GenericClauses<'_>, rustc_middle::ty::ImplTraitHeader<'_>, + rustc_middle::ty::Instance<'_>, rustc_middle::ty::ParamEnv<'_>, rustc_middle::ty::SymbolName<'_>, rustc_middle::ty::TypingEnv<'_>, diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 6e96bfe13bbc3..c450584dfb948 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -1,7 +1,5 @@ -use std::ops::ControlFlow; use std::{assert_matches, fmt}; -use rustc_abi::{Layout, LayoutData}; use rustc_attr_ir::lang_items::LangItem; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; @@ -19,8 +17,8 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::print::{FmtPrinter, Print}; use crate::ty::{ - self, AssocContainer, EarlyBinder, GenericArgs, GenericArgsRef, ParamTy, Ty, TyCtxt, - TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + self, AssocContainer, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; /// An `InstanceKind` along with the args that are needed to substitute the instance. @@ -1018,144 +1016,6 @@ impl<'tcx> Instance<'tcx> { self.fold_with(&mut EraseEscapingFolder { tcx }) } - - // TODO: this and/or is_ty_param_polymorphizable should probably be queries, - // used less ad hoc, and located somewhere else - #[instrument(level = "debug", skip(tcx), ret)] - pub fn polymorphize(&self, tcx: TyCtxt<'tcx>) -> Self { - if !tcx.sess.opts.unstable_opts.polymorphize { - return *self; - } - let InstanceKind::Item(def_id) = self.def else { - return *self; - }; - if tcx.intrinsic(def_id).is_some() { - // Intrinsics sometimes do weird stuff with generics, where they are generic - // but rustc will ICE if they are called with unexpected types. - // TODO: is there any way this is visible from generic user code that doesn't use intrinsics? - return *self; - } - // FIXME: exclude all functions with non-Rust reprs anywhere in signature (including theirs) - - let generics = tcx.generics_of(def_id); - let clauses: Vec<_> = tcx - .clauses_of(def_id) - .instantiate_identity(tcx) - .into_iter() - .map(|(c, _)| c.skip_norm_wip()) - .collect(); - let args = - tcx.mk_args_from_iter(self.args.iter().enumerate().map( - |(idx, arg)| match arg.kind() { - ty::GenericArgKind::Type(ty) => { - let param_ty = ParamTy::for_def(generics.param_at(idx, tcx)); - let layout = tcx - .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) - .unwrap() - .layout; - if is_ty_param_polymorphizable(tcx, &clauses, param_ty) - // FIXME: pass drop glue in sidecar to relax this - && !ty.needs_drop(tcx, ty::TypingEnv::fully_monomorphized()) - // FIXME: track metadata layout in ParamLayout to relax this - && layout.is_sized() - // FIXME: figure out how to handle uninhabited types -- should they be erased? - // (causes issues with comparing layout inhabitedness w/ opsem inhabitedness) - && !layout.uninhabited - { - let param_layout = make_param_layout(tcx, layout); - let erased_ty = - tcx.mk_ty_from_kind(ty::Erased(Some(param_ty), param_layout)); - erased_ty.into() - } else { - arg - } - } - ty::GenericArgKind::Lifetime(_) | ty::GenericArgKind::Const(_) => arg, - }, - )); - Self { def: self.def, args } - } -} - -fn make_param_layout<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) -> ty::ParamLayout<'tcx> { - let LayoutData { - fields: _, - variants: _, - backend_repr, - largest_niche, - uninhabited: _, - align: rustc_abi::AbiAlign { abi: align }, - size, - max_repr_align: _, - unadjusted_abi_align: _, - randomization_seed: _, - } = *layout.0.0; - tcx.mk_param_layout(ty::ParamLayoutData { backend_repr, largest_niche, align, size }) -} - -#[instrument(level = "debug", ret, skip(tcx))] -fn is_ty_param_polymorphizable<'tcx>( - tcx: TyCtxt<'tcx>, - clauses: &[ty::Clause<'tcx>], - param_ty: ParamTy, -) -> bool { - for clause in clauses { - // FIXME: is skip_binder appropriate? - match clause.kind().skip_binder() { - ty::ClauseKind::Trait(trait_predicate) => { - let is_for_param = trait_predicate.self_ty().is_param(param_ty.index); - if is_for_param - && tcx.is_lang_item(trait_predicate.def_id(), LangItem::Sized) - { - // FIXME: what about rest of Sized hierarchy? - debug!("found Sized bound -> doesn't matter"); - } else if has_param(param_ty, trait_predicate) { - debug!("polymorphization disqualified by {clause:?}"); - return false; - } - } - ty::ClauseKind::Projection(projection_predicate) => { - if has_param(param_ty, projection_predicate) { - debug!("polymorphization disqualified by {clause:?}"); - return false; - } - } - ty::ClauseKind::ConstArgHasType(_, ty) => { - if has_param(param_ty, ty) { - debug!("polymorphization disqualified by {clause:?}"); - return false; - } - } - ty::ClauseKind::RegionOutlives(..) - // TODO: maybe disqualify T: 'static since that's needed for TypeId on stable? - // might allow ignoring TypeId for now without breaking stuff. - | ty::ClauseKind::TypeOutlives(..) - | ty::ClauseKind::WellFormed(..) - | ty::ClauseKind::HostEffect(..) - | ty::ClauseKind::ConstEvaluatable(..) - | ty::ClauseKind::UnstableFeature(..) => {} - } - } - true -} - -fn has_param<'tcx, T: TypeVisitable>>(param_ty: ParamTy, t: T) -> bool { - t.visit_with(&mut HasParamVisitor { param_ty }).is_break() -} - -struct HasParamVisitor { - param_ty: ParamTy, -} - -impl<'tcx> TypeVisitor> for HasParamVisitor { - type Result = ControlFlow<()>; - - fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { - if t.is_param(self.param_ty.index) { - return ControlFlow::Break(()); - } - t.super_visit_with(self) - } } fn needs_fn_once_adapter_shim( diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index caab4d5111afd..3c5875b48f467 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1099,7 +1099,10 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> // TODO: polymorphize should not be ad hoc like this if tcx.is_reachable_non_generic(def_id) - || instance.erase_escaping(tcx).polymorphize(tcx).upstream_monomorphization(tcx).is_some() + || tcx + .polymorphize_instance(instance.erase_escaping(tcx)) + .upstream_monomorphization(tcx) + .is_some() { // We can link to the item in question, no instance needed in this crate. return false; @@ -1233,7 +1236,7 @@ fn create_fn_mono_item<'tcx>( crate::util::dump_closure_profile(tcx, instance); } - let instance = instance.erase_escaping(tcx).polymorphize(tcx); + let instance = tcx.polymorphize_instance(instance.erase_escaping(tcx)); respan(source, MonoItem::Fn(instance)) } diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 82adc619aa706..23e72b457171d 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -144,8 +144,8 @@ pub fn mangle_offload_export<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) // instance from the local crate. In particular, it will also look up the // correct symbol name of instances from upstream crates. fn symbol_name_provider<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::SymbolName<'tcx> { - // TODO: not the right place for this probably - let instance = instance.polymorphize(tcx); + // TODO: this is wrong, it should be handled correctly in the callers instead + let instance = tcx.polymorphize_instance(instance); let symbol_name = compute_symbol_name(tcx, instance, || { // This closure determines the instantiating crate for instances that // need an instantiating-crate-suffix for their symbol name, in order diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 2b4c17c5fb94c..ab34e26e6a571 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -23,6 +23,7 @@ mod layout; mod needs_drop; mod nested_bodies; mod opaque_types; +mod polymorphize; mod representability; mod structural_match; mod ty; @@ -33,12 +34,13 @@ pub fn provide(providers: &mut Providers) { common_traits::provide(providers); consts::provide(providers); implied_bounds::provide(providers); + instance::provide(providers); layout::provide(providers); needs_drop::provide(providers); + nested_bodies::provide(providers); opaque_types::provide(providers); + polymorphize::provide(providers); representability::provide(providers); - ty::provide(providers); - instance::provide(providers); structural_match::provide(providers); - nested_bodies::provide(providers); + ty::provide(providers); } diff --git a/compiler/rustc_ty_utils/src/polymorphize.rs b/compiler/rustc_ty_utils/src/polymorphize.rs new file mode 100644 index 0000000000000..cc0032f0a55f0 --- /dev/null +++ b/compiler/rustc_ty_utils/src/polymorphize.rs @@ -0,0 +1,151 @@ +use std::ops::ControlFlow; + +use rustc_abi::{Layout, LayoutData}; +use rustc_attr_ir::lang_items::LangItem; +use rustc_middle::queries::Providers; +use rustc_middle::ty::{ + self, Instance, InstanceKind, ParamTy, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitor, +}; +use tracing::{debug, instrument}; + +// TODO: this should be used less ad hoc +#[instrument(level = "debug", skip(tcx), ret)] +fn polymorphize_instance<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Instance<'tcx> { + if !tcx.sess.opts.unstable_opts.polymorphize { + return instance; + } + let InstanceKind::Item(def_id) = instance.def else { + return instance; + }; + if tcx.intrinsic(def_id).is_some() { + // Intrinsics sometimes do weird stuff with generics, where they are generic + // but rustc will ICE if they are called with unexpected types. + // TODO: is there any way this is visible from generic user code that doesn't use intrinsics? + return instance; + } + // FIXME: exclude all functions with non-Rust reprs anywhere in signature (including theirs) + + let generics = tcx.generics_of(def_id); + let clauses: Vec<_> = tcx + .clauses_of(def_id) + .instantiate_identity(tcx) + .into_iter() + .map(|(c, _)| c.skip_norm_wip()) + .collect(); + let args = + tcx.mk_args_from_iter(instance.args.iter().enumerate().map( + |(idx, arg)| match arg.kind() { + ty::GenericArgKind::Type(ty) => { + let param_ty = ParamTy::for_def(generics.param_at(idx, tcx)); + let layout = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) + .unwrap() + .layout; + if is_ty_param_polymorphizable(tcx, &clauses, param_ty) + // FIXME: pass drop glue in sidecar to relax this + && !ty.needs_drop(tcx, ty::TypingEnv::fully_monomorphized()) + // FIXME: track metadata layout in ParamLayout to relax this + && layout.is_sized() + // FIXME: figure out how to handle uninhabited types -- should they be erased? + // (causes issues with comparing layout inhabitedness w/ opsem inhabitedness) + && !layout.uninhabited + { + let param_layout = make_param_layout(tcx, layout); + let erased_ty = + tcx.mk_ty_from_kind(ty::Erased(Some(param_ty), param_layout)); + erased_ty.into() + } else { + arg + } + } + ty::GenericArgKind::Lifetime(_) | ty::GenericArgKind::Const(_) => arg, + }, + )); + Instance { def: instance.def, args } +} + +fn make_param_layout<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) -> ty::ParamLayout<'tcx> { + let LayoutData { + fields: _, + variants: _, + backend_repr, + largest_niche, + uninhabited: _, + align: rustc_abi::AbiAlign { abi: align }, + size, + max_repr_align: _, + unadjusted_abi_align: _, + randomization_seed: _, + } = *layout.0.0; + tcx.mk_param_layout(ty::ParamLayoutData { backend_repr, largest_niche, align, size }) +} + +#[instrument(level = "debug", ret, skip(tcx))] +fn is_ty_param_polymorphizable<'tcx>( + tcx: TyCtxt<'tcx>, + clauses: &[ty::Clause<'tcx>], + param_ty: ParamTy, +) -> bool { + for clause in clauses { + // FIXME: is skip_binder appropriate? + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(trait_predicate) => { + let is_for_param = trait_predicate.self_ty().is_param(param_ty.index); + if is_for_param + && tcx.is_lang_item(trait_predicate.def_id(), LangItem::Sized) + { + // FIXME: what about rest of Sized hierarchy? + debug!("found Sized bound -> doesn't matter"); + } else if has_param(param_ty, trait_predicate) { + debug!("polymorphization disqualified by {clause:?}"); + return false; + } + } + ty::ClauseKind::Projection(projection_predicate) => { + if has_param(param_ty, projection_predicate) { + debug!("polymorphization disqualified by {clause:?}"); + return false; + } + } + ty::ClauseKind::ConstArgHasType(_, ty) => { + if has_param(param_ty, ty) { + debug!("polymorphization disqualified by {clause:?}"); + return false; + } + } + ty::ClauseKind::RegionOutlives(..) + // TODO: maybe disqualify T: 'static since that's needed for TypeId on stable? + // might allow ignoring TypeId for now without breaking stuff. + | ty::ClauseKind::TypeOutlives(..) + | ty::ClauseKind::WellFormed(..) + | ty::ClauseKind::HostEffect(..) + | ty::ClauseKind::ConstEvaluatable(..) + | ty::ClauseKind::UnstableFeature(..) => {} + } + } + true +} + +fn has_param<'tcx, T: TypeVisitable>>(param_ty: ParamTy, t: T) -> bool { + t.visit_with(&mut HasParamVisitor { param_ty }).is_break() +} + +struct HasParamVisitor { + param_ty: ParamTy, +} + +impl<'tcx> TypeVisitor> for HasParamVisitor { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { + if t.is_param(self.param_ty.index) { + return ControlFlow::Break(()); + } + t.super_visit_with(self) + } +} + +pub(crate) fn provide(providers: &mut Providers) { + providers.polymorphize_instance = polymorphize_instance; +}