diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 6ba03f0340cc..1d7a1f11b6c8 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -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()) - } else { - bug!("failed to get layout for `{}`: {}", ty, e) - } - }) + #[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 { + span_bug!(span, "failed to get layout for `{}`: {}", ty, err) + } } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index d7885e653a10..2c420caad755 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -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) } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 1e54ad0c729c..6cb85eeb0d92 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -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()) - } else { - bug!("failed to get layout for `{}`: {}", ty, e) - } - }) + #[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 { + span_bug!(span, "failed to get layout for `{}`: {}", ty, err) + } } } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index a6d3bae65eca..ee43937e4d64 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -1083,8 +1083,9 @@ impl<'tcx> ty::layout::HasParamEnv<'tcx> for LateContext<'tcx> { impl<'tcx> LayoutOf<'tcx> for LateContext<'tcx> { type LayoutOfResult = Result, 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 } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 1259538bcfb1..a9cbe2314140 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -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>; - 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>, + ) -> >>::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, 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, 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 } } diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index f1f97ea05778..527caea19fa3 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -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() } } diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index a4de20ea1b4d..4be0f28f5d6c 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -333,8 +333,9 @@ struct ConstPropagator<'mir, 'tcx> { impl<'mir, 'tcx> LayoutOf<'tcx> for ConstPropagator<'mir, 'tcx> { type LayoutOfResult = Result, 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 } } diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index bef7a3c62d57..0b7fbb6bb8c0 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -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 + ); } }