diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index e99a227a3a6ea..0e2966dd63d3e 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -79,7 +79,7 @@ pub(crate) fn codegen_fn<'tcx>( let arg_uninhabited = fx .mir .args_iter() - .any(|arg| fx.layout_of(fx.monomorphize(&fx.mir.local_decls[arg].ty)).abi.is_uninhabited()); + .any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).abi.is_uninhabited()); if !crate::constant::check_constants(&mut fx) { fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]); @@ -835,7 +835,7 @@ pub(crate) fn codegen_place<'tcx>( let from: u64 = from; let to: u64 = to; - match cplace.layout().ty.kind() { + match *cplace.layout().ty.kind() { ty::Array(elem_ty, _len) => { assert!(!from_end, "array subslices are never `from_end`"); let elem_layout = fx.layout_of(elem_ty); diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 03f462a63b31b..4a00c6fd7bfb3 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}; @@ -256,15 +257,6 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { pub(crate) inline_asm_index: u32, } -impl<'tcx> LayoutOf<'tcx> for FunctionCx<'_, '_, 'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = TyAndLayout<'tcx>; - - fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> { - RevealAllLayoutCx(self.tcx).layout_of(ty) - } -} - impl<'tcx> layout::HasTyCtxt<'tcx> for FunctionCx<'_, '_, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { self.tcx @@ -289,6 +281,15 @@ impl<'tcx> HasTargetSpec for FunctionCx<'_, '_, 'tcx> { } } +impl<'tcx> ty::layout::IsLayoutCx<'tcx> for FunctionCx<'_, '_, 'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; + + #[inline] + fn map_err_for_layout_of(err: LayoutError<'tcx>, cx: &Self, span: Span, ty: Ty<'tcx>) -> ! { + RevealAllLayoutCx::map_err_for_layout_of(err, &RevealAllLayoutCx(cx.tcx), span, ty) + } +} + impl<'tcx> FunctionCx<'_, '_, 'tcx> { pub(crate) fn monomorphize(&self, value: T) -> T where @@ -364,22 +365,6 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>); -impl<'tcx> LayoutOf<'tcx> for RevealAllLayoutCx<'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = 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) - } - }) - } -} - impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { self.0 @@ -403,3 +388,16 @@ impl<'tcx> HasTargetSpec for RevealAllLayoutCx<'tcx> { &self.0.sess.target } } + +impl<'tcx> ty::layout::IsLayoutCx<'tcx> for RevealAllLayoutCx<'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; + + #[inline] + fn map_err_for_layout_of(err: LayoutError<'tcx>, cx: &Self, span: Span, ty: Ty<'tcx>) -> ! { + if let layout::LayoutError::SizeOverflow(_) = err { + cx.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_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 424a0d742d12b..8c84b1ab3bf2f 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -489,7 +489,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( return None; } let const_val = mir_operand_get_const_val(fx, operand)?; - if fx.layout_of(ty).size + if fx.layout_of(*ty).size != const_val.try_to_scalar_int()?.size() { return None; diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 364b3da92b888..c017206ad2618 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -678,7 +678,7 @@ impl<'tcx> CPlace<'tcx> { fx: &mut FunctionCx<'_, '_, 'tcx>, index: Value, ) -> CPlace<'tcx> { - let (elem_layout, ptr) = match self.layout().ty.kind() { + let (elem_layout, ptr) = match *self.layout().ty.kind() { ty::Array(elem_ty, _) => (fx.layout_of(elem_ty), self.to_ptr()), ty::Slice(elem_ty) => (fx.layout_of(elem_ty), self.to_ptr_maybe_unsized().0), _ => bug!("place_index({:?})", self.layout().ty), diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 47529f719b514..d91b9f25bfa3e 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::TyAndLayout; +use rustc_middle::ty::layout::{LayoutError, TyAndLayout}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; use rustc_target::abi::{self, Align, Size}; @@ -88,12 +88,12 @@ impl HasTargetSpec for Builder<'_, '_, 'tcx> { } } -impl abi::LayoutOf<'tcx> for Builder<'_, '_, 'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = TyAndLayout<'tcx>; +impl ty::layout::IsLayoutCx<'tcx> for Builder<'_, '_, 'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.cx.layout_of(ty) + #[inline] + fn map_err_for_layout_of(err: LayoutError<'tcx>, bx: &Self, span: Span, ty: Ty<'tcx>) -> ! { + CodegenCx::map_err_for_layout_of(err, bx.cx, span, ty) } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 45da18d4a24f3..93f4a2c9eebf3 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -14,15 +14,15 @@ 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, 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, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx}; +use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; use smallvec::SmallVec; @@ -835,27 +835,21 @@ impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> { } } -impl LayoutOf<'tcx> for CodegenCx<'ll, 'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = TyAndLayout<'tcx>; - - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.spanned_layout_of(ty, DUMMY_SP) - } - - fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::TyAndLayout { - 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) - } - }) - } -} - impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx> { ty::ParamEnv::reveal_all() } } + +impl ty::layout::IsLayoutCx<'tcx> for CodegenCx<'ll, 'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; + + #[inline] + fn map_err_for_layout_of(err: LayoutError<'tcx>, cx: &Self, span: Span, ty: Ty<'tcx>) -> ! { + if let LayoutError::SizeOverflow(_) = err { + cx.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/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 914376d58ddee..d028621209f55 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -401,7 +401,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let t = arg.layout.ty; let t = match t.kind() { ty::Array(ct, _) - if (*ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => + if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() => { cx.tcx.mk_imm_ptr(ct) } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 1393fc71d6bc3..139cea1bd50ee 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -10,13 +10,12 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn}; use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_session::{ config::{self, OutputFilenames, PrintRequest}, Session, }; use rustc_span::symbol::Symbol; -use rustc_target::abi::LayoutOf; use rustc_target::spec::Target; pub use rustc_data_structures::sync::MetadataRef; @@ -42,14 +41,14 @@ pub trait Backend<'tcx>: Sized + BackendTypes + HasTyCtxt<'tcx> - + LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>> + + ty::layout::IsLayoutCx<'tcx, LayoutOfResult = TyAndLayout<'tcx>> { } impl<'tcx, T> Backend<'tcx> for T where Self: BackendTypes + HasTyCtxt<'tcx> - + LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>> + + ty::layout::IsLayoutCx<'tcx, LayoutOfResult = TyAndLayout<'tcx>> { } diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index c529fbbf518b6..a8e908133c5a3 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -44,6 +44,11 @@ pub use self::type_::{ }; pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; +// HACK(eddyb) this means that `traits::*` imports will also import `LayoutOf`, +// which wasn't needed previously because `Backend` itself having `LayoutOf` as +// a supertrait meant that methods from `LayoutOf` were always available. +pub use rustc_target::abi::LayoutOf as _; + use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt}; use rustc_target::spec::HasTargetSpec; diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index a5b4fa15921b8..9b47d5fb3b4d9 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2830,18 +2830,19 @@ impl ClashingExternDeclarations { let a_kind = a.kind(); let b_kind = b.kind(); - let compare_layouts = |a, b| -> Result> { - debug!("compare_layouts({:?}, {:?})", a, b); - let a_layout = &cx.layout_of(a)?.layout.abi; - let b_layout = &cx.layout_of(b)?.layout.abi; - debug!( - "comparing layouts: {:?} == {:?} = {}", - a_layout, - b_layout, - a_layout == b_layout - ); - Ok(a_layout == b_layout) - }; + let compare_layouts = + |a: Ty<'tcx>, b: Ty<'tcx>| -> Result> { + debug!("compare_layouts({:?}, {:?})", a, b); + let a_layout = &cx.layout_of(a)?.layout.abi; + let b_layout = &cx.layout_of(b)?.layout.abi; + debug!( + "comparing layouts: {:?} == {:?} = {}", + a_layout, + b_layout, + a_layout == b_layout + ); + Ok(a_layout == b_layout) + }; #[allow(rustc::usage_of_ty_tykind)] let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 7dbc3d60439c4..1166f430fb108 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -41,7 +41,7 @@ use rustc_session::Session; use rustc_session::SessionLintStore; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP}; -use rustc_target::abi::{self, LayoutOf}; +use rustc_target::abi; use tracing::debug; use std::cell::Cell; @@ -1080,12 +1080,17 @@ impl<'tcx> ty::layout::HasParamEnv<'tcx> for LateContext<'tcx> { } } -impl<'tcx> LayoutOf<'tcx> for LateContext<'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = Result, LayoutError<'tcx>>; +impl<'tcx> ty::layout::IsLayoutCx<'tcx> for LateContext<'tcx> { + type LayoutOfResult = Result, LayoutError<'tcx>>; - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.tcx.layout_of(self.param_env.and(ty)) + #[inline] + fn map_err_for_layout_of( + err: LayoutError<'tcx>, + _cx: &Self, + _span: Span, + _ty: Ty<'tcx>, + ) -> LayoutError<'tcx> { + err } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 5e5902abe662f..f2a0943c1f1da 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -13,7 +13,7 @@ use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; use rustc_session::{config::OptLevel, DataTypeKind, FieldInfo, SizeKind, VariantInfo}; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::DUMMY_SP; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::call::{ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind, }; @@ -2012,10 +2012,24 @@ pub trait HasTyCtxt<'tcx>: HasDataLayout { fn tcx(&self) -> TyCtxt<'tcx>; } +impl> HasTyCtxt<'tcx> for &mut T { + #[inline] + fn tcx(&self) -> TyCtxt<'tcx> { + (**self).tcx() + } +} + pub trait HasParamEnv<'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx>; } +impl> HasParamEnv<'tcx> for &mut T { + #[inline] + fn param_env(&self) -> ty::ParamEnv<'tcx> { + (**self).param_env() + } +} + impl<'tcx> HasDataLayout for TyCtxt<'tcx> { #[inline] fn data_layout(&self) -> &TargetDataLayout { @@ -2064,34 +2078,110 @@ impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> { pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>; -impl LayoutOf<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> { - type Ty = Ty<'tcx>; - type TyAndLayout = Result, LayoutError<'tcx>>; +/// Trait that indicates a context which should have `cx.layout_of(...)` +/// (provided by `rustc_target::abi::LayoutOf` through `TyAbiInterface`), +/// and which should be able to be used for various layout methods, +/// e.g. `layout.for_variant(cx, v)` and `layout.field(cx, i)`. +pub trait IsLayoutCx<'tcx>: HasTyCtxt<'tcx> + HasParamEnv<'tcx> { + /// The `TyAndLayout`-wrapping type (or `TyAndLayout` itself), which will be + /// returned from `cx.layout_of(...)` (see also `map_err_for_layout_of`). + type LayoutOfResult: MaybeResult>; + + /// `Span` to use for `tcx.at(span)`, from `cx.layout_of(...)`. + // FIXME(eddyb) perhaps make this mandatory to get contexts to track it better? + #[inline] + fn tcx_at_span_for_layout_of(_cx: &Self) -> Span { + DUMMY_SP + } + + /// Helper used for `cx.layout_of(...)`, to adapt `tcx.layout_of(...)` + /// into a `Self::LayoutOfResult` (which may not even 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 map_err_for_layout_of( + err: LayoutError<'tcx>, + cx: &Self, + span: Span, + ty: Ty<'tcx>, + ) -> >>::Error; +} + +impl> IsLayoutCx<'tcx> for &mut C { + type LayoutOfResult = C::LayoutOfResult; + + #[inline] + fn tcx_at_span_for_layout_of(cx: &Self) -> Span { + C::tcx_at_span_for_layout_of(cx) + } - /// 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::TyAndLayout { - self.tcx.layout_of(self.param_env.and(ty)) + fn map_err_for_layout_of( + err: LayoutError<'tcx>, + cx: &Self, + span: Span, + ty: Ty<'tcx>, + ) -> >>::Error { + C::map_err_for_layout_of(err, cx, span, ty) } } -impl LayoutOf<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> { - type Ty = Ty<'tcx>; - type TyAndLayout = Result, LayoutError<'tcx>>; +impl IsLayoutCx<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> { + type LayoutOfResult = Result, LayoutError<'tcx>>; + + #[inline] + fn map_err_for_layout_of( + err: LayoutError<'tcx>, + _cx: &Self, + _span: Span, + _ty: Ty<'tcx>, + ) -> LayoutError<'tcx> { + err + } +} + +impl IsLayoutCx<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> { + type LayoutOfResult = Result, LayoutError<'tcx>>; + + #[inline] + fn tcx_at_span_for_layout_of(cx: &Self) -> Span { + cx.tcx.span + } - /// 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::TyAndLayout { - self.tcx.layout_of(self.param_env.and(ty)) + fn map_err_for_layout_of( + err: LayoutError<'tcx>, + _cx: &Self, + _span: Span, + _ty: Ty<'tcx>, + ) -> LayoutError<'tcx> { + err } } impl<'tcx, C> TyAbiInterface<'tcx, C> for Ty<'tcx> where - C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>, + C: IsLayoutCx<'tcx>, { + type CxLayoutOfResult = C::LayoutOfResult; + + #[inline] + fn cx_layout_of(ty: Ty<'tcx>, cx: &C) -> C::LayoutOfResult { + Self::cx_spanned_layout_of(ty, cx, DUMMY_SP) + } + #[inline] + fn cx_spanned_layout_of(ty: Ty<'tcx>, cx: &C, span: Span) -> C::LayoutOfResult { + let span = if !span.is_dummy() { span } else { C::tcx_at_span_for_layout_of(cx) }; + MaybeResult::from( + cx.tcx() + .at(span) + .layout_of(cx.param_env().and(ty)) + .map_err(|err| C::map_err_for_layout_of(err, cx, span, ty)), + ) + } + fn ty_and_layout_for_variant( this: TyAndLayout<'tcx>, cx: &C, @@ -2559,11 +2649,7 @@ impl<'tcx> ty::Instance<'tcx> { pub trait FnAbiExt<'tcx, C> where - C: LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>, + C: IsLayoutCx<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec, { /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. /// @@ -2746,11 +2832,7 @@ pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv { impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>> where - C: LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>, + C: IsLayoutCx<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec, { fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { call::FnAbi::new_internal(cx, sig, extra_args, None, CodegenFnAttrFlags::empty(), false) @@ -3026,7 +3108,7 @@ where } fn make_thin_self_ptr<'tcx>( - cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>), + cx: &impl IsLayoutCx<'tcx>, layout: TyAndLayout<'tcx>, ) -> TyAndLayout<'tcx> { let tcx = cx.tcx(); diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index bfb3de04c59fb..2dd4e4c44853b 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, TyAndLayout}; +use rustc_middle::ty::layout::{self, LayoutError, 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, LayoutOf, 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; @@ -312,15 +312,24 @@ where } } -impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf<'tcx> for InterpCx<'mir, 'tcx, M> { - type Ty = Ty<'tcx>; - type TyAndLayout = InterpResult<'tcx, TyAndLayout<'tcx>>; +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ty::layout::IsLayoutCx<'tcx> + for InterpCx<'mir, 'tcx, M> +{ + type LayoutOfResult = InterpResult<'tcx, TyAndLayout<'tcx>>; + + #[inline] + fn tcx_at_span_for_layout_of(cx: &Self) -> Span { + cx.tcx.span + } #[inline] - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.tcx - .layout_of(self.param_env.and(ty)) - .map_err(|layout| err_inval!(Layout(layout)).into()) + fn map_err_for_layout_of( + err: LayoutError<'tcx>, + _cx: &Self, + _span: Span, + _ty: Ty<'tcx>, + ) -> InterpErrorInfo<'tcx> { + err_inval!(Layout(err)).into() } } diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index 2bb2f88725784..c16ea99a06647 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -557,7 +557,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' { // A mutable reference inside a const? That does not seem right (except if it is // a ZST). - let layout = self.ecx.layout_of(ty)?; + let layout = self.ecx.layout_of(*ty)?; if !layout.is_zst() { throw_validation_failure!(self.path, { "mutable reference in a `const`" }); } @@ -810,7 +810,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> op: &OpTy<'tcx, M::PointerTag>, fields: impl Iterator>, ) -> InterpResult<'tcx> { - match op.layout.ty.kind() { + match *op.layout.ty.kind() { ty::Str => { let mplace = op.assert_mem_place(); // strings are never immediate let len = mplace.len(self.ecx)?; diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index 5c51aa4ed679b..c3876561fd3ba 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -330,15 +330,6 @@ struct ConstPropagator<'mir, 'tcx> { source_info: Option, } -impl<'mir, 'tcx> LayoutOf<'tcx> for ConstPropagator<'mir, 'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = Result, LayoutError<'tcx>>; - - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.tcx.layout_of(self.param_env.and(ty)) - } -} - impl<'mir, 'tcx> HasDataLayout for ConstPropagator<'mir, 'tcx> { #[inline] fn data_layout(&self) -> &TargetDataLayout { @@ -360,6 +351,20 @@ impl<'mir, 'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'mir, 'tcx> { } } +impl<'mir, 'tcx> ty::layout::IsLayoutCx<'tcx> for ConstPropagator<'mir, 'tcx> { + type LayoutOfResult = Result, LayoutError<'tcx>>; + + #[inline] + fn map_err_for_layout_of( + err: LayoutError<'tcx>, + _cx: &Self, + _span: Span, + _ty: Ty<'tcx>, + ) -> LayoutError<'tcx> { + err + } +} + impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn new( body: &Body<'tcx>, @@ -869,7 +874,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let alloc = self.use_ecx(|this| { let ty1 = substs[0].expect_ty(); let ty2 = substs[1].expect_ty(); - let ty_is_scalar = |ty| { + let ty_is_scalar = |ty: Ty<'tcx>| { this.ecx.layout_of(ty).ok().map(|layout| layout.abi.is_scalar()) == Some(true) }; diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 64ea4ee570e82..ce9600bd705d2 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -3,10 +3,11 @@ 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, TyAndLayout}; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout}; +use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; use rustc_span::symbol::sym; -use rustc_target::abi::{HasDataLayout, LayoutOf, TargetDataLayout}; +use rustc_span::Span; +use rustc_target::abi::{HasDataLayout, TargetDataLayout}; pub fn test_layout(tcx: TyCtxt<'_>) { if tcx.features().rustc_attrs { @@ -113,15 +114,6 @@ struct UnwrapLayoutCx<'tcx> { param_env: ParamEnv<'tcx>, } -impl LayoutOf<'tcx> for UnwrapLayoutCx<'tcx> { - type Ty = Ty<'tcx>; - type TyAndLayout = TyAndLayout<'tcx>; - - fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - self.tcx.layout_of(self.param_env.and(ty)).unwrap() - } -} - impl HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx @@ -139,3 +131,16 @@ impl HasDataLayout for UnwrapLayoutCx<'tcx> { self.tcx.data_layout() } } + +impl ty::layout::IsLayoutCx<'tcx> for UnwrapLayoutCx<'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; + + fn map_err_for_layout_of(err: LayoutError<'tcx>, _cx: &Self, span: Span, ty: Ty<'tcx>) -> ! { + span_bug!( + span, + "`#[rustc_layout(..)]` test resulted in `layout_of({}) = Err({})`", + ty, + err + ); + } +} diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 820399943f0af..951655d0e7562 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -231,6 +231,13 @@ pub trait HasDataLayout { fn data_layout(&self) -> &TargetDataLayout; } +impl HasDataLayout for &mut T { + #[inline] + fn data_layout(&self) -> &TargetDataLayout { + (**self).data_layout() + } +} + impl HasDataLayout for TargetDataLayout { #[inline] fn data_layout(&self) -> &TargetDataLayout { @@ -1173,17 +1180,6 @@ impl<'a, Ty> Deref for TyAndLayout<'a, Ty> { } } -/// Trait for context types that can compute layouts of things. -pub trait LayoutOf<'a>: Sized { - type Ty: TyAbiInterface<'a, Self>; - type TyAndLayout: MaybeResult>; - - fn layout_of(&self, ty: Self::Ty) -> Self::TyAndLayout; - fn spanned_layout_of(&self, ty: Self::Ty, _span: Span) -> Self::TyAndLayout { - self.layout_of(ty) - } -} - pub trait MaybeResult { type Error; @@ -1239,6 +1235,13 @@ pub struct PointeeInfo { /// Trait that needs to be implemented by the higher-level type representation /// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality. pub trait TyAbiInterface<'a, C>: Sized { + type CxLayoutOfResult: MaybeResult>; + + fn cx_layout_of(ty: Self, cx: &C) -> Self::CxLayoutOfResult; + // 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 cx_spanned_layout_of(ty: Self, cx: &C, span: Span) -> Self::CxLayoutOfResult; + fn ty_and_layout_for_variant( this: TyAndLayout<'a, Self>, cx: &C, @@ -1252,6 +1255,23 @@ pub trait TyAbiInterface<'a, C>: Sized { ) -> Option; } +/// Extension trait for contexts that can compute layouts from types. +// NOTE(eddyb) this has to be an extension trait because `C::layout_of` proxies +// to `TyAbiInterface::::cx_layout_of`, and we don't want to require wrapping +// whichever `C` context type the user has, or require inherent methods on it. +pub trait LayoutOf<'a, Ty: TyAbiInterface<'a, Self>>: Sized { + fn layout_of(&self, ty: Ty) -> Ty::CxLayoutOfResult { + Ty::cx_layout_of(ty, self) + } + // 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, span: Span) -> Ty::CxLayoutOfResult { + Ty::cx_spanned_layout_of(ty, self, span) + } +} + +impl<'a, Ty: TyAbiInterface<'a, C>, C> LayoutOf<'a, Ty> for C {} + impl<'a, Ty> TyAndLayout<'a, Ty> { pub fn for_variant(self, cx: &C, variant_index: VariantIdx) -> Self where diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index 5d4e06c2af082..1ee2503ec58dd 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { if !item.span.from_expansion(); if let ItemKind::Const(hir_ty, _) = &item.kind; let ty = hir_ty_to_ty(cx.tcx, hir_ty); - if let ty::Array(element_type, cst) = ty.kind(); + if let ty::Array(element_type, cst) = *ty.kind(); if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val; if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index 7088630bfdbb4..566bedd08cee7 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -42,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Repeat(_, _) = expr.kind; - if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind(); + if let ty::Array(element_type, cst) = *cx.typeck_results().expr_ty(expr).kind(); if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val; if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 157b18c1f6b1f..4d696cd4032dc 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -152,7 +152,7 @@ impl<'tcx> PassByRefOrValue { _ => (), } - match ty.kind() { + match *ty.kind() { ty::Ref(input_lt, ty, Mutability::Not) => { // Use lifetimes to determine if we're returning a reference to the // argument. In that case we can't switch to pass-by-value as the @@ -164,7 +164,7 @@ impl<'tcx> PassByRefOrValue { }; if_chain! { - if !output_lts.contains(input_lt); + if !output_lts.contains(&input_lt); if is_copy(cx, ty); if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()); if size <= self.ref_min_size;