layout computation: eagerly error for unexpected unsized fields

This commit is contained in:
Lukas Markeffsky 2024-09-15 22:16:21 +02:00
parent 12aa05094f
commit 08344c2ae8
2 changed files with 40 additions and 38 deletions

View file

@ -1,13 +1,13 @@
//! Compute the binary representation of a type //! Compute the binary representation of a type
use std::{borrow::Cow, fmt}; use std::fmt;
use base_db::salsa::Cycle; use base_db::salsa::Cycle;
use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
use hir_def::{ use hir_def::{
layout::{ layout::{
Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutS,
Scalar, Size, StructKind, TargetDataLayout, WrappingRange, Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange,
}, },
LocalFieldId, StructId, LocalFieldId, StructId,
}; };
@ -15,7 +15,6 @@ use la_arena::{Idx, RawIdx};
use rustc_abi::AddressSpace; use rustc_abi::AddressSpace;
use rustc_index::{IndexSlice, IndexVec}; use rustc_index::{IndexSlice, IndexVec};
use stdx::never;
use triomphe::Arc; use triomphe::Arc;
use crate::{ use crate::{
@ -107,19 +106,24 @@ impl fmt::Display for LayoutError {
} }
} }
impl From<LayoutCalculatorError> for LayoutError {
fn from(err: LayoutCalculatorError) -> Self {
match err {
LayoutCalculatorError::UnexpectedUnsized | LayoutCalculatorError::EmptyUnion => {
LayoutError::Unknown
}
LayoutCalculatorError::SizeOverflow => LayoutError::SizeOverflow,
}
}
}
struct LayoutCx<'a> { struct LayoutCx<'a> {
target: &'a TargetDataLayout, calc: LayoutCalculator<&'a TargetDataLayout>,
} }
impl<'a> LayoutCalculator for LayoutCx<'a> { impl<'a> LayoutCx<'a> {
type TargetDataLayoutRef = &'a TargetDataLayout; fn new(target: &'a TargetDataLayout) -> Self {
Self { calc: LayoutCalculator::new(target) }
fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>) {
never!("{}", txt.into());
}
fn current_data_layout(&self) -> &'a TargetDataLayout {
self.target
} }
} }
@ -205,8 +209,8 @@ pub fn layout_of_ty_query(
let Ok(target) = db.target_data_layout(krate) else { let Ok(target) = db.target_data_layout(krate) else {
return Err(LayoutError::TargetLayoutNotAvailable); return Err(LayoutError::TargetLayoutNotAvailable);
}; };
let cx = LayoutCx { target: &target }; let dl = &*target;
let dl = cx.current_data_layout(); let cx = LayoutCx::new(dl);
let ty = normalize(db, trait_env.clone(), ty); let ty = normalize(db, trait_env.clone(), ty);
let result = match ty.kind(Interner) { let result = match ty.kind(Interner) {
TyKind::Adt(AdtId(def), subst) => { TyKind::Adt(AdtId(def), subst) => {
@ -281,7 +285,7 @@ pub fn layout_of_ty_query(
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>(); let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
let fields = fields.iter().collect::<IndexVec<_, _>>(); let fields = fields.iter().collect::<IndexVec<_, _>>();
cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)? cx.calc.univariant(&fields, &ReprOptions::default(), kind)?
} }
TyKind::Array(element, count) => { TyKind::Array(element, count) => {
let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64; let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64;
@ -367,12 +371,12 @@ pub fn layout_of_ty_query(
}; };
// Effectively a (ptr, meta) tuple. // Effectively a (ptr, meta) tuple.
cx.scalar_pair(data_ptr, metadata) cx.calc.scalar_pair(data_ptr, metadata)
} }
TyKind::FnDef(_, _) => layout_of_unit(&cx, dl)?, TyKind::FnDef(_, _) => layout_of_unit(&cx)?,
TyKind::Never => cx.layout_of_never_type(), TyKind::Never => cx.calc.layout_of_never_type(),
TyKind::Dyn(_) | TyKind::Foreign(_) => { TyKind::Dyn(_) | TyKind::Foreign(_) => {
let mut unit = layout_of_unit(&cx, dl)?; let mut unit = layout_of_unit(&cx)?;
match &mut unit.abi { match &mut unit.abi {
Abi::Aggregate { sized } => *sized = false, Abi::Aggregate { sized } => *sized = false,
_ => return Err(LayoutError::Unknown), _ => return Err(LayoutError::Unknown),
@ -414,8 +418,7 @@ pub fn layout_of_ty_query(
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>(); let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
let fields = fields.iter().collect::<IndexVec<_, _>>(); let fields = fields.iter().collect::<IndexVec<_, _>>();
cx.univariant(dl, &fields, &ReprOptions::default(), StructKind::AlwaysSized) cx.calc.univariant(&fields, &ReprOptions::default(), StructKind::AlwaysSized)?
.ok_or(LayoutError::Unknown)?
} }
TyKind::Coroutine(_, _) | TyKind::CoroutineWitness(_, _) => { TyKind::Coroutine(_, _) | TyKind::CoroutineWitness(_, _) => {
return Err(LayoutError::NotImplemented) return Err(LayoutError::NotImplemented)
@ -447,14 +450,14 @@ pub fn layout_of_ty_recover(
Err(LayoutError::RecursiveTypeWithoutIndirection) Err(LayoutError::RecursiveTypeWithoutIndirection)
} }
fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, LayoutError> { fn layout_of_unit(cx: &LayoutCx<'_>) -> Result<Layout, LayoutError> {
cx.univariant::<RustcFieldIdx, RustcEnumVariantIdx, &&Layout>( cx.calc
dl, .univariant::<RustcFieldIdx, RustcEnumVariantIdx, &&Layout>(
IndexSlice::empty(), IndexSlice::empty(),
&ReprOptions::default(), &ReprOptions::default(),
StructKind::AlwaysSized, StructKind::AlwaysSized,
) )
.ok_or(LayoutError::Unknown) .map_err(Into::into)
} }
fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty { fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty {

View file

@ -5,7 +5,7 @@ use std::{cmp, ops::Bound};
use base_db::salsa::Cycle; use base_db::salsa::Cycle;
use hir_def::{ use hir_def::{
data::adt::VariantData, data::adt::VariantData,
layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout}, layout::{Integer, ReprOptions, TargetDataLayout},
AdtId, VariantId, AdtId, VariantId,
}; };
use intern::sym; use intern::sym;
@ -36,8 +36,8 @@ pub fn layout_of_adt_query(
let Ok(target) = db.target_data_layout(krate) else { let Ok(target) = db.target_data_layout(krate) else {
return Err(LayoutError::TargetLayoutNotAvailable); return Err(LayoutError::TargetLayoutNotAvailable);
}; };
let cx = LayoutCx { target: &target }; let dl = &*target;
let dl = cx.current_data_layout(); let cx = LayoutCx::new(dl);
let handle_variant = |def: VariantId, var: &VariantData| { let handle_variant = |def: VariantId, var: &VariantData| {
var.fields() var.fields()
.iter() .iter()
@ -73,9 +73,9 @@ pub fn layout_of_adt_query(
.collect::<SmallVec<[_; 1]>>(); .collect::<SmallVec<[_; 1]>>();
let variants = variants.iter().map(|it| it.iter().collect()).collect::<IndexVec<_, _>>(); let variants = variants.iter().map(|it| it.iter().collect()).collect::<IndexVec<_, _>>();
let result = if matches!(def, AdtId::UnionId(..)) { let result = if matches!(def, AdtId::UnionId(..)) {
cx.layout_of_union(&repr, &variants).ok_or(LayoutError::Unknown)? cx.calc.layout_of_union(&repr, &variants)?
} else { } else {
cx.layout_of_struct_or_enum( cx.calc.layout_of_struct_or_enum(
&repr, &repr,
&variants, &variants,
matches!(def, AdtId::EnumId(..)), matches!(def, AdtId::EnumId(..)),
@ -103,8 +103,7 @@ pub fn layout_of_adt_query(
.next() .next()
.and_then(|it| it.iter().last().map(|it| !it.is_unsized())) .and_then(|it| it.iter().last().map(|it| !it.is_unsized()))
.unwrap_or(true), .unwrap_or(true),
) )?
.ok_or(LayoutError::SizeOverflow)?
}; };
Ok(Arc::new(result)) Ok(Arc::new(result))
} }