ty::layout: propagate errors up to (but not out of) FnAbi::of_*.

This commit is contained in:
Eduard-Mihai Burtescu 2021-08-26 19:01:55 +03:00
parent 4d36faf9ef
commit 7f2f927eb8
2 changed files with 129 additions and 27 deletions

View file

@ -18,7 +18,7 @@ use rustc_target::abi::call::{
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
};
use rustc_target::abi::*;
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy};
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
use std::cmp;
use std::fmt;
@ -2015,6 +2015,12 @@ impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
}
}
impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
fn target_spec(&self) -> &Target {
&self.sess.target
}
}
impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
#[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
@ -2048,6 +2054,12 @@ impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
}
}
impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> {
fn target_spec(&self) -> &Target {
self.tcx.target_spec()
}
}
impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx.tcx()
@ -2788,9 +2800,39 @@ pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
}
}
/// Error produced by attempting to compute or adjust a `FnAbi`.
enum FnAbiError<'tcx> {
/// Error produced by a `layout_of` call, while computing `FnAbi` initially.
Layout(LayoutError<'tcx>),
/// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
AdjustForForeignAbi(call::AdjustForForeignAbiError),
}
impl 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 {
match self {
Self::Layout(err) => err.fmt(f),
Self::AdjustForForeignAbi(err) => err.fmt(f),
}
}
}
pub trait FnAbiExt<'tcx, C>
where
C: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec,
C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>,
{
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
///
@ -2808,10 +2850,26 @@ where
impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
where
C: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec,
C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>,
{
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)
call::FnAbi::new_internal(
&LayoutCx { tcx: cx.tcx(), param_env: cx.param_env() },
sig,
extra_args,
None,
CodegenFnAttrFlags::empty(),
false,
)
.unwrap_or_else(|err| {
// FIXME(eddyb) get a better `span` here.
let span = DUMMY_SP;
if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
cx.tcx().sess.span_fatal(span, &err.to_string())
} else {
span_bug!(span, "`FnAbi::of_fn_ptr({}, {:?})` failed: {}", sig, extra_args, err);
}
})
}
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
@ -2826,35 +2884,57 @@ where
let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()).flags;
call::FnAbi::new_internal(
cx,
&LayoutCx { tcx: cx.tcx(), param_env: cx.param_env() },
sig,
extra_args,
caller_location,
attrs,
matches!(instance.def, ty::InstanceDef::Virtual(..)),
)
.unwrap_or_else(|err| {
// FIXME(eddyb) get a better `span` here.
let span = cx.tcx().def_span(instance.def_id());
if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
cx.tcx().sess.span_fatal(span, &err.to_string())
} else {
span_bug!(
span,
"`FnAbi::of_instance({}, {:?})` failed: {}",
instance,
extra_args,
err
);
}
})
}
}
/// Implementation detail of computing `FnAbi`s, shouldn't be exported.
trait FnAbiInternalExt<'tcx, C>
// FIXME(eddyb) move this off of being generic on `C: LayoutOf`, and
// explicitly take `LayoutCx` *or* `TyCtxt` and `ParamEnvAnd<...>`.
trait FnAbiInternalExt<'tcx, C>: Sized
where
C: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec,
C: LayoutOf<'tcx, LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>>
+ HasTargetSpec,
{
// FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
// arguments of this method, into a separate `struct`.
fn new_internal(
cx: &C,
sig: ty::PolyFnSig<'tcx>,
extra_args: &[Ty<'tcx>],
caller_location: Option<Ty<'tcx>>,
codegen_fn_attr_flags: CodegenFnAttrFlags,
// FIXME(eddyb) replace this with something typed, like an `enum`.
make_self_ptr_thin: bool,
) -> Self;
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
) -> Result<Self, FnAbiError<'tcx>>;
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) -> Result<(), FnAbiError<'tcx>>;
}
impl<'tcx, C> FnAbiInternalExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
where
C: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec,
C: LayoutOf<'tcx, LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>>
+ HasTargetSpec,
{
fn new_internal(
cx: &C,
@ -2863,10 +2943,10 @@ where
caller_location: Option<Ty<'tcx>>,
codegen_fn_attr_flags: CodegenFnAttrFlags,
force_thin_self_ptr: bool,
) -> Self {
) -> Result<Self, FnAbiError<'tcx>> {
debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
let sig = cx.tcx().normalize_erasing_late_bound_regions(cx.param_env(), sig);
let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
@ -2972,10 +3052,10 @@ where
}
};
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
let is_return = arg_idx.is_none();
let layout = cx.layout_of(ty);
let layout = cx.layout_of(ty)?;
let layout = if force_thin_self_ptr && arg_idx == Some(0) {
// Don't pass the vtable, it's not an argument of the virtual fn.
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
@ -3006,11 +3086,11 @@ where
}
}
arg
Ok(arg)
};
let mut fn_abi = FnAbi {
ret: arg_of(sig.output(), None),
ret: arg_of(sig.output(), None)?,
args: inputs
.iter()
.cloned()
@ -3018,20 +3098,20 @@ where
.chain(caller_location)
.enumerate()
.map(|(i, ty)| arg_of(ty, Some(i)))
.collect(),
.collect::<Result<_, _>>()?,
c_variadic: sig.c_variadic,
fixed_count: inputs.len(),
conv,
can_unwind: fn_can_unwind(cx.tcx(), codegen_fn_attr_flags, sig.abi),
};
fn_abi.adjust_for_abi(cx, sig.abi);
fn_abi.adjust_for_abi(cx, sig.abi)?;
debug!("FnAbi::new_internal = {:?}", fn_abi);
fn_abi
Ok(fn_abi)
}
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) {
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) -> Result<(), FnAbiError<'tcx>> {
if abi == SpecAbi::Unadjusted {
return;
return Ok(());
}
if abi == SpecAbi::Rust
@ -3095,12 +3175,11 @@ where
for arg in &mut self.args {
fixup(arg);
}
return;
} else {
self.adjust_for_foreign_abi(cx, abi)?;
}
if let Err(msg) = self.adjust_for_foreign_abi(cx, abi) {
cx.tcx().sess.fatal(&msg);
}
Ok(())
}
}

View file

@ -1,6 +1,7 @@
use crate::abi::{self, Abi, Align, FieldsShape, Size};
use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
use crate::spec::{self, HasTargetSpec};
use std::fmt;
mod aarch64;
mod amdgpu;
@ -599,8 +600,28 @@ pub struct FnAbi<'a, Ty> {
pub can_unwind: bool,
}
/// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
pub enum AdjustForForeignAbiError {
/// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs.
Unsupported { arch: String, abi: spec::abi::Abi },
}
impl fmt::Display for AdjustForForeignAbiError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unsupported { arch, abi } => {
write!(f, "target architecture {:?} does not support `extern {}` ABI", arch, abi)
}
}
}
}
impl<'a, Ty> FnAbi<'a, Ty> {
pub fn adjust_for_foreign_abi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(), String>
pub fn adjust_for_foreign_abi<C>(
&mut self,
cx: &C,
abi: spec::abi::Abi,
) -> Result<(), AdjustForForeignAbiError>
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec,
@ -655,7 +676,9 @@ impl<'a, Ty> FnAbi<'a, Ty> {
}
"asmjs" => wasm::compute_c_abi_info(cx, self),
"bpf" => bpf::compute_abi_info(self),
a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
arch => {
return Err(AdjustForForeignAbiError::Unsupported { arch: arch.to_string(), abi });
}
}
Ok(())