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_middle::ty::layout::LayoutError;
use rustc_middle::ty::SymbolName;
use rustc_target::abi::call::FnAbi;
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> {
type LayoutOfResult = TyAndLayout<'tcx>;
fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> {
RevealAllLayoutCx(self.tcx).layout_of(ty)
#[inline]
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> {
type LayoutOfResult = TyAndLayout<'tcx>;
fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> {
assert!(!ty.still_further_specializable());
self.0.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap_or_else(|e| {
if let layout::LayoutError::SizeOverflow(_) = e {
self.0.sess.fatal(&e.to_string())
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
if let layout::LayoutError::SizeOverflow(_) = err {
self.0.sess.span_fatal(span, &err.to_string())
} 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_data_structures::small_c_str::SmallCStr;
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_span::Span;
use rustc_target::abi::{self, Align, Size};
@ -91,8 +91,9 @@ impl HasTargetSpec for Builder<'_, '_, 'tcx> {
impl LayoutOf<'tcx> for Builder<'_, '_, 'tcx> {
type LayoutOfResult = TyAndLayout<'tcx>;
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
self.cx.layout_of(ty)
#[inline]
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::fx::FxHashMap;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_middle::bug;
use rustc_middle::mir::mono::CodegenUnit;
use rustc_middle::ty::layout::{HasParamEnv, LayoutError, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::config::{CFGuard, CrateType, DebugInfo};
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_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
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> {
type LayoutOfResult = TyAndLayout<'tcx>;
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
self.spanned_layout_of(ty, DUMMY_SP)
}
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())
#[inline]
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())
} 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> {
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
self.tcx.layout_of(self.param_env.and(ty))
#[inline]
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.
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>>;
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
// `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 {
self.layout_of(ty)
#[inline]
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>> {
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]
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
self.tcx.layout_of(self.param_env.and(ty))
fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
err
}
}
impl LayoutOf<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'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]
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
self.tcx.layout_of(self.param_env.and(ty))
fn layout_tcx_at_span(&self) -> Span {
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_middle::ich::StableHashingContext;
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::{
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 super::{
AllocId, GlobalId, Immediate, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory,
MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance, Scalar, ScalarMaybeUninit,
StackPopJump,
AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance, Scalar,
ScalarMaybeUninit, StackPopJump,
};
use crate::transform::validate::equal_up_to_regions;
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>>;
#[inline]
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
self.tcx
.layout_of(self.param_env.and(ty))
.map_err(|layout| err_inval!(Layout(layout)).into())
fn layout_tcx_at_span(&self) -> Span {
self.tcx.span
}
#[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> {
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
self.tcx.layout_of(self.param_env.and(ty))
#[inline]
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::itemlikevisit::ItemLikeVisitor;
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_span::symbol::sym;
use rustc_span::Span;
use rustc_target::abi::{HasDataLayout, TargetDataLayout};
pub fn test_layout(tcx: TyCtxt<'_>) {
@ -116,8 +117,13 @@ struct UnwrapLayoutCx<'tcx> {
impl LayoutOf<'tcx> for UnwrapLayoutCx<'tcx> {
type LayoutOfResult = TyAndLayout<'tcx>;
fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
self.tcx.layout_of(self.param_env.and(ty)).unwrap()
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
span_bug!(
span,
"`#[rustc_layout(..)]` test resulted in `layout_of({}) = Err({})`",
ty,
err
);
}
}