summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_ty_utils/src/layout.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_ty_utils/src/layout.rs')
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs143
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);