Skip to content

Commit 7c182eb

Browse files
authored
Rollup merge of rust-lang#76570 - katie-martin-fastly:implement-rfc-2945-c-unwind-abi, r=Amanieu
Implement RFC 2945: "C-unwind" ABI ## Implement RFC 2945: "C-unwind" ABI This branch implements [RFC 2945]. The tracking issue for this RFC is rust-lang#74990. The feature gate for the issue is `#![feature(c_unwind)]`. This RFC was created as part of the ffi-unwind project group tracked at rust-lang/lang-team#19. ### Changes Further details will be provided in commit messages, but a high-level overview of the changes follows: * 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]. * 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. * We adjust the `rustc_middle::ty::layout::fn_can_unwind` function, used to compute whether or not a `FnAbi` object represents a function that should be able to unwind when `panic=unwind` is in use. * Changes are also made to `rustc_mir_build::build::should_abort_on_panic` so that the function ABI is used to determind whether it should abort, assuming that the `panic=unwind` strategy is being used, and no explicit unwind attribute was provided. [RFC 2945]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
2 parents 643a79a + 5d75cde commit 7c182eb

File tree

48 files changed

+672
-80
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+672
-80
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

+38-16
Original file line numberDiff line numberDiff line change
@@ -2546,6 +2546,7 @@ fn fn_can_unwind(
25462546
panic_strategy: PanicStrategy,
25472547
codegen_fn_attr_flags: CodegenFnAttrFlags,
25482548
call_conv: Conv,
2549+
abi: SpecAbi,
25492550
) -> bool {
25502551
if panic_strategy != PanicStrategy::Unwind {
25512552
// In panic=abort mode we assume nothing can unwind anywhere, so
@@ -2570,17 +2571,33 @@ fn fn_can_unwind(
25702571
//
25712572
// 2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`).
25722573
//
2573-
// Foreign items (case 1) are assumed to not unwind; it is
2574-
// UB otherwise. (At least for now; see also
2575-
// rust-lang/rust#63909 and Rust RFC 2753.)
2576-
//
2577-
// Items defined in Rust with non-Rust ABIs (case 2) are also
2578-
// not supposed to unwind. Whether this should be enforced
2579-
// (versus stating it is UB) and *how* it would be enforced
2580-
// is currently under discussion; see rust-lang/rust#58794.
2581-
//
2582-
// In either case, we mark item as explicitly nounwind.
2583-
false
2574+
// In both of these cases, we should refer to the ABI to determine whether or not we
2575+
// should unwind. See Rust RFC 2945 for more information on this behavior, here:
2576+
// https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
2577+
use SpecAbi::*;
2578+
match abi {
2579+
C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => {
2580+
unwind
2581+
}
2582+
Cdecl
2583+
| Fastcall
2584+
| Vectorcall
2585+
| Aapcs
2586+
| Win64
2587+
| SysV64
2588+
| PtxKernel
2589+
| Msp430Interrupt
2590+
| X86Interrupt
2591+
| AmdGpuKernel
2592+
| EfiApi
2593+
| AvrInterrupt
2594+
| AvrNonBlockingInterrupt
2595+
| RustIntrinsic
2596+
| PlatformIntrinsic
2597+
| Unadjusted => false,
2598+
// In the `if` above, we checked for functions with the Rust calling convention.
2599+
Rust | RustCall => unreachable!(),
2600+
}
25842601
}
25852602
}
25862603
}
@@ -2638,14 +2655,14 @@ where
26382655
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
26392656

26402657
// It's the ABI's job to select this, not ours.
2641-
System => bug!("system abi should be selected elsewhere"),
2658+
System { .. } => bug!("system abi should be selected elsewhere"),
26422659
EfiApi => bug!("eficall abi should be selected elsewhere"),
26432660

2644-
Stdcall => Conv::X86Stdcall,
2661+
Stdcall { .. } => Conv::X86Stdcall,
26452662
Fastcall => Conv::X86Fastcall,
26462663
Vectorcall => Conv::X86VectorCall,
2647-
Thiscall => Conv::X86ThisCall,
2648-
C => Conv::C,
2664+
Thiscall { .. } => Conv::X86ThisCall,
2665+
C { .. } => Conv::C,
26492666
Unadjusted => Conv::C,
26502667
Win64 => Conv::X86_64Win64,
26512668
SysV64 => Conv::X86_64SysV,
@@ -2806,7 +2823,12 @@ where
28062823
c_variadic: sig.c_variadic,
28072824
fixed_count: inputs.len(),
28082825
conv,
2809-
can_unwind: fn_can_unwind(cx.tcx().sess.panic_strategy(), codegen_fn_attr_flags, conv),
2826+
can_unwind: fn_can_unwind(
2827+
cx.tcx().sess.panic_strategy(),
2828+
codegen_fn_attr_flags,
2829+
conv,
2830+
sig.abi,
2831+
),
28102832
};
28112833
fn_abi.adjust_for_abi(cx, sig.abi);
28122834
debug!("FnAbi::new_internal = {:?}", fn_abi);

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_mir_build/src/build/mod.rs

+33-4
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ macro_rules! unpack {
546546
}};
547547
}
548548

549-
fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, _abi: Abi) -> bool {
549+
fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, abi: Abi) -> bool {
550550
// Validate `#[unwind]` syntax regardless of platform-specific panic strategy.
551551
let attrs = &tcx.get_attrs(fn_def_id.to_def_id());
552552
let unwind_attr = attr::find_unwind_attr(&tcx.sess, attrs);
@@ -556,12 +556,41 @@ fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, _abi: Abi) -> b
556556
return false;
557557
}
558558

559-
// This is a special case: some functions have a C abi but are meant to
560-
// unwind anyway. Don't stop them.
561559
match unwind_attr {
562-
None => false, // FIXME(#58794); should be `!(abi == Abi::Rust || abi == Abi::RustCall)`
560+
// If an `#[unwind]` attribute was found, we should adhere to it.
563561
Some(UnwindAttr::Allowed) => false,
564562
Some(UnwindAttr::Aborts) => true,
563+
// If no attribute was found and the panic strategy is `unwind`, then we should examine
564+
// the function's ABI string to determine whether it should abort upon panic.
565+
None => {
566+
use Abi::*;
567+
match abi {
568+
// In the case of ABI's that have an `-unwind` equivalent, check whether the ABI
569+
// permits unwinding. If so, we should not abort. Otherwise, we should.
570+
C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => {
571+
!unwind
572+
}
573+
// Rust and `rust-call` functions are allowed to unwind, and should not abort.
574+
Rust | RustCall => false,
575+
// Other ABI's should abort.
576+
Cdecl
577+
| Fastcall
578+
| Vectorcall
579+
| Aapcs
580+
| Win64
581+
| SysV64
582+
| PtxKernel
583+
| Msp430Interrupt
584+
| X86Interrupt
585+
| AmdGpuKernel
586+
| EfiApi
587+
| AvrInterrupt
588+
| AvrNonBlockingInterrupt
589+
| RustIntrinsic
590+
| PlatformIntrinsic
591+
| Unadjusted => true,
592+
}
593+
}
565594
}
566595
}
567596

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
@@ -440,7 +440,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
440440
}
441441
match sig.abi {
442442
Abi::Rust => {}
443-
Abi::C => cx.push("KC"),
443+
Abi::C { unwind: false } => cx.push("KC"),
444444
abi => {
445445
cx.push("K");
446446
let name = abi.name();

0 commit comments

Comments
 (0)