Skip to content

Commit d9bee1c

Browse files
author
katelyn a. martin
committed
rustc_target: add "unwind" payloads to Abi
### Overview This commit begins the implementation work for RFC 2945. For more information, see the rendered RFC [1] and tracking issue [2]. A boolean `unwind` payload is added to the `C`, `System`, `Stdcall`, and `Thiscall` variants, marking whether unwinding across FFI boundaries is acceptable. The cases where each of these variants' `unwind` member is true correspond with the `C-unwind`, `system-unwind`, `stdcall-unwind`, and `thiscall-unwind` ABI strings introduced in RFC 2945 [3]. ### Feature Gate and Unstable Book This commit adds a `c_unwind` feature gate for the new ABI strings. Tests for this feature gate are included in `src/test/ui/c-unwind/`, which ensure that this feature gate works correctly for each of the new ABIs. A new language features entry in the unstable book is added as well. ### Further Work To Be Done This commit does not proceed to implement the new unwinding ABIs, and is intentionally scoped specifically to *defining* the ABIs and their feature flag. ### One Note on Test Churn This will lead to some test churn, in re-blessing hash tests, as the deleted comment in `src/librustc_target/spec/abi.rs` mentioned, because we can no longer guarantee the ordering of the `Abi` variants. While this is a downside, this decision was made bearing in mind that RFC 2945 states the following, in the "Other `unwind` Strings" section [3]: > More unwind variants of existing ABI strings may be introduced, > with the same semantics, without an additional RFC. Adding a new variant for each of these cases, rather than specifying a payload for a given ABI, would quickly become untenable, and make working with the `Abi` enum prone to mistakes. This approach encodes the unwinding information *into* a given ABI, to account for the future possibility of other `-unwind` ABI strings. ### Footnotes [1]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md [2]: rust-lang#74990 [3]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md#other-unwind-abi-strings
1 parent d1aed50 commit d9bee1c

File tree

29 files changed

+270
-60
lines changed

29 files changed

+270
-60
lines changed

compiler/rustc_ast_lowering/src/item.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -319,10 +319,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
319319
ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)),
320320
ItemKind::ForeignMod(ref fm) => {
321321
if fm.abi.is_none() {
322-
self.maybe_lint_missing_abi(span, id, abi::Abi::C);
322+
self.maybe_lint_missing_abi(span, id, abi::Abi::C { unwind: false });
323323
}
324324
hir::ItemKind::ForeignMod {
325-
abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)),
325+
abi: fm.abi.map_or(abi::Abi::C { unwind: false }, |abi| self.lower_abi(abi)),
326326
items: self
327327
.arena
328328
.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
@@ -1315,8 +1315,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
13151315
match ext {
13161316
Extern::None => abi::Abi::Rust,
13171317
Extern::Implicit => {
1318-
self.maybe_lint_missing_abi(span, id, abi::Abi::C);
1319-
abi::Abi::C
1318+
self.maybe_lint_missing_abi(span, id, abi::Abi::C { unwind: false });
1319+
abi::Abi::C { unwind: false }
13201320
}
13211321
Extern::Explicit(abi) => self.lower_abi(abi),
13221322
}

compiler/rustc_ast_passes/src/feature_gate.rs

+33
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,39 @@ impl<'a> PostExpansionVisitor<'a> {
156156
"efiapi ABI is experimental and subject to change"
157157
);
158158
}
159+
// FFI Unwinding ABI's
160+
"C-unwind" => {
161+
gate_feature_post!(
162+
&self,
163+
c_unwind,
164+
span,
165+
"C-unwind ABI is experimental and subject to change"
166+
);
167+
}
168+
"stdcall-unwind" => {
169+
gate_feature_post!(
170+
&self,
171+
c_unwind,
172+
span,
173+
"stdcall-unwind ABI is experimental and subject to change"
174+
);
175+
}
176+
"system-unwind" => {
177+
gate_feature_post!(
178+
&self,
179+
c_unwind,
180+
span,
181+
"system-unwind ABI is experimental and subject to change"
182+
);
183+
}
184+
"thiscall-unwind" => {
185+
gate_feature_post!(
186+
&self,
187+
c_unwind,
188+
span,
189+
"thiscall-unwind ABI is experimental and subject to change"
190+
);
191+
}
159192
abi => self
160193
.sess
161194
.parse_sess

