diff options
Diffstat (limited to 'compiler/rustc_middle/src/ty/layout.rs')
| -rw-r--r-- | compiler/rustc_middle/src/ty/layout.rs | 81 |
1 files changed, 51 insertions, 30 deletions
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index b87e23af72b..caf33fa5d21 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1,5 +1,6 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir::{GeneratorLayout, GeneratorSavedLocal}; +use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::subst::Subst; use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable}; use rustc_ast as ast; @@ -9,7 +10,7 @@ use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; use rustc_session::{config::OptLevel, DataTypeKind, FieldInfo, SizeKind, VariantInfo}; -use rustc_span::symbol::{Ident, Symbol}; +use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::call::{ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind, @@ -167,7 +168,7 @@ impl PrimitiveExt for Primitive { /// Return an *integer* type matching this primitive. /// Useful in particular when dealing with enum discriminants. #[inline] - fn to_int_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { Int(i, signed) => i.to_ty(tcx, signed), Pointer => tcx.types.usize, @@ -199,6 +200,7 @@ pub const MAX_SIMD_LANES: u64 = 1 << 0xF; pub enum LayoutError<'tcx> { Unknown(Ty<'tcx>), SizeOverflow(Ty<'tcx>), + NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>), } impl<'tcx> fmt::Display for LayoutError<'tcx> { @@ -208,16 +210,24 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { LayoutError::SizeOverflow(ty) => { write!(f, "values of the type `{}` are too big for the current architecture", ty) } + LayoutError::NormalizationFailure(t, e) => write!( + f, + "unable to determine layout for `{}` because `{}` cannot be normalized", + t, + e.get_type_for_failure() + ), } } } +#[instrument(skip(tcx, query), level = "debug")] fn layout_of<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> { ty::tls::with_related_context(tcx, move |icx| { let (param_env, ty) = query.into_parts(); + debug!(?ty); if !tcx.recursion_limit().value_within_limit(icx.layout_depth) { tcx.sess.fatal(&format!("overflow representing the type `{}`", ty)); @@ -229,7 +239,18 @@ fn layout_of<'tcx>( ty::tls::enter_context(&icx, |_| { let param_env = param_env.with_reveal_all_normalized(tcx); let unnormalized_ty = ty; - let ty = tcx.normalize_erasing_regions(param_env, ty); + + // FIXME: We might want to have two different versions of `layout_of`: + // One that can be called after typecheck has completed and can use + // `normalize_erasing_regions` here and another one that can be called + // before typecheck has completed and uses `try_normalize_erasing_regions`. + let ty = match tcx.try_normalize_erasing_regions(param_env, ty) { + Ok(t) => t, + Err(normalization_error) => { + return Err(LayoutError::NormalizationFailure(ty, normalization_error)); + } + }; + if ty != unnormalized_ty { // Ensure this layout is also cached for the normalized type. return tcx.layout_of(param_env.and(ty)); @@ -326,10 +347,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect(); - // `ReprOptions.layout_seed` is a deterministic seed that we can use to - // randomize field ordering with - let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed); - let optimize = !repr.inhibit_struct_field_reordering_opt(); if optimize { let end = @@ -343,6 +360,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // the field ordering to try and catch some code making assumptions about layouts // we don't guarantee if repr.can_randomize_type_layout() { + // `ReprOptions.layout_seed` is a deterministic seed that we can use to + // randomize field ordering with + let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed); + // Shuffle the ordering of the fields optimizing.shuffle(&mut rng); @@ -512,7 +533,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } } - if sized && fields.iter().any(|f| f.abi.is_uninhabited()) { + if fields.iter().any(|f| f.abi.is_uninhabited()) { abi = Abi::Uninhabited; } @@ -1748,9 +1769,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Ignore layouts that are done with non-empty environments or // non-monomorphic layouts, as the user only wants to see the stuff // resulting from the final codegen session. - if layout.ty.definitely_has_param_types_or_consts(self.tcx) - || !self.param_env.caller_bounds().is_empty() - { + if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() { return; } @@ -1789,7 +1808,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let adt_kind = adt_def.adt_kind(); let adt_packed = adt_def.repr.pack.is_some(); - let build_variant_info = |n: Option<Ident>, flds: &[Symbol], layout: TyAndLayout<'tcx>| { + let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| { let mut min_size = Size::ZERO; let field_info: Vec<_> = flds .iter() @@ -1824,15 +1843,15 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { if !adt_def.variants.is_empty() && layout.fields != FieldsShape::Primitive { debug!( "print-type-size `{:#?}` variant {}", - layout, adt_def.variants[index].ident + layout, adt_def.variants[index].name ); let variant_def = &adt_def.variants[index]; - let fields: Vec<_> = variant_def.fields.iter().map(|f| f.ident.name).collect(); + let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect(); record( adt_kind.into(), adt_packed, None, - vec![build_variant_info(Some(variant_def.ident), &fields, layout)], + vec![build_variant_info(Some(variant_def.name), &fields, layout)], ); } else { // (This case arises for *empty* enums; so give it @@ -1851,10 +1870,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { .variants .iter_enumerated() .map(|(i, variant_def)| { - let fields: Vec<_> = - variant_def.fields.iter().map(|f| f.ident.name).collect(); + let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect(); build_variant_info( - Some(variant_def.ident), + Some(variant_def.name), &fields, layout.for_variant(self, i), ) @@ -1916,7 +1934,7 @@ impl<'tcx> SizeSkeleton<'tcx> { let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env); match tail.kind() { ty::Param(_) | ty::Projection(_) => { - debug_assert!(tail.definitely_has_param_types_or_consts(tcx)); + debug_assert!(tail.has_param_types_or_consts()); Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) } _ => bug!( @@ -2174,9 +2192,9 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> { } } -impl<C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {} +impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {} -impl LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> { +impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> { type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>; #[inline] @@ -2185,7 +2203,7 @@ impl LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> { } } -impl LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> { +impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> { type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>; #[inline] @@ -2261,7 +2279,7 @@ where TyAndLayout(TyAndLayout<'tcx>), } - fn field_ty_or_layout( + fn field_ty_or_layout<'tcx>( this: TyAndLayout<'tcx>, cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>), i: usize, @@ -2560,9 +2578,12 @@ impl<'tcx> ty::Instance<'tcx> { // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead), // or should go through `FnAbi` instead, to avoid losing any // adjustments `fn_abi_of_instance` might be performing. - fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { - // FIXME(davidtwco,eddyb): A `ParamEnv` should be passed through to this function. - let ty = self.ty(tcx, ty::ParamEnv::reveal_all()); + fn fn_sig_for_fn_abi( + &self, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> ty::PolyFnSig<'tcx> { + let ty = self.ty(tcx, param_env); match *ty.kind() { ty::FnDef(..) => { // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering @@ -2703,7 +2724,7 @@ impl<'tcx> ty::Instance<'tcx> { /// with `-Cpanic=abort` will look like they can't unwind when in fact they /// might (from a foreign exception or similar). #[inline] -pub fn fn_can_unwind( +pub fn fn_can_unwind<'tcx>( tcx: TyCtxt<'tcx>, codegen_fn_attr_flags: CodegenFnAttrFlags, abi: SpecAbi, @@ -2821,7 +2842,7 @@ pub enum FnAbiError<'tcx> { AdjustForForeignAbi(call::AdjustForForeignAbiError), } -impl From<LayoutError<'tcx>> for FnAbiError<'tcx> { +impl<'tcx> From<LayoutError<'tcx>> for FnAbiError<'tcx> { fn from(err: LayoutError<'tcx>) -> Self { Self::Layout(err) } @@ -2921,7 +2942,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { } } -impl<C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {} +impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {} fn fn_abi_of_fn_ptr<'tcx>( tcx: TyCtxt<'tcx>, @@ -2944,7 +2965,7 @@ fn fn_abi_of_instance<'tcx>( ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { let (param_env, (instance, extra_args)) = query.into_parts(); - let sig = instance.fn_sig_for_fn_abi(tcx); + let sig = instance.fn_sig_for_fn_abi(tcx, param_env); let caller_location = if instance.def.requires_caller_location(tcx) { Some(tcx.caller_location_ty()) |
