ty::layout: implement layout_of automatically as a default method.

This commit is contained in:
Eduard-Mihai Burtescu 2021-08-30 18:01:58 +03:00
parent 4ce933f13f
commit 1e02262dcc
8 changed files with 105 additions and 54 deletions

View file

@ -1,4 +1,5 @@
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
use rustc_middle::ty::layout::LayoutError;
use rustc_middle::ty::SymbolName; use rustc_middle::ty::SymbolName;
use rustc_target::abi::call::FnAbi; use rustc_target::abi::call::FnAbi;
use rustc_target::abi::{Integer, Primitive}; use rustc_target::abi::{Integer, Primitive};
@ -259,8 +260,9 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
impl<'tcx> LayoutOf<'tcx> for FunctionCx<'_, '_, 'tcx> { impl<'tcx> LayoutOf<'tcx> for FunctionCx<'_, '_, 'tcx> {
type LayoutOfResult = TyAndLayout<'tcx>; type LayoutOfResult = TyAndLayout<'tcx>;
fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> { #[inline]
RevealAllLayoutCx(self.tcx).layout_of(ty) fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
RevealAllLayoutCx(self.tcx).handle_layout_err(err, span, ty)
} }
} }
@ -366,15 +368,13 @@ pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
impl<'tcx> LayoutOf<'tcx> for RevealAllLayoutCx<'tcx> { impl<'tcx> LayoutOf<'tcx> for RevealAllLayoutCx<'tcx> {
type LayoutOfResult = TyAndLayout<'tcx>; type LayoutOfResult = TyAndLayout<'tcx>;
fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> { #[inline]
assert!(!ty.still_further_specializable()); fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
self.0.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap_or_else(|e| { if let layout::LayoutError::SizeOverflow(_) = err {
if let layout::LayoutError::SizeOverflow(_) = e { self.0.sess.span_fatal(span, &err.to_string())
self.0.sess.fatal(&e.to_string())
} else { } else {
bug!("failed to get layout for `{}`: {}", ty, e) span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
} }
})
} }
} }

View file

@ -15,7 +15,7 @@ use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::MemFlags;
use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::small_c_str::SmallCStr;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::layout::{LayoutError, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span; use rustc_span::Span;
use rustc_target::abi::{self, Align, Size}; use rustc_target::abi::{self, Align, Size};
@ -91,8 +91,9 @@ impl HasTargetSpec for Builder<'_, '_, 'tcx> {
impl LayoutOf<'tcx> for Builder<'_, '_, 'tcx> { impl LayoutOf<'tcx> for Builder<'_, '_, 'tcx> {
type LayoutOfResult = TyAndLayout<'tcx>; type LayoutOfResult = TyAndLayout<'tcx>;
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult { #[inline]
self.cx.layout_of(ty) fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
self.cx.handle_layout_err(err, span, ty)
} }
} }

View file

@ -14,13 +14,13 @@ use rustc_codegen_ssa::traits::*;
use rustc_data_structures::base_n; use rustc_data_structures::base_n;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::small_c_str::SmallCStr;
use rustc_middle::bug;
use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::mir::mono::CodegenUnit;
use rustc_middle::ty::layout::{HasParamEnv, LayoutError, LayoutOf, TyAndLayout}; use rustc_middle::ty::layout::{HasParamEnv, LayoutError, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::config::{CFGuard, CrateType, DebugInfo}; use rustc_session::config::{CFGuard, CrateType, DebugInfo};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
@ -838,18 +838,13 @@ impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> {
impl LayoutOf<'tcx> for CodegenCx<'ll, 'tcx> { impl LayoutOf<'tcx> for CodegenCx<'ll, 'tcx> {
type LayoutOfResult = TyAndLayout<'tcx>; type LayoutOfResult = TyAndLayout<'tcx>;
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult { #[inline]
self.spanned_layout_of(ty, DUMMY_SP) fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
} if let LayoutError::SizeOverflow(_) = err {
self.sess().span_fatal(span, &err.to_string())
fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult {
self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap_or_else(|e| {
if let LayoutError::SizeOverflow(_) = e {
self.sess().span_fatal(span, &e.to_string())
} else { } else {
bug!("failed to get layout for `{}`: {}", ty, e) span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
} }
})
} }
} }

View file

@ -1083,8 +1083,9 @@ impl<'tcx> ty::layout::HasParamEnv<'tcx> for LateContext<'tcx> {
impl<'tcx> LayoutOf<'tcx> for LateContext<'tcx> { impl<'tcx> LayoutOf<'tcx> for LateContext<'tcx> {
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>; type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult { #[inline]
self.tcx.layout_of(self.param_env.and(ty)) fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
err
} }
} }

View file

