Skip to content

Commit 33af22a

Browse files
authored
Rollup merge of rust-lang#99767 - LeSeulArtichaut:stable-target-feature-11, r=estebank
Stabilize `#![feature(target_feature_11)]` ## Stabilization report ### Summary Allows for safe functions to be marked with `#[target_feature]` attributes. Functions marked with `#[target_feature]` are generally considered as unsafe functions: they are unsafe to call, cannot be assigned to safe function pointers, and don't implement the `Fn*` traits. However, calling them from other `#[target_feature]` functions with a superset of features is safe. ```rust // Demonstration function #[target_feature(enable = "avx2")] fn avx2() {} fn foo() { // Calling `avx2` here is unsafe, as we must ensure // that AVX is available first. unsafe { avx2(); } } #[target_feature(enable = "avx2")] fn bar() { // Calling `avx2` here is safe. avx2(); } ``` ### Test cases Tests for this feature can be found in [`src/test/ui/rfcs/rfc-2396-target_feature-11/`](https://github.com/rust-lang/rust/tree/b67ba9ba208ac918228a18321fc3a11a99b1c62b/src/test/ui/rfcs/rfc-2396-target_feature-11/). ### Edge cases - rust-lang#73631 Closures defined inside functions marked with `#[target_feature]` inherit the target features of their parent function. They can still be assigned to safe function pointers and implement the appropriate `Fn*` traits. ```rust #[target_feature(enable = "avx2")] fn qux() { let my_closure = || avx2(); // this call to `avx2` is safe let f: fn() = my_closure; } ``` This means that in order to call a function with `#[target_feature]`, you must show that the target-feature is available while the function executes *and* for as long as whatever may escape from that function lives. ### Documentation - Reference: rust-lang/reference#1181 --- cc tracking issue rust-lang#69098 r? ``@ghost``
2 parents 49b9cc5 + b379d21 commit 33af22a

28 files changed

+78
-151
lines changed

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

+18-29
Original file line numberDiff line numberDiff line change
@@ -224,34 +224,23 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
224224
if !tcx.is_closure(did.to_def_id())
225225
&& tcx.fn_sig(did).skip_binder().unsafety() == hir::Unsafety::Normal
226226
{
227-
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
228-
// The `#[target_feature]` attribute is allowed on
229-
// WebAssembly targets on all functions, including safe
230-
// ones. Other targets require that `#[target_feature]` is
231-
// only applied to unsafe functions (pending the
232-
// `target_feature_11` feature) because on most targets
233-
// execution of instructions that are not supported is
234-
// considered undefined behavior. For WebAssembly which is a
235-
// 100% safe target at execution time it's not possible to
236-
// execute undefined instructions, and even if a future
237-
// feature was added in some form for this it would be a
238-
// deterministic trap. There is no undefined behavior when
239-
// executing WebAssembly so `#[target_feature]` is allowed
240-
// on safe functions (but again, only for WebAssembly)
241-
//
242-
// Note that this is also allowed if `actually_rustdoc` so
243-
// if a target is documenting some wasm-specific code then
244-
// it's not spuriously denied.
245-
} else if !tcx.features().target_feature_11 {
246-
let mut err = feature_err(
247-
&tcx.sess.parse_sess,
248-
sym::target_feature_11,
249-
attr.span,
250-
"`#[target_feature(..)]` can only be applied to `unsafe` functions",
251-
);
252-
err.span_label(tcx.def_span(did), "not an `unsafe` function");
253-
err.emit();
254-
} else {
227+
// The `#[target_feature]` attribute is allowed on
228+
// WebAssembly targets on all functions, including safe
229+
// ones. Other targets have conditions on the usage of
230+
// `#[target_feature]` because on most targets
231+
// execution of instructions that are not supported is
232+
// considered undefined behavior. For WebAssembly which is a
233+
// 100% safe target at execution time it's not possible to
234+
// execute undefined instructions, and even if a future
235+
// feature was added in some form for this it would be a
236+
// deterministic trap. There is no undefined behavior when
237+
// executing WebAssembly so `#[target_feature]` is allowed
238+
// on safe functions (but again, only for WebAssembly)
239+
//
240+
// Note that this is also allowed if `actually_rustdoc` so
241+
// if a target is documenting some wasm-specific code then
242+
// it's not spuriously denied.
243+
if !(tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc) {
255244
check_target_feature_trait_unsafe(tcx, did, attr.span);
256245
}
257246
}
@@ -478,7 +467,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
478467
});
479468