compiler/rustc_codegen_cranelift/src/abi/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ fn clif_sig_from_fn_sig<'tcx>(
101101
requires_caller_location: bool,
102102
) -> Signature {
103103
let abi = match sig.abi {
104-
Abi::System => Abi::C,
104+
Abi::System { unwind: false } => Abi::C { unwind: false },
105105
abi => abi,
106106
};
107107
let (call_conv, inputs, output): (CallConv, Vec<Ty<'tcx>>, Ty<'tcx>) = match abi {
@@ -110,7 +110,7 @@ fn clif_sig_from_fn_sig<'tcx>(
110110
sig.inputs().to_vec(),
111111
sig.output(),
112112
),
113-
Abi::C | Abi::Unadjusted => (
113+
Abi::C { unwind: false } | Abi::Unadjusted => (
114114
CallConv::triple_default(triple),
115115
sig.inputs().to_vec(),
116116
sig.output(),
@@ -126,7 +126,7 @@ fn clif_sig_from_fn_sig<'tcx>(
126126
inputs.extend(extra_args.types());
127127
(CallConv::triple_default(triple), inputs, sig.output())
128128
}
129-
Abi::System => unreachable!(),
129+
Abi::System { .. } => unreachable!(),
130130
Abi::RustIntrinsic => (
131131
CallConv::triple_default(triple),
132132
sig.inputs().to_vec(),
@@ -664,7 +664,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
664664

665665
// FIXME find a cleaner way to support varargs
666666
if fn_sig.c_variadic {
667-
if fn_sig.abi != Abi::C {
667+
if !matches!(fn_sig.abi, Abi::C { .. }) {
668668
fx.tcx.sess.span_fatal(
669669
span,
670670
&format!("Variadic call for non-C abi {:?}", fn_sig.abi),

compiler/rustc_feature/src/active.rs

+4
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,10 @@ declare_features! (
631631

632632
/// Allows using `pointer` and `reference` in intra-doc links
633633
(active, intra_doc_pointers, "1.51.0", Some(80896), None),
634+
635+
/// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries.
636+
(active, c_unwind, "1.51.0", Some(74990), None),
637+
634638
// -------------------------------------------------------------------------
635639
// feature-group-end: actual feature gates
636640
// -------------------------------------------------------------------------

compiler/rustc_middle/src/ty/layout.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -2615,14 +2615,14 @@ where
26152615
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
26162616

26172617
// It's the ABI's job to select this, not ours.
2618-
System => bug!("system abi should be selected elsewhere"),
2618+
System { .. } => bug!("system abi should be selected elsewhere"),
26192619
EfiApi => bug!("eficall abi should be selected elsewhere"),
26202620

2621-
Stdcall => Conv::X86Stdcall,
2621+
Stdcall { .. } => Conv::X86Stdcall,
26222622
Fastcall => Conv::X86Fastcall,
26232623
Vectorcall => Conv::X86VectorCall,
2624-
Thiscall => Conv::X86ThisCall,
2625-
C => Conv::C,
2624+
Thiscall { .. } => Conv::X86ThisCall,
2625+
C { .. } => Conv::C,
26262626
Unadjusted => Conv::C,
26272627
Win64 => Conv::X86_64Win64,
26282628
SysV64 => Conv::X86_64SysV,

compiler/rustc_mir/src/interpret/terminator.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
244244
};
245245
if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
246246
throw_ub_format!(
247-
"calling a function with ABI {:?} using caller ABI {:?}",
248-
callee_abi,
249-
caller_abi
247+
"calling a function with ABI {} using caller ABI {}",
248+
callee_abi.name(),
249+
caller_abi.name()
250250
)
251251
}
252252
}

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ symbols! {
315315
bridge,
316316
bswap,
317317
c_str,
318+
c_unwind,
318319
c_variadic,
319320
call,
320321
call_mut,

compiler/rustc_symbol_mangling/src/v0.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
441441
}
442442
match sig.abi {
443443
Abi::Rust => {}
444-
Abi::C => cx.push("KC"),
444+
Abi::C { unwind: false } => cx.push("KC"),
445445
abi => {
446446
cx.push("K");
447447
let name = abi.name();

compiler/rustc_target/src/spec/abi.rs

+50-19
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,16 @@ mod tests;
88
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
99
#[derive(HashStable_Generic, Encodable, Decodable)]
1010
pub enum Abi {
11-
// N.B., this ordering MUST match the AbiDatas array below.
12-
// (This is ensured by the test indices_are_correct().)
13-
1411
// Multiplatform / generic ABIs
15-
//
16-
// These ABIs come first because every time we add a new ABI, we
17-
// have to re-bless all the hashing tests. These are used in many
18-
// places, so giving them stable values reduces test churn. The
19-
// specific values are meaningless.
20-
Rust = 0,
21-
C = 1,
12+
Rust,
13+
C { unwind: bool },
2214

2315
// Single platform ABIs
2416
Cdecl,
25-
Stdcall,
17+
Stdcall { unwind: bool },
2618
Fastcall,
2719
Vectorcall,
28-
Thiscall,
20+
Thiscall { unwind: bool },
2921
Aapcs,
3022
Win64,
3123
SysV64,
@@ -38,7 +30,7 @@ pub enum Abi {
3830
AvrNonBlockingInterrupt,
3931

4032
// Multiplatform / generic ABIs
41-
System,
33+
System { unwind: bool },
4234
RustIntrinsic,
4335
RustCall,
4436
PlatformIntrinsic,
@@ -60,13 +52,16 @@ pub struct AbiData {
6052
const AbiDatas: &[AbiData] = &[
6153
// Cross-platform ABIs
6254
AbiData { abi: Abi::Rust, name: "Rust", generic: true },
63-
AbiData { abi: Abi::C, name: "C", generic: true },
55+
AbiData { abi: Abi::C { unwind: false }, name: "C", generic: true },
56+
AbiData { abi: Abi::C { unwind: true }, name: "C-unwind", generic: true },
6457
// Platform-specific ABIs
6558
AbiData { abi: Abi::Cdecl, name: "cdecl", generic: false },
66-
AbiData { abi: Abi::Stdcall, name: "stdcall", generic: false },
59+
AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall", generic: false },
60+
AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind", generic: false },
6761
AbiData { abi: Abi::Fastcall, name: "fastcall", generic: false },
6862
AbiData { abi: Abi::Vectorcall, name: "vectorcall", generic: false },
69-
AbiData { abi: Abi::Thiscall, name: "thiscall", generic: false },
63+
AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall", generic: false },
64+
AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind", generic: false },
7065
AbiData { abi: Abi::Aapcs, name: "aapcs", generic: false },
7166
AbiData { abi: Abi::Win64, name: "win64", generic: false },
7267
AbiData { abi: Abi::SysV64, name: "sysv64", generic: false },
@@ -82,7 +77,8 @@ const AbiDatas: &[AbiData] = &[
8277
generic: false,
8378
},
8479
// Cross-platform ABIs
85-
AbiData { abi: Abi::System, name: "system", generic: true },
80+
AbiData { abi: Abi::System { unwind: false }, name: "system", generic: true },
81+
AbiData { abi: Abi::System { unwind: true }, name: "system-unwind", generic: true },
8682
AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true },
8783
AbiData { abi: Abi::RustCall, name: "rust-call", generic: true },
8884
AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic", generic: true },
@@ -101,7 +97,40 @@ pub fn all_names() -> Vec<&'static str> {
10197
impl Abi {
10298
#[inline]
10399
pub fn index(self) -> usize {
104-
self as usize
100+
// N.B., this ordering MUST match the AbiDatas array above.
101+
// (This is ensured by the test indices_are_correct().)
102+
use Abi::*;
103+
match self {
104+
// Cross-platform ABIs
105+
Rust => 0,
106+
C { unwind: false } => 1,
107+
C { unwind: true } => 2,
108+
// Platform-specific ABIs
109+
Cdecl => 3,
110+
Stdcall { unwind: false } => 4,
111+
Stdcall { unwind: true } => 5,
112+
Fastcall => 6,
113+
Vectorcall => 7,
114+
Thiscall { unwind: false } => 8,
115+
Thiscall { unwind: true } => 9,
116+
Aapcs => 10,
117+
Win64 => 11,
118+
SysV64 => 12,
119+
PtxKernel => 13,
120+
Msp430Interrupt => 14,
121+
X86Interrupt => 15,
122+
AmdGpuKernel => 16,
123+
EfiApi => 17,
124+
AvrInterrupt => 18,
125+
AvrNonBlockingInterrupt => 19,
126+
// Cross-platform ABIs
127+
System { unwind: false } => 20,
128+
System { unwind: true } => 21,
129+
RustIntrinsic => 22,
130+
RustCall => 23,
131+
PlatformIntrinsic => 24,
132+
Unadjusted => 25,
133+
}
105134
}
106135

107136
#[inline]
@@ -120,6 +149,8 @@ impl Abi {
120149

121150
impl fmt::Display for Abi {
122151
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123-
write!(f, "\"{}\"", self.name())
152+
match self {
153+
abi => write!(f, "\"{}\"", abi.name()),
154+
}
124155
}
125156
}

compiler/rustc_target/src/spec/arm_base.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,14 @@ use crate::spec::abi::Abi;
22

33
// All the calling conventions trigger an assertion(Unsupported calling convention) in llvm on arm
44
pub fn unsupported_abis() -> Vec<Abi> {
5-
vec![Abi::Stdcall, Abi::Fastcall, Abi::Vectorcall, Abi::Thiscall, Abi::Win64, Abi::SysV64]
5+
vec![
6+
Abi::Stdcall { unwind: false },
7+
Abi::Stdcall { unwind: true },
8+
Abi::Fastcall,
9+
Abi::Vectorcall,
10+
Abi::Thiscall { unwind: false },
11+
Abi::Thiscall { unwind: true },
12+
Abi::Win64,
13+
Abi::SysV64,
14+
]
615
}

compiler/rustc_target/src/spec/mipsel_unknown_none.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ pub fn target() -> Target {
2323
panic_strategy: PanicStrategy::Abort,
2424
relocation_model: RelocModel::Static,
2525
unsupported_abis: vec![
26-
Abi::Stdcall,
26+
Abi::Stdcall { unwind: false },
27+
Abi::Stdcall { unwind: true },
2728
Abi::Fastcall,
2829
Abi::Vectorcall,
29-
Abi::Thiscall,
30+
Abi::Thiscall { unwind: false },
31+
Abi::Thiscall { unwind: true },
3032
Abi::Win64,
3133
Abi::SysV64,
3234
],

compiler/rustc_target/src/spec/mod.rs

+13-6
Original file line numberDiff line numberDiff line change
@@ -1208,24 +1208,31 @@ impl Target {
12081208
/// Given a function ABI, turn it into the correct ABI for this target.
12091209
pub fn adjust_abi(&self, abi: Abi) -> Abi {
12101210
match abi {
1211-
Abi::System => {
1211+
Abi::System { unwind } => {
12121212
if self.is_like_windows && self.arch == "x86" {
1213-
Abi::Stdcall
1213+
Abi::Stdcall { unwind }
12141214
} else {
1215-
Abi::C
1215+
Abi::C { unwind }
12161216
}
12171217
}
12181218
// These ABI kinds are ignored on non-x86 Windows targets.
12191219
// See https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
12201220
// and the individual pages for __stdcall et al.
1221-
Abi::Stdcall | Abi::Fastcall | Abi::Vectorcall | Abi::Thiscall => {
1222-
if self.is_like_windows && self.arch != "x86" { Abi::C } else { abi }
1221+
Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => {
1222+
if self.is_like_windows && self.arch != "x86" { Abi::C { unwind } } else { abi }
1223+
}
1224+
Abi::Fastcall | Abi::Vectorcall => {
1225+
if self.is_like_windows && self.arch != "x86" {
1226+
Abi::C { unwind: false }
1227+
} else {
1228+
abi
1229+
}
12231230
}
12241231
Abi::EfiApi => {
12251232
if self.arch == "x86_64" {
12261233
Abi::Win64
12271234
} else {
1228-
Abi::C
1235+
Abi::C { unwind: false }
12291236
}
12301237
}
12311238
abi => abi,

compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,12 @@ pub fn target() -> Target {
4949
// create the tests for this.
5050
unsupported_abis: vec![
5151
Abi::Cdecl,
52-
Abi::Stdcall,
52+
Abi::Stdcall { unwind: false },
53+
Abi::Stdcall { unwind: true },
5354
Abi::Fastcall,
5455
Abi::Vectorcall,
55-
Abi::Thiscall,
56+
Abi::Thiscall { unwind: false },
57+
Abi::Thiscall { unwind: true },
5658
Abi::Aapcs,
5759
Abi::Win64,
5860
Abi::SysV64,

compiler/rustc_target/src/spec/riscv_base.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ use crate::spec::abi::Abi;
55
pub fn unsupported_abis() -> Vec<Abi> {
66
vec![
77
Abi::Cdecl,
8-
Abi::Stdcall,
8+
Abi::Stdcall { unwind: false },
9+
Abi::Stdcall { unwind: true },
910
Abi::Fastcall,
1011
Abi::Vectorcall,
11-
Abi::Thiscall,
12+
Abi::Thiscall { unwind: false },
13+
Abi::Thiscall { unwind: true },
1214
Abi::Aapcs,
1315
Abi::Win64,
1416
Abi::SysV64,

compiler/rustc_typeck/src/collect.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2569,7 +2569,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
25692569
} else if tcx.sess.check_name(attr, sym::used) {
25702570
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
25712571
} else if tcx.sess.check_name(attr, sym::cmse_nonsecure_entry) {
2572-
if tcx.fn_sig(id).abi() != abi::Abi::C {
2572+
if !matches!(tcx.fn_sig(id).abi(), abi::Abi::C { .. }) {
25732573
struct_span_err!(
25742574
tcx.sess,
25752575
attr.span,

0 commit comments

Comments
 (0)