diff options
Diffstat (limited to 'compiler/rustc_ty_utils/src/layout.rs')
-rw-r--r-- | compiler/rustc_ty_utils/src/layout.rs | 143 |
1 files changed, 70 insertions, 73 deletions
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index e3132fcc4..63ef1c724 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -1,7 +1,7 @@ use hir::def_id::DefId; use rustc_hir as hir; use rustc_index::bit_set::BitSet; -use rustc_index::vec::{Idx, IndexVec}; +use rustc_index::vec::{IndexSlice, IndexVec}; use rustc_middle::mir::{GeneratorLayout, GeneratorSavedLocal}; use rustc_middle::ty::layout::{ IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES, @@ -17,6 +17,9 @@ use rustc_target::abi::*; use std::fmt::Debug; use std::iter; +use crate::errors::{ + MultipleArrayFieldsSimdType, NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType, +}; use crate::layout_sanity_check::sanity_check_layout; pub fn provide(providers: &mut ty::query::Providers) { @@ -62,23 +65,10 @@ fn layout_of<'tcx>( Ok(layout) } -// Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`. -// This is used to go between `memory_index` (source field order to memory order) -// and `inverse_memory_index` (memory order to source field order). -// See also `FieldsShape::Arbitrary::memory_index` for more details. -// FIXME(eddyb) build a better abstraction for permutations, if possible. -fn invert_mapping(map: &[u32]) -> Vec<u32> { - let mut inverse = vec![0; map.len()]; - for i in 0..map.len() { - inverse[map[i] as usize] = i as u32; - } - inverse -} - fn univariant_uninterned<'tcx>( cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, ty: Ty<'tcx>, - fields: &[Layout<'_>], + fields: &IndexSlice<FieldIdx, Layout<'_>>, repr: &ReprOptions, kind: StructKind, ) -> Result<LayoutS, LayoutError<'tcx>> { @@ -106,7 +96,7 @@ fn layout_of_uncached<'tcx>( }; let scalar = |value: Primitive| tcx.mk_layout(LayoutS::scalar(cx, scalar_unit(value))); - let univariant = |fields: &[Layout<'_>], repr: &ReprOptions, kind| { + let univariant = |fields: &IndexSlice<FieldIdx, Layout<'_>>, repr: &ReprOptions, kind| { Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, repr, kind)?)) }; debug_assert!(!ty.has_non_region_infer()); @@ -156,7 +146,11 @@ fn layout_of_uncached<'tcx>( let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env); - let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() { + let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() + // Projection eagerly bails out when the pointee references errors, + // fall back to structurally deducing metadata. + && !pointee.references_error() + { let metadata_ty = tcx.normalize_erasing_regions( param_env, tcx.mk_projection(metadata_def_id, [pointee]), @@ -223,7 +217,7 @@ fn layout_of_uncached<'tcx>( let largest_niche = if count != 0 { element.largest_niche } else { None }; tcx.mk_layout(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, + variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count }, abi, largest_niche, @@ -234,7 +228,7 @@ fn layout_of_uncached<'tcx>( ty::Slice(element) => { let element = cx.layout_of(element)?; tcx.mk_layout(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, + variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count: 0 }, abi: Abi::Aggregate { sized: false }, largest_niche: None, @@ -243,7 +237,7 @@ fn layout_of_uncached<'tcx>( }) } ty::Str => tcx.mk_layout(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, + variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, abi: Abi::Aggregate { sized: false }, largest_niche: None, @@ -252,12 +246,14 @@ fn layout_of_uncached<'tcx>( }), // Odd unit types. - ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?, + ty::FnDef(..) => { + univariant(IndexSlice::empty(), &ReprOptions::default(), StructKind::AlwaysSized)? + } ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => { let mut unit = univariant_uninterned( cx, ty, - &[], + IndexSlice::empty(), &ReprOptions::default(), StructKind::AlwaysSized, )?; @@ -273,7 +269,7 @@ fn layout_of_uncached<'tcx>( ty::Closure(_, ref substs) => { let tys = substs.as_closure().upvar_tys(); univariant( - &tys.map(|ty| Ok(cx.layout_of(ty)?.layout)).collect::<Result<Vec<_>, _>>()?, + &tys.map(|ty| Ok(cx.layout_of(ty)?.layout)).try_collect::<IndexVec<_, _>>()?, &ReprOptions::default(), StructKind::AlwaysSized, )? @@ -284,7 +280,7 @@ fn layout_of_uncached<'tcx>( if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; univariant( - &tys.iter().map(|k| Ok(cx.layout_of(k)?.layout)).collect::<Result<Vec<_>, _>>()?, + &tys.iter().map(|k| Ok(cx.layout_of(k)?.layout)).try_collect::<IndexVec<_, _>>()?, &ReprOptions::default(), kind, )? @@ -301,6 +297,8 @@ fn layout_of_uncached<'tcx>( return Err(LayoutError::Unknown(ty)); } + let fields = &def.non_enum_variant().fields; + // Supported SIMD vectors are homogeneous ADTs with at least one field: // // * #[repr(simd)] struct S(T, T, T, T); @@ -311,18 +309,22 @@ fn layout_of_uncached<'tcx>( // SIMD vectors with zero fields are not supported. // (should be caught by typeck) - if def.non_enum_variant().fields.is_empty() { - tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty)); + if fields.is_empty() { + tcx.sess.emit_fatal(ZeroLengthSimdType { ty }) } // Type of the first ADT field: - let f0_ty = def.non_enum_variant().fields[0].ty(tcx, substs); + let f0_ty = fields[FieldIdx::from_u32(0)].ty(tcx, substs); // Heterogeneous SIMD vectors are not supported: // (should be caught by typeck) - for fi in &def.non_enum_variant().fields { + for fi in fields { if fi.ty(tcx, substs) != f0_ty { - tcx.sess.fatal(&format!("monomorphising heterogeneous SIMD type `{}`", ty)); + tcx.sess.delay_span_bug( + DUMMY_SP, + "#[repr(simd)] was applied to an ADT with heterogeneous field type", + ); + return Err(LayoutError::Unknown(ty)); } } @@ -337,12 +339,9 @@ fn layout_of_uncached<'tcx>( // First ADT field is an array: // SIMD vectors with multiple array fields are not supported: - // (should be caught by typeck) + // Can't be caught by typeck with a generic simd type. if def.non_enum_variant().fields.len() != 1 { - tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` with more than one array field", - ty - )); + tcx.sess.emit_fatal(MultipleArrayFieldsSimdType { ty }); } // Extract the number of elements from the layout of the array field: @@ -362,12 +361,9 @@ fn layout_of_uncached<'tcx>( // // Can't be caught in typeck if the array length is generic. if e_len == 0 { - tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty)); + tcx.sess.emit_fatal(ZeroLengthSimdType { ty }); } else if e_len > MAX_SIMD_LANES { - tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` of length greater than {}", - ty, MAX_SIMD_LANES, - )); + tcx.sess.emit_fatal(OversizedSimdType { ty, max_lanes: MAX_SIMD_LANES }); } // Compute the ABI of the element type: @@ -375,11 +371,7 @@ fn layout_of_uncached<'tcx>( let Abi::Scalar(e_abi) = e_ly.abi else { // This error isn't caught in typeck, e.g., if // the element type of the vector is generic. - tcx.sess.fatal(&format!( - "monomorphising SIMD type `{}` with a non-primitive-scalar \ - (integer/float/pointer) element type `{}`", - ty, e_ty - )) + tcx.sess.emit_fatal(NonPrimitiveSimdType { ty, e_ty }); }; // Compute the size and alignment of the vector: @@ -389,13 +381,13 @@ fn layout_of_uncached<'tcx>( // Compute the placement of the vector fields: let fields = if is_array { - FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0] } + FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() } } else { FieldsShape::Array { stride: e_ly.size, count: e_len } }; tcx.mk_layout(LayoutS { - variants: Variants::Single { index: VariantIdx::new(0) }, + variants: Variants::Single { index: FIRST_VARIANT }, fields, abi: Abi::Vector { element: e_abi, count: e_len }, largest_niche: e_ly.largest_niche, @@ -414,9 +406,9 @@ fn layout_of_uncached<'tcx>( v.fields .iter() .map(|field| Ok(cx.layout_of(field.ty(tcx, substs))?.layout)) - .collect::<Result<Vec<_>, _>>() + .try_collect::<IndexVec<_, _>>() }) - .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; + .try_collect::<IndexVec<VariantIdx, _>>()?; if def.is_union() { if def.repr().pack.is_some() && def.repr().align.is_some() { @@ -452,7 +444,8 @@ fn layout_of_uncached<'tcx>( { let param_env = tcx.param_env(def.did()); def.is_struct() - && match def.variants().iter().next().and_then(|x| x.fields.last()) { + && match def.variants().iter().next().and_then(|x| x.fields.raw.last()) + { Some(last_field) => tcx .type_of(last_field.did) .subst_identity() @@ -487,8 +480,7 @@ fn layout_of_uncached<'tcx>( enum SavedLocalEligibility { Unassigned, Assigned(VariantIdx), - // FIXME: Use newtype_index so we aren't wasting bytes - Ineligible(Option<u32>), + Ineligible(Option<FieldIdx>), } // When laying out generators, we divide our saved local fields into two @@ -517,7 +509,7 @@ fn generator_saved_local_eligibility( use SavedLocalEligibility::*; let mut assignments: IndexVec<GeneratorSavedLocal, SavedLocalEligibility> = - IndexVec::from_elem_n(Unassigned, info.field_tys.len()); + IndexVec::from_elem(Unassigned, &info.field_tys); // The saved locals not eligible for overlap. These will get // "promoted" to the prefix of our generator. @@ -600,7 +592,7 @@ fn generator_saved_local_eligibility( // Write down the order of our locals that will be promoted to the prefix. { for (idx, local) in ineligible_locals.iter().enumerate() { - assignments[local] = Ineligible(Some(idx as u32)); + assignments[local] = Ineligible(Some(FieldIdx::from_usize(idx))); } } debug!("generator saved local assignments: {:?}", assignments); @@ -649,7 +641,7 @@ fn generator_layout<'tcx>( .map(|ty| Ok(cx.layout_of(ty)?.layout)) .chain(iter::once(Ok(tag_layout))) .chain(promoted_layouts) - .collect::<Result<Vec<_>, _>>()?; + .try_collect::<IndexVec<_, _>>()?; let prefix = univariant_uninterned( cx, ty, @@ -667,26 +659,28 @@ fn generator_layout<'tcx>( debug!("prefix = {:#?}", prefix); let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields { FieldsShape::Arbitrary { mut offsets, memory_index } => { - let mut inverse_memory_index = invert_mapping(&memory_index); + let mut inverse_memory_index = memory_index.invert_bijective_mapping(); // "a" (`0..b_start`) and "b" (`b_start..`) correspond to // "outer" and "promoted" fields respectively. - let b_start = (tag_index + 1) as u32; - let offsets_b = offsets.split_off(b_start as usize); + let b_start = FieldIdx::from_usize(tag_index + 1); + let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.as_usize())); let offsets_a = offsets; // Disentangle the "a" and "b" components of `inverse_memory_index` // by preserving the order but keeping only one disjoint "half" each. // FIXME(eddyb) build a better abstraction for permutations, if possible. - let inverse_memory_index_b: Vec<_> = - inverse_memory_index.iter().filter_map(|&i| i.checked_sub(b_start)).collect(); - inverse_memory_index.retain(|&i| i < b_start); + let inverse_memory_index_b: IndexVec<u32, FieldIdx> = inverse_memory_index + .iter() + .filter_map(|&i| i.as_u32().checked_sub(b_start.as_u32()).map(FieldIdx::from_u32)) + .collect(); + inverse_memory_index.raw.retain(|&i| i < b_start); let inverse_memory_index_a = inverse_memory_index; // Since `inverse_memory_index_{a,b}` each only refer to their // respective fields, they can be safely inverted - let memory_index_a = invert_mapping(&inverse_memory_index_a); - let memory_index_b = invert_mapping(&inverse_memory_index_b); + let memory_index_a = inverse_memory_index_a.invert_bijective_mapping(); + let memory_index_b = inverse_memory_index_b.invert_bijective_mapping(); let outer_fields = FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a }; @@ -717,7 +711,7 @@ fn generator_layout<'tcx>( ty, &variant_only_tys .map(|ty| Ok(cx.layout_of(ty)?.layout)) - .collect::<Result<Vec<_>, _>>()?, + .try_collect::<IndexVec<_, _>>()?, &ReprOptions::default(), StructKind::Prefixed(prefix_size, prefix_align.abi), )?; @@ -736,13 +730,16 @@ fn generator_layout<'tcx>( // promoted fields were being used, but leave the elements not in the // subset as `INVALID_FIELD_IDX`, which we can filter out later to // obtain a valid (bijective) mapping. - const INVALID_FIELD_IDX: u32 = !0; - let mut combined_inverse_memory_index = - vec![INVALID_FIELD_IDX; promoted_memory_index.len() + memory_index.len()]; + const INVALID_FIELD_IDX: FieldIdx = FieldIdx::MAX; + debug_assert!(variant_fields.next_index() <= INVALID_FIELD_IDX); + + let mut combined_inverse_memory_index = IndexVec::from_elem_n( + INVALID_FIELD_IDX, + promoted_memory_index.len() + memory_index.len(), + ); let mut offsets_and_memory_index = iter::zip(offsets, memory_index); let combined_offsets = variant_fields - .iter() - .enumerate() + .iter_enumerated() .map(|(i, local)| { let (offset, memory_index) = match assignments[*local] { Unassigned => bug!(), @@ -751,19 +748,19 @@ fn generator_layout<'tcx>( (offset, promoted_memory_index.len() as u32 + memory_index) } Ineligible(field_idx) => { - let field_idx = field_idx.unwrap() as usize; + let field_idx = field_idx.unwrap(); (promoted_offsets[field_idx], promoted_memory_index[field_idx]) } }; - combined_inverse_memory_index[memory_index as usize] = i as u32; + combined_inverse_memory_index[memory_index] = i; offset }) .collect(); // Remove the unused slots and invert the mapping to obtain the // combined `memory_index` (also see previous comment). - combined_inverse_memory_index.retain(|&i| i != INVALID_FIELD_IDX); - let combined_memory_index = invert_mapping(&combined_inverse_memory_index); + combined_inverse_memory_index.raw.retain(|&i| i != INVALID_FIELD_IDX); + let combined_memory_index = combined_inverse_memory_index.invert_bijective_mapping(); variant.fields = FieldsShape::Arbitrary { offsets: combined_offsets, @@ -774,7 +771,7 @@ fn generator_layout<'tcx>( align = align.max(variant.align); Ok(variant) }) - .collect::<Result<IndexVec<VariantIdx, _>, _>>()?; + .try_collect::<IndexVec<VariantIdx, _>>()?; size = size.align_to(align.abi); |