480469
// #73631: closures inherit `#[target_feature]` annotations
481-
if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
470+
if tcx.is_closure(did.to_def_id()) {
482471
let owner_id = tcx.parent(did.to_def_id());
483472
if tcx.def_kind(owner_id).has_codegen_attrs() {
484473
codegen_fn_attrs

compiler/rustc_feature/src/accepted.rs

+2
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ declare_features! (
312312
(accepted, struct_variant, "1.0.0", None, None),
313313
/// Allows `#[target_feature(...)]`.
314314
(accepted, target_feature, "1.27.0", None, None),
315+
/// Allows the use of `#[target_feature]` on safe functions.
316+
(accepted, target_feature_11, "CURRENT_RUSTC_VERSION", Some(69098), None),
315317
/// Allows `fn main()` with return types which implements `Termination` (RFC 1937).
316318
(accepted, termination_trait, "1.26.0", Some(43301), None),
317319
/// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937).

compiler/rustc_feature/src/active.rs

-2
Original file line numberDiff line numberDiff line change
@@ -513,8 +513,6 @@ declare_features! (
513513
(active, strict_provenance, "1.61.0", Some(95228), None),
514514
/// Allows string patterns to dereference values to match them.
515515
(active, string_deref_patterns, "1.67.0", Some(87121), None),
516-
/// Allows the use of `#[target_feature]` on safe functions.
517-
(active, target_feature_11, "1.45.0", Some(69098), None),
518516
/// Allows using `#[thread_local]` on `static` items.
519517
(active, thread_local, "1.0.0", Some(29594), None),
520518
/// Allows defining `trait X = A + B;` alias items.

library/core/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@
229229
#![feature(simd_ffi)]
230230
#![feature(staged_api)]
231231
#![feature(stmt_expr_attributes)]
232-
#![feature(target_feature_11)]
233232
#![feature(trait_alias)]
234233
#![feature(transparent_unions)]
235234
#![feature(try_blocks)]

tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
fn inlined_no_sanitize() -> () {
55
let mut _0: (); // return place in scope 0 at $DIR/inline_compatibility.rs:+0:37: +0:37
66
let _1: (); // in scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
7-
+ scope 1 (inlined no_sanitize) { // at $DIR/inline_compatibility.rs:24:5: 24:18
7+
+ scope 1 (inlined no_sanitize) { // at $DIR/inline_compatibility.rs:23:5: 23:18
88
+ }
99

1010
bb0: {
1111
StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
1212
- _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
1313
- // mir::Constant
14-
- // + span: $DIR/inline_compatibility.rs:24:5: 24:16
14+
- // + span: $DIR/inline_compatibility.rs:23:5: 23:16
1515
- // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(<ZST>) }
1616
- }
1717
-

tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
fn inlined_target_feature() -> () {
55
let mut _0: (); // return place in scope 0 at $DIR/inline_compatibility.rs:+0:40: +0:40
66
let _1: (); // in scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
7-
+ scope 1 (inlined target_feature) { // at $DIR/inline_compatibility.rs:13:5: 13:21
7+
+ scope 1 (inlined target_feature) { // at $DIR/inline_compatibility.rs:12:5: 12:21
88
+ }
99

1010
bb0: {
1111
StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
1212
- _1 = target_feature() -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
1313
- // mir::Constant
14-
- // + span: $DIR/inline_compatibility.rs:13:5: 13:19
14+
- // + span: $DIR/inline_compatibility.rs:12:5: 12:19
1515
- // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(<ZST>) }
1616
- }
1717
-

tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:9: +1:10
1313
_1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:13: +1:52
1414
// mir::Constant
15-
// + span: $DIR/inline_compatibility.rs:42:13: 42:16
15+
// + span: $DIR/inline_compatibility.rs:41:13: 41:16
1616
// + literal: Const { ty: unsafe extern "C" fn(u32, ...) -> u32 {sum}, val: Value(<ZST>) }
1717
}
1818

tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
1010
_1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
1111
// mir::Constant
12-
// + span: $DIR/inline_compatibility.rs:29:5: 29:16
12+
// + span: $DIR/inline_compatibility.rs:28:5: 28:16
1313
// + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(<ZST>) }
1414
}
1515

tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
1010
_1 = target_feature() -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
1111
// mir::Constant
12-
// + span: $DIR/inline_compatibility.rs:18:5: 18:19
12+
// + span: $DIR/inline_compatibility.rs:17:5: 17:19
1313
// + literal: Const { ty: unsafe fn() {target_feature}, val: Value(<ZST>) }
1414
}
1515

tests/mir-opt/inline/inline_compatibility.rs

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
#![crate_type = "lib"]
66
#![feature(no_sanitize)]
7-
#![feature(target_feature_11)]
87
#![feature(c_variadic)]
98

109
// EMIT_MIR inline_compatibility.inlined_target_feature.Inline.diff

tests/ui/asm/x86_64/issue-89875.rs

-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// needs-asm-support
33
// only-x86_64
44

5-
#![feature(target_feature_11)]
6-
75
use std::arch::asm;
86

97
#[target_feature(enable = "avx")]

tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs

-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
// revisions: mir thir
1212
// [thir]compile-flags: -Z thir-unsafeck
1313

14-
#![feature(target_feature_11)]
15-
1614
#[target_feature(enable = "sse2")]
1715
const fn sse2() {}
1816

tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs

-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
// [thir]compile-flags: -Z thir-unsafeck
66
// only-x86_64
77

8-
#![feature(target_feature_11)]
9-
108
#[target_feature(enable="avx")]
119
fn also_use_avx() {
1210
println!("Hello from AVX")

tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs

-6
This file was deleted.

tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr

-14
This file was deleted.

tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0308]: mismatched types
2-
--> $DIR/fn-ptr.rs:11:21
2+
--> $DIR/fn-ptr.rs:9:21
33
|
44
LL | #[target_feature(enable = "sse2")]
55
| ---------------------------------- `#[target_feature]` added here

tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs

-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// [thir]compile-flags: -Z thir-unsafeck
33
// only-x86_64
44

5-
#![feature(target_feature_11)]
6-
75
#[target_feature(enable = "sse2")]
86
fn foo() {}
97

tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0308]: mismatched types
2-
--> $DIR/fn-ptr.rs:11:21
2+
--> $DIR/fn-ptr.rs:9:21
33
|
44
LL | #[target_feature(enable = "sse2")]
55
| ---------------------------------- `#[target_feature]` added here

tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// only-x86_64
22

3-
#![feature(target_feature_11)]
4-
53
#[target_feature(enable = "avx")]
64
fn foo() {}
75

tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0277]: expected a `Fn<()>` closure, found `fn() {foo}`
2-
--> $DIR/fn-traits.rs:24:10
2+
--> $DIR/fn-traits.rs:22:10
33
|
44
LL | call(foo);
55
| ---- ^^^ expected an `Fn<()>` closure, found `fn() {foo}`
@@ -10,13 +10,13 @@ LL | call(foo);
1010
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
1111
= note: `#[target_feature]` functions do not implement the `Fn` traits
1212
note: required by a bound in `call`
13-
--> $DIR/fn-traits.rs:11:17
13+
--> $DIR/fn-traits.rs:9:17
1414
|
1515
LL | fn call(f: impl Fn()) {
1616
| ^^^^ required by this bound in `call`
1717

1818
error[E0277]: expected a `FnMut<()>` closure, found `fn() {foo}`
19-
--> $DIR/fn-traits.rs:25:14
19+
--> $DIR/fn-traits.rs:23:14
2020
|
2121
LL | call_mut(foo);
2222
| -------- ^^^ expected an `FnMut<()>` closure, found `fn() {foo}`
@@ -27,13 +27,13 @@ LL | call_mut(foo);
2727
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
2828
= note: `#[target_feature]` functions do not implement the `Fn` traits
2929
note: required by a bound in `call_mut`
30-
--> $DIR/fn-traits.rs:15:21
30+
--> $DIR/fn-traits.rs:13:21
3131
|
3232
LL | fn call_mut(f: impl FnMut()) {
3333
| ^^^^^^^ required by this bound in `call_mut`
3434

3535
error[E0277]: expected a `FnOnce<()>` closure, found `fn() {foo}`
36-
--> $DIR/fn-traits.rs:26:15
36+
--> $DIR/fn-traits.rs:24:15
3737
|
3838
LL | call_once(foo);
3939
| --------- ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}`
@@ -44,13 +44,13 @@ LL | call_once(foo);
4444
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
4545
= note: `#[target_feature]` functions do not implement the `Fn` traits
4646
note: required by a bound in `call_once`
47-
--> $DIR/fn-traits.rs:19:22
47+
--> $DIR/fn-traits.rs:17:22
4848
|
4949
LL | fn call_once(f: impl FnOnce()) {
5050
| ^^^^^^^^ required by this bound in `call_once`
5151

5252
error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
53-
--> $DIR/fn-traits.rs:28:10
53+
--> $DIR/fn-traits.rs:26:10
5454
|
5555
LL | call(foo_unsafe);
5656
| ---- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
@@ -61,13 +61,13 @@ LL | call(foo_unsafe);
6161
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
6262
= note: `#[target_feature]` functions do not implement the `Fn` traits
6363
note: required by a bound in `call`
64-
--> $DIR/fn-traits.rs:11:17
64+
--> $DIR/fn-traits.rs:9:17
6565
|
6666
LL | fn call(f: impl Fn()) {
6767
| ^^^^ required by this bound in `call`
6868

6969
error[E0277]: expected a `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
70-
--> $DIR/fn-traits.rs:30:14
70+
--> $DIR/fn-traits.rs:28:14
7171
|
7272
LL | call_mut(foo_unsafe);
7373
| -------- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
@@ -78,13 +78,13 @@ LL | call_mut(foo_unsafe);
7878
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
7979
= note: `#[target_feature]` functions do not implement the `Fn` traits
8080
note: required by a bound in `call_mut`
81-
--> $DIR/fn-traits.rs:15:21
81+
--> $DIR/fn-traits.rs:13:21
8282
|
8383
LL | fn call_mut(f: impl FnMut()) {
8484
| ^^^^^^^ required by this bound in `call_mut`
8585

8686
error[E0277]: expected a `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
87-
--> $DIR/fn-traits.rs:32:15
87+
--> $DIR/fn-traits.rs:30:15
8888
|
8989
LL | call_once(foo_unsafe);
9090
| --------- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
@@ -95,7 +95,7 @@ LL | call_once(foo_unsafe);
9595
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
9696
= note: `#[target_feature]` functions do not implement the `Fn` traits
9797
note: required by a bound in `call_once`
98-
--> $DIR/fn-traits.rs:19:22
98+
--> $DIR/fn-traits.rs:17:22
9999
|
100100
LL | fn call_once(f: impl FnOnce()) {
101101
| ^^^^^^^^ required by this bound in `call_once`

tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// check-pass
22

3-
#![feature(target_feature_11)]
4-
53
struct S<T>(T)
64
where
75
[T; (|| {}, 1).1]: Copy;

0 commit comments

Comments
 (0)