Skip to content

Commit bc9bfc7

Browse files
committed
Implement ffi_returns_twice attribute
1 parent d173180 commit bc9bfc7

File tree

13 files changed

+79
-0
lines changed

13 files changed

+79
-0
lines changed

src/librustc/hir/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2489,6 +2489,9 @@ bitflags! {
24892489
/// #[used], indicates that LLVM can't eliminate this function (but the
24902490
/// linker can!)
24912491
const USED = 1 << 9;
2492+
/// #[ffi_returns_twice], indicates that an extern function can return
2493+
/// multiple times
2494+
const FFI_RETURNS_TWICE = 1 << 10;
24922495
}
24932496
}
24942497

src/librustc_codegen_llvm/attributes.rs

+3
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ pub fn from_fn_attrs(
223223
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
224224
Attribute::Cold.apply_llfn(Function, llfn);
225225
}
226+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) {
227+
Attribute::ReturnsTwice.apply_llfn(Function, llfn);
228+
}
226229
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
227230
naked(llfn, true);
228231
}

src/librustc_codegen_llvm/llvm/ffi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ pub enum Attribute {
116116
SanitizeMemory = 22,
117117
NonLazyBind = 23,
118118
OptimizeNone = 24,
119+
ReturnsTwice = 25,
119120
}
120121

121122
/// LLVMIntPredicate

src/librustc_typeck/collect.rs

+12
Original file line numberDiff line numberDiff line change
@@ -2270,6 +2270,18 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
22702270
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
22712271
} else if attr.check_name("unwind") {
22722272
codegen_fn_attrs.flags |= CodegenFnAttrFlags::UNWIND;
2273+
} else if attr.check_name("ffi_returns_twice") {
2274+
if tcx.is_foreign_item(id) {
2275+
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
2276+
} else {
2277+
// `#[ffi_returns_twice]` is only allowed `extern fn`s
2278+
struct_span_err!(
2279+
tcx.sess,
2280+
attr.span,
2281+
E0723,
2282+
"`#[ffi_returns_twice]` may only be used on `extern fn`s"
2283+
).emit();
2284+
}
22732285
} else if attr.check_name("rustc_allocator_nounwind") {
22742286
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND;
22752287
} else if attr.check_name("naked") {

src/librustc_typeck/diagnostics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4720,4 +4720,5 @@ register_diagnostics! {
47204720
E0698, // type inside generator must be known in this context
47214721
E0719, // duplicate values for associated type binding
47224722
E0722, // Malformed #[optimize] attribute
4723+
E0723, // `#[ffi_returns_twice]` is only allowed in `extern fn`
47234724
}

src/libsyntax/feature_gate.rs

+8
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,9 @@ declare_features! (
290290
// The `repr(i128)` annotation for enums.
291291
(active, repr128, "1.16.0", Some(35118), None),
292292

293+
// Allows the use of `#[ffi_returns_twice]` on extern functions.
294+
(active, ffi_returns_twice, "1.34.0", Some(58314), None),
295+
293296
// The `unadjusted` ABI; perma-unstable.
294297
//
295298
// rustc internal
@@ -1124,6 +1127,11 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
11241127
"the `#[naked]` attribute \
11251128
is an experimental feature",
11261129
cfg_fn!(naked_functions))),
1130+
("ffi_returns_twice", Whitelisted, template!(Word), Gated(Stability::Unstable,
1131+
"ffi_returns_twice",
1132+
"the `#[ffi_returns_twice]` attribute \
1133+
is an experimental feature",
1134+
cfg_fn!(ffi_returns_twice))),
11271135
("target_feature", Whitelisted, template!(List: r#"enable = "name""#), Ungated),
11281136
("export_name", Whitelisted, template!(NameValueStr: "name"), Ungated),
11291137
("inline", Whitelisted, template!(Word, List: "always|never"), Ungated),

src/rustllvm/RustWrapper.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
190190
return Attribute::NonLazyBind;
191191
case OptimizeNone:
192192
return Attribute::OptimizeNone;
193+
case ReturnsTwice:
194+
return Attribute::ReturnsTwice;
193195
}
194196
report_fatal_error("bad AttributeKind");
195197
}

src/rustllvm/rustllvm.h

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ enum LLVMRustAttribute {
8585
SanitizeMemory = 22,
8686
NonLazyBind = 23,
8787
OptimizeNone = 24,
88+
ReturnsTwice = 25,
8889
};
8990

9091
typedef struct OpaqueRustString *RustStringRef;

src/test/codegen/ffi-returns-twice.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// compile-flags: -C no-prepopulate-passes
2+
#![crate_type = "lib"]
3+
#![feature(ffi_returns_twice)]
4+
5+
extern {
6+
// CHECK-LABEL: @foo()
7+
// CHECK: attributes #1 = { {{.*}}returns_twice{{.*}} }
8+
#[no_mangle]
9+
#[ffi_returns_twice]
10+
pub fn foo();
11+
}
12+
13+
pub fn bar() {
14+
unsafe { foo() }
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// ignore-tidy-linelength
2+
#![crate_type = "lib"]
3+
4+
extern {
5+
#[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature (see issue #58314)
6+
pub fn foo();
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0658]: the `#[ffi_returns_twice]` attribute is an experimental feature (see issue #58314)
2+
--> $DIR/feature-gate-ffi_returns_twice.rs:5:5
3+
|
4+
LL | #[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature (see issue #58314)
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= help: add #![feature(ffi_returns_twice)] to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0658`.

src/test/ui/ffi_returns_twice.rs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// ignore-tidy-linelength
2+
#![feature(ffi_returns_twice)]
3+
#![crate_type = "lib"]
4+
5+
#[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on `extern fn`s
6+
pub fn foo() {}

src/test/ui/ffi_returns_twice.stderr

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0723]: `#[ffi_returns_twice]` may only be used on `extern fn`s
2+
--> $DIR/ffi_returns_twice.rs:5:1
3+
|
4+
LL | #[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on `extern fn`s
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0723`.

0 commit comments

Comments
 (0)