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..226a7e2e9e1be 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -1121,9 +1121,8 @@ 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.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 +1372,7 @@ impl LayoutCalculator { offsets } FieldsShape::Primitive + | FieldsShape::Opaque | FieldsShape::Array { .. } | FieldsShape::Union(..) => { panic!("encountered a non-arbitrary layout during enum layout") 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..1989dd384120f 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. @@ -2296,6 +2332,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 +2520,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..dbe78ef7d2fb4 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 param/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/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/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..c450584dfb948 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -9,6 +9,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; @@ -991,6 +992,30 @@ impl<'tcx> Instance<'tcx> { tcx.try_normalize_erasing_regions(typing_env, v.instantiate_identity()) } } + + // 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 }) + } } 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..b950125f201cf 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::{ @@ -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_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..e9c3317656fea 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -825,6 +825,15 @@ 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(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 { ty::BoundTyKind::Anon => { rustc_type_ir::debug_bound_var(self, debruijn, bound_ty.var)? @@ -3398,6 +3407,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..c33073abac378 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. @@ -429,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>, @@ -947,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) } @@ -1245,6 +1280,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(_)) @@ -1337,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)) @@ -1712,7 +1756,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 +1849,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 +2028,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 +2103,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 +2122,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..3c5875b48f467 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1097,7 +1097,13 @@ 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) + || 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; } @@ -1230,6 +1236,7 @@ fn create_fn_mono_item<'tcx>( crate::util::dump_closure_profile(tcx, instance); } + let instance = tcx.polymorphize_instance(instance.erase_escaping(tcx)); respan(source, MonoItem::Fn(instance)) } 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/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_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..23e72b457171d 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: 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 @@ -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..2764f4e8cabf7 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..614237dad0dd0 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -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: Hash64::ZERO, + }) +} + 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/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/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/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; +} 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..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; @@ -197,6 +199,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..0c4a8cb444c0e 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -539,6 +539,13 @@ 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_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 35f8897afd4c4..296cdae07323e 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -316,6 +316,14 @@ pub enum TyKind { /// A type parameter; for example, `T` in `fn f(x: T) {}`. Param(I::ParamTy), + /// 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 ())`. /// /// For canonical queries, we replace inference variables with bound variables, @@ -412,6 +420,7 @@ impl TyKind { | ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(..) + | ty::Erased(..) | ty::Never | ty::Tuple(_) => true, @@ -484,6 +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(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), 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)