Skip to content

Commit 7f2f927

Browse files
committed
ty::layout: propagate errors up to (but not out of) FnAbi::of_*.
1 parent 4d36faf commit 7f2f927

File tree

2 files changed

+129
-27
lines changed

2 files changed

+129
-27
lines changed

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 104 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_target::abi::call::{
1818
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
1919
};
2020
use rustc_target::abi::*;
21-
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy};
21+
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
2222

2323
use std::cmp;
2424
use std::fmt;
@@ -2015,6 +2015,12 @@ impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
20152015
}
20162016
}
20172017

2018+
impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
2019+
fn target_spec(&self) -> &Target {
2020+
&self.sess.target
2021+
}
2022+
}
2023+
20182024
impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
20192025
#[inline]
20202026
fn tcx(&self) -> TyCtxt<'tcx> {
@@ -2048,6 +2054,12 @@ impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
20482054
}
20492055
}
20502056

2057+
impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> {
2058+
fn target_spec(&self) -> &Target {
2059+
self.tcx.target_spec()
2060+
}
2061+
}
2062+
20512063
impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
20522064
fn tcx(&self) -> TyCtxt<'tcx> {
20532065
self.tcx.tcx()
@@ -2788,9 +2800,39 @@ pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
27882800
}
27892801
}
27902802

2803+
/// Error produced by attempting to compute or adjust a `FnAbi`.
2804+
enum FnAbiError<'tcx> {
2805+
/// Error produced by a `layout_of` call, while computing `FnAbi` initially.
2806+
Layout(LayoutError<'tcx>),
2807+
2808+
/// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
2809+
AdjustForForeignAbi(call::AdjustForForeignAbiError),
2810+
}
2811+
2812+
impl From<LayoutError<'tcx>> for FnAbiError<'tcx> {
2813+
fn from(err: LayoutError<'tcx>) -> Self {
2814+
Self::Layout(err)
2815+
}
2816+
}
2817+
2818+
impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
2819+
fn from(err: call::AdjustForForeignAbiError) -> Self {
2820+
Self::AdjustForForeignAbi(err)
2821+
}
2822+
}
2823+
2824+
impl<'tcx> fmt::Display for FnAbiError<'tcx> {
2825+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2826+
match self {
2827+
Self::Layout(err) => err.fmt(f),
2828+
Self::AdjustForForeignAbi(err) => err.fmt(f),
2829+
}
2830+
}
2831+
}
2832+
27912833
pub trait FnAbiExt<'tcx, C>
27922834
where
2793-
C: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec,
2835+
C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>,
27942836
{
27952837
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
27962838
///
@@ -2808,10 +2850,26 @@ where
28082850

28092851
impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
28102852
where
2811-
C: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec,
2853+
C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>,
28122854
{
28132855
fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
2814-
call::FnAbi::new_internal(cx, sig, extra_args, None, CodegenFnAttrFlags::empty(), false)
2856+
call::FnAbi::new_internal(
2857+
&LayoutCx { tcx: cx.tcx(), param_env: cx.param_env() },
2858+
sig,
2859+
extra_args,
2860+
None,
2861+
CodegenFnAttrFlags::empty(),
2862+
false,
2863+
)
2864+
.unwrap_or_else(|err| {
2865+
// FIXME(eddyb) get a better `span` here.
2866+
let span = DUMMY_SP;
2867+
if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
2868+
cx.tcx().sess.span_fatal(span, &err.to_string())
2869+
} else {
2870+
span_bug!(span, "`FnAbi::of_fn_ptr({}, {:?})` failed: {}", sig, extra_args, err);
2871+
}
2872+
})
28152873
}
28162874

28172875
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
@@ -2826,35 +2884,57 @@ where
28262884
let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()).flags;
28272885

28282886
call::FnAbi::new_internal(
2829-
cx,
2887+
&LayoutCx { tcx: cx.tcx(), param_env: cx.param_env() },
28302888
sig,
28312889
extra_args,
28322890
caller_location,
28332891
attrs,
28342892
matches!(instance.def, ty::InstanceDef::Virtual(..)),
28352893
)
2894+
.unwrap_or_else(|err| {
2895+
// FIXME(eddyb) get a better `span` here.
2896+
let span = cx.tcx().def_span(instance.def_id());
2897+
if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
2898+
cx.tcx().sess.span_fatal(span, &err.to_string())
2899+
} else {
2900+
span_bug!(
2901+
span,
2902+
"`FnAbi::of_instance({}, {:?})` failed: {}",
2903+
instance,
2904+
extra_args,
2905+
err
2906+
);
2907+
}
2908+
})
28362909
}
28372910
}
28382911

28392912
/// Implementation detail of computing `FnAbi`s, shouldn't be exported.
2840-
trait FnAbiInternalExt<'tcx, C>
2913+
// FIXME(eddyb) move this off of being generic on `C: LayoutOf`, and
2914+
// explicitly take `LayoutCx` *or* `TyCtxt` and `ParamEnvAnd<...>`.
2915+
trait FnAbiInternalExt<'tcx, C>: Sized
28412916
where
2842-
C: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec,
2917+
C: LayoutOf<'tcx, LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>>
2918+
+ HasTargetSpec,
28432919
{
2920+
// FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
2921+
// arguments of this method, into a separate `struct`.
28442922
fn new_internal(
28452923
cx: &C,
28462924
sig: ty::PolyFnSig<'tcx>,
28472925
extra_args: &[Ty<'tcx>],
28482926
caller_location: Option<Ty<'tcx>>,
28492927
codegen_fn_attr_flags: CodegenFnAttrFlags,
2928+
// FIXME(eddyb) replace this with something typed, like an `enum`.
28502929
make_self_ptr_thin: bool,
2851-
) -> Self;
2852-
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
2930+
) -> Result<Self, FnAbiError<'tcx>>;
2931+
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) -> Result<(), FnAbiError<'tcx>>;
28532932
}
28542933

