summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/ty/layout.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle/src/ty/layout.rs')
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs200
1 files changed, 96 insertions, 104 deletions
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index b5a743cfe..d95b05ef7 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1,8 +1,9 @@
-use crate::fluent_generated as fluent;
+use crate::error::UnsupportedFnAbi;
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::query::TyCtxtAt;
use crate::ty::normalize_erasing_regions::NormalizationError;
-use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitableExt};
+use crate::ty::{self, ConstKind, ReprOptions, Ty, TyCtxt, TypeVisitableExt};
+use rustc_error_messages::DiagnosticMessage;
use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@@ -14,7 +15,7 @@ use rustc_target::abi::call::FnAbi;
use rustc_target::abi::*;
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
-use std::cmp::{self};
+use std::cmp;
use std::fmt;
use std::num::NonZeroUsize;
use std::ops::Bound;
@@ -132,7 +133,7 @@ impl PrimitiveExt for Primitive {
F32 => tcx.types.f32,
F64 => tcx.types.f64,
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
- Pointer(_) => tcx.mk_mut_ptr(tcx.mk_unit()),
+ Pointer(_) => Ty::new_mut_ptr(tcx, Ty::new_unit(tcx)),
}
}
@@ -214,29 +215,29 @@ pub enum LayoutError<'tcx> {
Cycle,
}
-impl IntoDiagnostic<'_, !> for LayoutError<'_> {
- fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
- let mut diag = handler.struct_fatal("");
+impl<'tcx> LayoutError<'tcx> {
+ pub fn diagnostic_message(&self) -> DiagnosticMessage {
+ use crate::fluent_generated::*;
+ use LayoutError::*;
+ match self {
+ Unknown(_) => middle_unknown_layout,
+ SizeOverflow(_) => middle_values_too_big,
+ NormalizationFailure(_, _) => middle_cannot_be_normalized,
+ Cycle => middle_cycle,
+ }
+ }
+ pub fn into_diagnostic(self) -> crate::error::LayoutError<'tcx> {
+ use crate::error::LayoutError as E;
+ use LayoutError::*;
match self {
- LayoutError::Unknown(ty) => {
- diag.set_arg("ty", ty);
- diag.set_primary_message(fluent::middle_unknown_layout);
- }
- LayoutError::SizeOverflow(ty) => {
- diag.set_arg("ty", ty);
- diag.set_primary_message(fluent::middle_values_too_big);
- }
- LayoutError::NormalizationFailure(ty, e) => {
- diag.set_arg("ty", ty);
- diag.set_arg("failure_ty", e.get_type_for_failure());
- diag.set_primary_message(fluent::middle_cannot_be_normalized);
- }
- LayoutError::Cycle => {
- diag.set_primary_message(fluent::middle_cycle);
+ Unknown(ty) => E::Unknown { ty },
+ SizeOverflow(ty) => E::Overflow { ty },
+ NormalizationFailure(ty, e) => {
+ E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
}
+ Cycle => E::Cycle,
}
- diag
}
}
@@ -309,7 +310,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
ty: Ty<'tcx>,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- ) -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
+ ) -> Result<SizeSkeleton<'tcx>, &'tcx LayoutError<'tcx>> {
debug_assert!(!ty.has_non_region_infer());
// First try computing a static layout.
@@ -317,7 +318,13 @@ impl<'tcx> SizeSkeleton<'tcx> {
Ok(layout) => {
return Ok(SizeSkeleton::Known(layout.size));
}
- Err(err) => err,
+ Err(err @ LayoutError::Unknown(_)) => err,
+ // We can't extract SizeSkeleton info from other layout errors
+ Err(
+ e @ LayoutError::Cycle
+ | e @ LayoutError::SizeOverflow(_)
+ | e @ LayoutError::NormalizationFailure(..),
+ ) => return Err(e),
};
match *ty.kind() {
@@ -330,11 +337,8 @@ impl<'tcx> SizeSkeleton<'tcx> {
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
}
_ => bug!(
- "SizeSkeleton::compute({}): layout errored ({}), yet \
- tail `{}` is not a type parameter or a projection",
- ty,
- err,
- tail
+ "SizeSkeleton::compute({ty}): layout errored ({err:?}), yet \
+ tail `{tail}` is not a type parameter or a projection",
),
}
}
@@ -349,13 +353,13 @@ impl<'tcx> SizeSkeleton<'tcx> {
let size = s
.bytes()
.checked_mul(c)
- .ok_or_else(|| LayoutError::SizeOverflow(ty))?;
+ .ok_or_else(|| &*tcx.arena.alloc(LayoutError::SizeOverflow(ty)))?;
return Ok(SizeSkeleton::Known(Size::from_bytes(size)));
}
let len = tcx.expand_abstract_consts(len);
let prev = ty::Const::from_target_usize(tcx, s.bytes());
let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, prev) else {
- return Err(LayoutError::SizeOverflow(ty));
+ return Err(tcx.arena.alloc(LayoutError::SizeOverflow(ty)));
};
Ok(SizeSkeleton::Generic(gen_size))
}
@@ -363,7 +367,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
SizeSkeleton::Generic(g) => {
let len = tcx.expand_abstract_consts(len);
let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, g) else {
- return Err(LayoutError::SizeOverflow(ty));
+ return Err(tcx.arena.alloc(LayoutError::SizeOverflow(ty)));
};
Ok(SizeSkeleton::Generic(gen_size))
}
@@ -476,13 +480,11 @@ fn mul_sorted_consts<'tcx>(
b: ty::Const<'tcx>,
) -> Option<ty::Const<'tcx>> {
use crate::mir::BinOp::Mul;
- use ty::ConstKind::Expr;
- use ty::Expr::Binop;
let mut work = vec![a, b];
let mut done = vec![];
while let Some(n) = work.pop() {
- if let Expr(Binop(Mul, l, r)) = n.kind() {
+ if let ConstKind::Expr(ty::Expr::Binop(Mul, l, r)) = n.kind() {
work.push(l);
work.push(r)
} else {
@@ -513,7 +515,7 @@ fn mul_sorted_consts<'tcx>(
done.sort_unstable();
// create a single tree from the buffer
- done.into_iter().reduce(|acc, n| tcx.mk_const(Expr(Binop(Mul, n, acc)), n.ty()))
+ done.into_iter().reduce(|acc, n| ty::Const::new_expr(tcx, ty::Expr::Binop(Mul, n, acc), n.ty()))
}
pub trait HasTyCtxt<'tcx>: HasDataLayout {
@@ -668,7 +670,7 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
MaybeResult::from(
tcx.layout_of(self.param_env().and(ty))
- .map_err(|err| self.handle_layout_err(err, span, ty)),
+ .map_err(|err| self.handle_layout_err(*err, span, ty)),
)
}
}
@@ -676,16 +678,21 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
- type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
+ type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
#[inline]
- fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
- err
+ fn handle_layout_err(
+ &self,
+ err: LayoutError<'tcx>,
+ _: Span,
+ _: Ty<'tcx>,
+ ) -> &'tcx LayoutError<'tcx> {
+ self.tcx.arena.alloc(err)
}
}
impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> {
- type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
+ type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
#[inline]
fn layout_tcx_at_span(&self) -> Span {
@@ -693,8 +700,13 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> {
}
#[inline]
- fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
- err
+ fn handle_layout_err(
+ &self,
+ err: LayoutError<'tcx>,
+ _: Span,
+ _: Ty<'tcx>,
+ ) -> &'tcx LayoutError<'tcx> {
+ self.tcx.arena.alloc(err)
}
}
@@ -798,11 +810,11 @@ where
// (which may have no non-DST form), and will work as long
// as the `Abi` or `FieldsShape` is checked by users.
if i == 0 {
- let nil = tcx.mk_unit();
+ let nil = Ty::new_unit(tcx);
let unit_ptr_ty = if this.ty.is_unsafe_ptr() {
- tcx.mk_mut_ptr(nil)
+ Ty::new_mut_ptr(tcx, nil)
} else {
- tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
+ Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, nil)
};
// NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing
@@ -815,7 +827,11 @@ where
}
let mk_dyn_vtable = || {
- tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3))
+ Ty::new_imm_ref(
+ tcx,
+ tcx.lifetimes.re_static,
+ Ty::new_array(tcx, tcx.types.usize, 3),
+ )
/* FIXME: use actual fn pointers
Warning: naively computing the number of entries in the
vtable by counting the methods on the trait + methods on
@@ -824,9 +840,9 @@ where
Increase this counter if you tried to implement this but
failed to do it without duplicating a lot of code from
other places in the compiler: 2
- tcx.mk_tup(&[
- tcx.mk_array(tcx.types.usize, 3),
- tcx.mk_array(Option<fn()>),
+ Ty::new_tup(tcx,&[
+ Ty::new_array(tcx,tcx.types.usize, 3),
+ Ty::new_array(tcx,Option<fn()>),
])
*/
};
@@ -838,7 +854,7 @@ where
{
let metadata = tcx.normalize_erasing_regions(
cx.param_env(),
- tcx.mk_projection(metadata_def_id, [pointee]),
+ Ty::new_projection(tcx,metadata_def_id, [pointee]),
);
// Map `Metadata = DynMetadata<dyn Trait>` back to a vtable, since it
@@ -913,15 +929,14 @@ where
ty::Dynamic(_, _, ty::DynStar) => {
if i == 0 {
- TyMaybeWithLayout::Ty(tcx.mk_mut_ptr(tcx.types.unit))
+ TyMaybeWithLayout::Ty(Ty::new_mut_ptr(tcx, tcx.types.unit))
} else if i == 1 {
// FIXME(dyn-star) same FIXME as above applies here too
- TyMaybeWithLayout::Ty(
- tcx.mk_imm_ref(
- tcx.lifetimes.re_static,
- tcx.mk_array(tcx.types.usize, 3),
- ),
- )
+ TyMaybeWithLayout::Ty(Ty::new_imm_ref(
+ tcx,
+ tcx.lifetimes.re_static,
+ Ty::new_array(tcx, tcx.types.usize, 3),
+ ))
} else {
bug!("no field {i} on dyn*")
}
@@ -940,12 +955,8 @@ where
TyMaybeWithLayout::Ty(field_ty) => {
cx.tcx().layout_of(cx.param_env().and(field_ty)).unwrap_or_else(|e| {
bug!(
- "failed to get layout for `{}`: {},\n\
- despite it being a field (#{}) of an existing layout: {:#?}",
- field_ty,
- e,
- i,
- this
+ "failed to get layout for `{field_ty}`: {e:?},\n\
+ despite it being a field (#{i}) of an existing layout: {this:#?}",
)
})
}
@@ -970,10 +981,8 @@ where
})
}
ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
- tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo {
- size: layout.size,
- align: layout.align.abi,
- safe: None,
+ tcx.layout_of(param_env.and(Ty::new_fn_ptr(tcx, fn_sig))).ok().map(|layout| {
+ PointeeInfo { size: layout.size, align: layout.align.abi, safe: None }
})
}
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
@@ -1101,12 +1110,11 @@ where
///
/// This takes two primary parameters:
///
-/// * `codegen_fn_attr_flags` - these are flags calculated as part of the
-/// codegen attrs for a defined function. For function pointers this set of
-/// flags is the empty set. This is only applicable for Rust-defined
-/// functions, and generally isn't needed except for small optimizations where
-/// we try to say a function which otherwise might look like it could unwind
-/// doesn't actually unwind (such as for intrinsics and such).
+/// * `fn_def_id` - the `DefId` of the function. If this is provided then we can
+/// determine more precisely if the function can unwind. If this is not provided
+/// then we will only infer whether the function can unwind or not based on the
+/// ABI of the function. For example, a function marked with `#[rustc_nounwind]`
+/// is known to not unwind even if it's using Rust ABI.
///
/// * `abi` - this is the ABI that the function is defined with. This is the
/// primary factor for determining whether a function can unwind or not.
@@ -1138,11 +1146,6 @@ where
/// aborts the process.
/// * This affects whether functions have the LLVM `nounwind` attribute, which
/// affects various optimizations and codegen.
-///
-/// FIXME: this is actually buggy with respect to Rust functions. Rust functions
-/// compiled with `-Cpanic=unwind` and referenced from another crate compiled
-/// with `-Cpanic=abort` will look like they can't unwind when in fact they
-/// might (from a foreign exception or similar).
#[inline]
#[tracing::instrument(level = "debug", skip(tcx))]
pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool {
@@ -1250,33 +1253,18 @@ pub enum FnAbiError<'tcx> {
AdjustForForeignAbi(call::AdjustForForeignAbiError),
}
-impl<'tcx> From<LayoutError<'tcx>> for FnAbiError<'tcx> {
- fn from(err: LayoutError<'tcx>) -> Self {
- Self::Layout(err)
- }
-}
-
-impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
- fn from(err: call::AdjustForForeignAbiError) -> Self {
- Self::AdjustForForeignAbi(err)
- }
-}
-
-impl<'tcx> fmt::Display for FnAbiError<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+impl<'a, 'b> IntoDiagnostic<'a, !> for FnAbiError<'b> {
+ fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, !> {
match self {
- Self::Layout(err) => err.fmt(f),
- Self::AdjustForForeignAbi(err) => err.fmt(f),
+ Self::Layout(e) => e.into_diagnostic().into_diagnostic(handler),
+ Self::AdjustForForeignAbi(call::AdjustForForeignAbiError::Unsupported {
+ arch,
+ abi,
+ }) => UnsupportedFnAbi { arch, abi: abi.name() }.into_diagnostic(handler),
}
}
}
-impl IntoDiagnostic<'_, !> for FnAbiError<'_> {
- fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
- handler.struct_fatal(self.to_string())
- }
-}
-
// FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
// just for error handling.
#[derive(Debug)]
@@ -1324,7 +1312,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
let tcx = self.tcx().at(span);
MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err(
- |err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
+ |err| self.handle_fn_abi_err(*err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
))
}
@@ -1351,7 +1339,11 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
// However, we don't do this early in order to avoid calling
// `def_span` unconditionally (which may have a perf penalty).
let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
- self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args })
+ self.handle_fn_abi_err(
+ *err,
+ span,
+ FnAbiRequest::OfInstance { instance, extra_args },
+ )
}),
)
}