@ -2095,35 +2095,74 @@ pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
/// Trait for contexts that can compute layouts of types. /// Trait for contexts that can compute layouts of types.
pub trait LayoutOf<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasParamEnv<'tcx> { pub trait LayoutOf<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasParamEnv<'tcx> {
/// The `TyAndLayout`-wrapping type (or `TyAndLayout` itself), which will be
/// returned from `layout_of` (see also `handle_layout_err`).
type LayoutOfResult: MaybeResult<TyAndLayout<'tcx>>; type LayoutOfResult: MaybeResult<TyAndLayout<'tcx>>;
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult; /// `Span` to use for `tcx.at(span)`, from `layout_of`.
// FIXME(eddyb) perhaps make this mandatory to get contexts to track it better?
#[inline]
fn layout_tcx_at_span(&self) -> Span {
DUMMY_SP
}
/// Helper used for `layout_of`, to adapt `tcx.layout_of(...)` into a
/// `Self::LayoutOfResult` (which does not need to be a `Result<...>`).
///
/// Most `impl`s, which propagate `LayoutError`s, should simply return `err`,
/// but this hook allows e.g. codegen to return only `TyAndLayout` from its
/// `cx.layout_of(...)`, without any `Result<...>` around it to deal with
/// (and any `LayoutError`s are turned into fatal errors or ICEs).
fn handle_layout_err(
&self,
err: LayoutError<'tcx>,
span: Span,
ty: Ty<'tcx>,
) -> <Self::LayoutOfResult as MaybeResult<TyAndLayout<'tcx>>>::Error;
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode, and will normalize the input type.
#[inline]
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
self.spanned_layout_of(ty, DUMMY_SP)
}
/// Computes the layout of a type, at `span`. Note that this implicitly
/// executes in "reveal all" mode, and will normalize the input type.
// FIXME(eddyb) avoid passing information like this, and instead add more // FIXME(eddyb) avoid passing information like this, and instead add more
// `TyCtxt::at`-like APIs to be able to do e.g. `cx.at(span).layout_of(ty)`. // `TyCtxt::at`-like APIs to be able to do e.g. `cx.at(span).layout_of(ty)`.
fn spanned_layout_of(&self, ty: Ty<'tcx>, _span: Span) -> Self::LayoutOfResult { #[inline]
self.layout_of(ty) fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult {
let span = if !span.is_dummy() { span } else { self.layout_tcx_at_span() };
MaybeResult::from(
self.tcx()
.at(span)
.layout_of(self.param_env().and(ty))
.map_err(|err| self.handle_layout_err(err, span, ty)),
)
} }
} }
impl LayoutOf<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> { impl LayoutOf<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>; type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode, and will normalize the input type.
#[inline] #[inline]
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult { fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
self.tcx.layout_of(self.param_env.and(ty)) err
} }
} }
impl LayoutOf<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> { impl LayoutOf<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>; type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode, and will normalize the input type.
#[inline] #[inline]
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult { fn layout_tcx_at_span(&self) -> Span {
self.tcx.layout_of(self.param_env.and(ty)) self.tcx.span
}
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
err
} }
} }

View file

@ -8,7 +8,7 @@ use rustc_index::vec::IndexVec;
use rustc_macros::HashStable; use rustc_macros::HashStable;
use rustc_middle::ich::StableHashingContext; use rustc_middle::ich::StableHashingContext;
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout}; use rustc_middle::ty::layout::{self, LayoutError, LayoutOf, TyAndLayout};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
}; };
@ -17,9 +17,9 @@ use rustc_span::{Pos, Span};
use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout}; use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout};
use super::{ use super::{
AllocId, GlobalId, Immediate, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance, Scalar, ScalarMaybeUninit, MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance, Scalar,
StackPopJump, ScalarMaybeUninit, StackPopJump,
}; };
use crate::transform::validate::equal_up_to_regions; use crate::transform::validate::equal_up_to_regions;
use crate::util::storage::AlwaysLiveLocals; use crate::util::storage::AlwaysLiveLocals;
@ -316,10 +316,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf<'tcx> for InterpCx<'mir,
type LayoutOfResult = InterpResult<'tcx, TyAndLayout<'tcx>>; type LayoutOfResult = InterpResult<'tcx, TyAndLayout<'tcx>>;
#[inline] #[inline]
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult { fn layout_tcx_at_span(&self) -> Span {
self.tcx self.tcx.span
.layout_of(self.param_env.and(ty)) }
.map_err(|layout| err_inval!(Layout(layout)).into())
#[inline]
fn handle_layout_err(
&self,
err: LayoutError<'tcx>,
_: Span,
_: Ty<'tcx>,
) -> InterpErrorInfo<'tcx> {
err_inval!(Layout(err)).into()
} }
} }

View file

@ -333,8 +333,9 @@ struct ConstPropagator<'mir, 'tcx> {
impl<'mir, 'tcx> LayoutOf<'tcx> for ConstPropagator<'mir, 'tcx> { impl<'mir, 'tcx> LayoutOf<'tcx> for ConstPropagator<'mir, 'tcx> {
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>; type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult { #[inline]
self.tcx.layout_of(self.param_env.and(ty)) fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
err
} }
} }

View file

@ -3,9 +3,10 @@ use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::ItemKind; use rustc_hir::ItemKind;
use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOf, TyAndLayout};
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::abi::{HasDataLayout, TargetDataLayout}; use rustc_target::abi::{HasDataLayout, TargetDataLayout};
pub fn test_layout(tcx: TyCtxt<'_>) { pub fn test_layout(tcx: TyCtxt<'_>) {
@ -116,8 +117,13 @@ struct UnwrapLayoutCx<'tcx> {
impl LayoutOf<'tcx> for UnwrapLayoutCx<'tcx> { impl LayoutOf<'tcx> for UnwrapLayoutCx<'tcx> {
type LayoutOfResult = TyAndLayout<'tcx>; type LayoutOfResult = TyAndLayout<'tcx>;
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult { fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
self.tcx.layout_of(self.param_env.and(ty)).unwrap() span_bug!(
span,
"`#[rustc_layout(..)]` test resulted in `layout_of({}) = Err({})`",
ty,
err
);
} }
} }