28552934
impl<'tcx, C> FnAbiInternalExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
28562935
where
2857-
C: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec,
2936+
C: LayoutOf<'tcx, LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>>
2937+
+ HasTargetSpec,
28582938
{
28592939
fn new_internal(
28602940
cx: &C,
@@ -2863,10 +2943,10 @@ where
28632943
caller_location: Option<Ty<'tcx>>,
28642944
codegen_fn_attr_flags: CodegenFnAttrFlags,
28652945
force_thin_self_ptr: bool,
2866-
) -> Self {
2946+
) -> Result<Self, FnAbiError<'tcx>> {
28672947
debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
28682948

2869-
let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
2949+
let sig = cx.tcx().normalize_erasing_late_bound_regions(cx.param_env(), sig);
28702950

28712951
let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
28722952

@@ -2972,10 +3052,10 @@ where
29723052
}
29733053
};
29743054

2975-
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
3055+
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
29763056
let is_return = arg_idx.is_none();
29773057

2978-
let layout = cx.layout_of(ty);
3058+
let layout = cx.layout_of(ty)?;
29793059
let layout = if force_thin_self_ptr && arg_idx == Some(0) {
29803060
// Don't pass the vtable, it's not an argument of the virtual fn.
29813061
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
@@ -3006,32 +3086,32 @@ where
30063086
}
30073087
}
30083088

3009-
arg
3089+
Ok(arg)
30103090
};
30113091

30123092
let mut fn_abi = FnAbi {
3013-
ret: arg_of(sig.output(), None),
3093+
ret: arg_of(sig.output(), None)?,
30143094
args: inputs
30153095
.iter()
30163096
.cloned()
30173097
.chain(extra_args)
30183098
.chain(caller_location)
30193099
.enumerate()
30203100
.map(|(i, ty)| arg_of(ty, Some(i)))
3021-
.collect(),
3101+
.collect::<Result<_, _>>()?,
30223102
c_variadic: sig.c_variadic,
30233103
fixed_count: inputs.len(),
30243104
conv,
30253105
can_unwind: fn_can_unwind(cx.tcx(), codegen_fn_attr_flags, sig.abi),
30263106
};
3027-
fn_abi.adjust_for_abi(cx, sig.abi);
3107+
fn_abi.adjust_for_abi(cx, sig.abi)?;
30283108
debug!("FnAbi::new_internal = {:?}", fn_abi);
3029-
fn_abi
3109+
Ok(fn_abi)
30303110
}
30313111

3032-
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) {
3112+
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) -> Result<(), FnAbiError<'tcx>> {
30333113
if abi == SpecAbi::Unadjusted {
3034-
return;
3114+
return Ok(());
30353115
}
30363116

30373117
if abi == SpecAbi::Rust
@@ -3095,12 +3175,11 @@ where
30953175
for arg in &mut self.args {
30963176
fixup(arg);
30973177
}
3098-
return;
3178+
} else {
3179+
self.adjust_for_foreign_abi(cx, abi)?;
30993180
}
31003181

3101-
if let Err(msg) = self.adjust_for_foreign_abi(cx, abi) {
3102-
cx.tcx().sess.fatal(&msg);
3103-
}
3182+
Ok(())
31043183
}
31053184
}
31063185

compiler/rustc_target/src/abi/call/mod.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::abi::{self, Abi, Align, FieldsShape, Size};
22
use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
33
use crate::spec::{self, HasTargetSpec};
4+
use std::fmt;
45

56
mod aarch64;
67
mod amdgpu;
@@ -599,8 +600,28 @@ pub struct FnAbi<'a, Ty> {
599600
pub can_unwind: bool,
600601
}
601602

603+
/// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
604+
pub enum AdjustForForeignAbiError {
605+
/// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs.
606+
Unsupported { arch: String, abi: spec::abi::Abi },
607+
}
608+
609+
impl fmt::Display for AdjustForForeignAbiError {
610+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
611+
match self {
612+
Self::Unsupported { arch, abi } => {
613+
write!(f, "target architecture {:?} does not support `extern {}` ABI", arch, abi)
614+
}
615+
}
616+
}
617+
}
618+
602619
impl<'a, Ty> FnAbi<'a, Ty> {
603-
pub fn adjust_for_foreign_abi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(), String>
620+
pub fn adjust_for_foreign_abi<C>(
621+
&mut self,
622+
cx: &C,
623+
abi: spec::abi::Abi,
624+
) -> Result<(), AdjustForForeignAbiError>
604625
where
605626
Ty: TyAbiInterface<'a, C> + Copy,
606627
C: HasDataLayout + HasTargetSpec,
@@ -655,7 +676,9 @@ impl<'a, Ty> FnAbi<'a, Ty> {
655676
}
656677
"asmjs" => wasm::compute_c_abi_info(cx, self),
657678
"bpf" => bpf::compute_abi_info(self),
658-
a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
679+
arch => {
680+
return Err(AdjustForForeignAbiError::Unsupported { arch: arch.to_string(), abi });
681+
}
659682
}
660683

661684
Ok(())

0 commit comments

Comments
 (0)