-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tracking issue for target_feature 1.1 RFC #69098
Comments
I've been working on this, trying to see if I would be able to implement this with my very little knowledge of the compiler. I think I can propose a PR soon. @rustbot claim |
In #69274 (comment), @petrochenkov pointed out a complication not made clear in the RFC (nor realized by anyone during the original discussion, AFAICT): safe trait functions are explicitly excluded because we can't check all call sites, but function items implement the |
It would probably be better to add the That would make the unsafety checker the only place (besides AST lowering) where they would be treated specially. Like, "yes, the function is unsafe, but we know that it's safe to call in this specific context, so the unsafe block can be omitted". The special coercion checks would no longer be necessary in that case. |
…r=hanna-kruppe Implement RFC 2396: `#[target_feature]` 1.1 Tracking issue: rust-lang#69098 r? @nikomatsakis cc @gnzlbg @joshtriplett
…hanna-kruppe Implement RFC 2396: `#[target_feature]` 1.1 Tracking issue: rust-lang#69098 r? @nikomatsakis cc @gnzlbg @joshtriplett
Now that #69274 landed, I think we can check |
@rustbot release-assignment |
Filed #72012 for the unsoundness discussed above (I think this is how T-lang tracking issues are supposed to be used now). |
Opened #73631 to discuss the expected behavior of closures with target-feature. |
It looks like there haven't been any updates on this in a while--is there anything I can do to bring this closer to stabilization? |
@calebzulawski I know it's almost a year later but I think this is probably ready for a stabilization report? (cc @rust-lang/lang) |
Tried to help by opening rust-lang/reference#1181, feedback from people who actually know what they are doing would be greatly appreciated. While writing the PR, I noticed that #72012 is a breaking change for wasm targets, where fn call_it(f: impl FnOnce()) {}
#[target_feature(enable = "simd128")]
fn foo_simd128() {}
fn main() {
foo_simd128(); // OK
call_it(foo_simd128); // error: the trait `FnOnce<()>` is not implemented
} |
…re-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`
Not having the target feature in the closure can also be pretty bad for performance, can't it? Presumably people enabled the target feature for a reason. I think we should have a lint that suggests people drop the |
Prior to I support adding the lint, as long as you are still permitted to use |
That seems odd to me; we don't allow this for regular functions either. Do you have a concrete usecase where this is relevant? I don't think we should just go based on "vibes" here. We'd have a future-compat lint for a while, and if nobody shows up with a usecase, IMO we should make it a hard error. |
Oh, I'm fine with that plan as well, it's the most consistent. #108655 suggested to me that there were users who wanted it, I don't personally have an example. However it does seem there's a PR coming to allow |
However it does seem there's a PR coming to allow #[inline(always)] on regular target feature functions by checking that there isn't a target feature mismatch at the call site, I'm not sure how successful that will be.
I heard there are such plans but IMO they should be blocked on fixing LLVM. Since I posted the link to the soundness issue in that Zulip thread, there has not been further discussion there AFAIK. But anyway that is a separate discussion.
|
I've written some code which I think would trigger the future-compat lint you're proposing (obviously I can't try it out yet). I think it's reasonable code:
There are ways I could rework my code to side-step the lint, but all I can think of make the code more ugly and brittle. And I don't really see a reason why I should have to do this. As I understand it, there's no problem with my code either under the old (closure doesn't inherit target_feature) or proposed new (does inherit) semantics. I appreciate that passing such a closure outside of the function it's defined in causes problems when combined with target_feature inheritance and LLVM's current behavior. But I don't think a future-compat warning and eventually hard error on perfectly good code is a nice way to handle that. |
@hanna-kruppe thanks! Yes that would trigger the lint.
Yes, but that's just incompatible with per-function target features, until LLVM fixes that bug. So the question is, what's more important -- having the target features in the closure, or having Would be interesting whether inheriting target features and regular
To be clear, the new semantics is that your closure still does not inherit target features, because it is |
In code like this, I mostly treat closures and non- Of course there are scenarios where I don't want or need everything to be inlined, e.g. because it's a big chunk of code that gets called from several different places. But in those cases I'm not slapping |
I mean we could also say that we'll "just" document that target_features is inherited into closures except for |
Note that the current behaviour is somewhat more surprising than that: it is inherited in inline(always) closures for purposes of safety checking, but not for codegen... |
What difference does not inheriting make, anyway?
|
If we do inherit target features into |
I hadn't seen that issue before and got confused trying to match what you're saying to the original reproducer in that issue. Are you saying
|
Yes that is exactly what I am saying. Specifically the example I posted above would be exactly that gadget, and I am fairly sure it would miscompile. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This looks like it would trigger it. While not directly related to this topic, I see you are passing the closure via |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
It's a work-around for an LLVM bug. In an ideal world we wouldn't have to worry about this.
Strictly speaking this doesn't make sense either. LLVM "just" has to ensure that the operations from The status quo is that:
It's not pretty, but between that long-standing LLVM bug and the general LLVM limitation around inlining and target features, and given our backwards compatibility constraints, it is unclear how to do better. Compared to stable, with TF 1.1 nothing changes for the behavior of |
Stabilize target_feature_11 # Stabilization report This is an updated version of rust-lang#116114, which is itself a redo of rust-lang#99767. Most of this commit and report were copied from those PRs. Thanks `@LeSeulArtichaut` and `@calebzulawski!` ## 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 *generally* 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(); } ``` Moreover, once rust-lang#135504 is merged, they can be converted to safe function pointers in a context in which calling them is safe: ```rust // Demonstration function #[target_feature(enable = "avx2")] fn avx2() {} fn foo() -> fn() { // Converting `avx2` to fn() is a compilation error here. avx2 } #[target_feature(enable = "avx2")] fn bar() -> fn() { // `avx2` coerces to fn() here avx2 } ``` See the section "Closures" below for justification of this behaviour. ## Test cases Tests for this feature can be found in [`tests/ui/target_feature/`](https://github.com/rust-lang/rust/tree/f6cb952dc115fd1311b02b694933e31d8dc8b002/tests/ui/target-feature). ## Edge cases ### Closures * [target-feature 1.1: should closures inherit target-feature annotations? rust-lang#73631](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 guarantee that the target-feature is available while the function, any closures defined inside it, as well as any safe function pointers obtained from target-feature functions inside it, execute. This is usually ensured because target features are assumed to never disappear, and: - on any unsafe call to a `#[target_feature]` function, presence of the target feature is guaranteed by the programmer through the safety requirements of the unsafe call. - on any safe call, this is guaranteed recursively by the caller. If you work in an environment where target features can be disabled, it is your responsibility to ensure that no code inside a target feature function (including inside a closure) runs after this (until the feature is enabled again). **Note:** this has an effect on existing code, as nowadays closures do not inherit features from the enclosing function, and thus this strengthens a safety requirement. It was originally proposed in rust-lang#73631 to solve this by adding a new type of UB: “taking a target feature away from your process after having run code that uses that target feature is UB” . This was motivated by userspace code already assuming in a few places that CPU features never disappear from a program during execution (see i.e. https://github.com/rust-lang/stdarch/blob/2e29bdf90832931ea499755bb4ad7a6b0809295a/crates/std_detect/src/detect/arch/x86.rs); however, concerns were raised in the context of the Linux kernel; thus, we propose to relax that requirement to "causing the set of usable features to be reduced is unsafe; when doing so, the programmer is required to ensure that no closures or safe fn pointers that use removed features are still in scope". * [Fix #[inline(always)] on closures with target feature 1.1 rust-lang#111836](rust-lang#111836) Closures accept `#[inline(always)]`, even within functions marked with `#[target_feature]`. Since these attributes conflict, `#[inline(always)]` wins out to maintain compatibility. ### ABI concerns * [The extern "C" ABI of SIMD vector types depends on target features rust-lang#116558](rust-lang#116558) The ABI of some types can change when compiling a function with different target features. This could have introduced unsoundness with target_feature_11, but recent fixes (rust-lang#133102, rust-lang#132173) either make those situations invalid or make the ABI no longer dependent on features. Thus, those issues should no longer occur. ### Special functions The `#[target_feature]` attribute is forbidden from a variety of special functions, such as main, current and future lang items (e.g. `#[start]`, `#[panic_handler]`), safe default trait implementations and safe trait methods. This was not disallowed at the time of the first stabilization PR for target_features_11, and resulted in the following issues/PRs: * [`#[target_feature]` is allowed on `main` rust-lang#108645](rust-lang#108645) * [`#[target_feature]` is allowed on default implementations rust-lang#108646](rust-lang#108646) * [#[target_feature] is allowed on #[panic_handler] with target_feature 1.1 rust-lang#109411](rust-lang#109411) * [Prevent using `#[target_feature]` on lang item functions rust-lang#115910](rust-lang#115910) ## Documentation * Reference: [Document the `target_feature_11` feature reference#1181](rust-lang/reference#1181) --- cc tracking issue rust-lang#69098 cc `@workingjubilee` cc `@RalfJung` r? `@rust-lang/lang`
Stabilize target_feature_11 # Stabilization report This is an updated version of rust-lang#116114, which is itself a redo of rust-lang#99767. Most of this commit and report were copied from those PRs. Thanks ``@LeSeulArtichaut`` and ``@calebzulawski!`` ## 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 *generally* 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(); } ``` Moreover, once rust-lang#135504 is merged, they can be converted to safe function pointers in a context in which calling them is safe: ```rust // Demonstration function #[target_feature(enable = "avx2")] fn avx2() {} fn foo() -> fn() { // Converting `avx2` to fn() is a compilation error here. avx2 } #[target_feature(enable = "avx2")] fn bar() -> fn() { // `avx2` coerces to fn() here avx2 } ``` See the section "Closures" below for justification of this behaviour. ## Test cases Tests for this feature can be found in [`tests/ui/target_feature/`](https://github.com/rust-lang/rust/tree/f6cb952dc115fd1311b02b694933e31d8dc8b002/tests/ui/target-feature). ## Edge cases ### Closures * [target-feature 1.1: should closures inherit target-feature annotations? rust-lang#73631](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 guarantee that the target-feature is available while the function, any closures defined inside it, as well as any safe function pointers obtained from target-feature functions inside it, execute. This is usually ensured because target features are assumed to never disappear, and: - on any unsafe call to a `#[target_feature]` function, presence of the target feature is guaranteed by the programmer through the safety requirements of the unsafe call. - on any safe call, this is guaranteed recursively by the caller. If you work in an environment where target features can be disabled, it is your responsibility to ensure that no code inside a target feature function (including inside a closure) runs after this (until the feature is enabled again). **Note:** this has an effect on existing code, as nowadays closures do not inherit features from the enclosing function, and thus this strengthens a safety requirement. It was originally proposed in rust-lang#73631 to solve this by adding a new type of UB: “taking a target feature away from your process after having run code that uses that target feature is UB” . This was motivated by userspace code already assuming in a few places that CPU features never disappear from a program during execution (see i.e. https://github.com/rust-lang/stdarch/blob/2e29bdf90832931ea499755bb4ad7a6b0809295a/crates/std_detect/src/detect/arch/x86.rs); however, concerns were raised in the context of the Linux kernel; thus, we propose to relax that requirement to "causing the set of usable features to be reduced is unsafe; when doing so, the programmer is required to ensure that no closures or safe fn pointers that use removed features are still in scope". * [Fix #[inline(always)] on closures with target feature 1.1 rust-lang#111836](rust-lang#111836) Closures accept `#[inline(always)]`, even within functions marked with `#[target_feature]`. Since these attributes conflict, `#[inline(always)]` wins out to maintain compatibility. ### ABI concerns * [The extern "C" ABI of SIMD vector types depends on target features rust-lang#116558](rust-lang#116558) The ABI of some types can change when compiling a function with different target features. This could have introduced unsoundness with target_feature_11, but recent fixes (rust-lang#133102, rust-lang#132173) either make those situations invalid or make the ABI no longer dependent on features. Thus, those issues should no longer occur. ### Special functions The `#[target_feature]` attribute is forbidden from a variety of special functions, such as main, current and future lang items (e.g. `#[start]`, `#[panic_handler]`), safe default trait implementations and safe trait methods. This was not disallowed at the time of the first stabilization PR for target_features_11, and resulted in the following issues/PRs: * [`#[target_feature]` is allowed on `main` rust-lang#108645](rust-lang#108645) * [`#[target_feature]` is allowed on default implementations rust-lang#108646](rust-lang#108646) * [#[target_feature] is allowed on #[panic_handler] with target_feature 1.1 rust-lang#109411](rust-lang#109411) * [Prevent using `#[target_feature]` on lang item functions rust-lang#115910](rust-lang#115910) ## Documentation * Reference: [Document the `target_feature_11` feature reference#1181](rust-lang/reference#1181) --- cc tracking issue rust-lang#69098 cc ``@workingjubilee`` cc ``@RalfJung`` r? ``@rust-lang/lang``
Stabilize target_feature_11 # Stabilization report This is an updated version of rust-lang#116114, which is itself a redo of rust-lang#99767. Most of this commit and report were copied from those PRs. Thanks ```@LeSeulArtichaut``` and ```@calebzulawski!``` ## 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 *generally* 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(); } ``` Moreover, once rust-lang#135504 is merged, they can be converted to safe function pointers in a context in which calling them is safe: ```rust // Demonstration function #[target_feature(enable = "avx2")] fn avx2() {} fn foo() -> fn() { // Converting `avx2` to fn() is a compilation error here. avx2 } #[target_feature(enable = "avx2")] fn bar() -> fn() { // `avx2` coerces to fn() here avx2 } ``` See the section "Closures" below for justification of this behaviour. ## Test cases Tests for this feature can be found in [`tests/ui/target_feature/`](https://github.com/rust-lang/rust/tree/f6cb952dc115fd1311b02b694933e31d8dc8b002/tests/ui/target-feature). ## Edge cases ### Closures * [target-feature 1.1: should closures inherit target-feature annotations? rust-lang#73631](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 guarantee that the target-feature is available while the function, any closures defined inside it, as well as any safe function pointers obtained from target-feature functions inside it, execute. This is usually ensured because target features are assumed to never disappear, and: - on any unsafe call to a `#[target_feature]` function, presence of the target feature is guaranteed by the programmer through the safety requirements of the unsafe call. - on any safe call, this is guaranteed recursively by the caller. If you work in an environment where target features can be disabled, it is your responsibility to ensure that no code inside a target feature function (including inside a closure) runs after this (until the feature is enabled again). **Note:** this has an effect on existing code, as nowadays closures do not inherit features from the enclosing function, and thus this strengthens a safety requirement. It was originally proposed in rust-lang#73631 to solve this by adding a new type of UB: “taking a target feature away from your process after having run code that uses that target feature is UB” . This was motivated by userspace code already assuming in a few places that CPU features never disappear from a program during execution (see i.e. https://github.com/rust-lang/stdarch/blob/2e29bdf90832931ea499755bb4ad7a6b0809295a/crates/std_detect/src/detect/arch/x86.rs); however, concerns were raised in the context of the Linux kernel; thus, we propose to relax that requirement to "causing the set of usable features to be reduced is unsafe; when doing so, the programmer is required to ensure that no closures or safe fn pointers that use removed features are still in scope". * [Fix #[inline(always)] on closures with target feature 1.1 rust-lang#111836](rust-lang#111836) Closures accept `#[inline(always)]`, even within functions marked with `#[target_feature]`. Since these attributes conflict, `#[inline(always)]` wins out to maintain compatibility. ### ABI concerns * [The extern "C" ABI of SIMD vector types depends on target features rust-lang#116558](rust-lang#116558) The ABI of some types can change when compiling a function with different target features. This could have introduced unsoundness with target_feature_11, but recent fixes (rust-lang#133102, rust-lang#132173) either make those situations invalid or make the ABI no longer dependent on features. Thus, those issues should no longer occur. ### Special functions The `#[target_feature]` attribute is forbidden from a variety of special functions, such as main, current and future lang items (e.g. `#[start]`, `#[panic_handler]`), safe default trait implementations and safe trait methods. This was not disallowed at the time of the first stabilization PR for target_features_11, and resulted in the following issues/PRs: * [`#[target_feature]` is allowed on `main` rust-lang#108645](rust-lang#108645) * [`#[target_feature]` is allowed on default implementations rust-lang#108646](rust-lang#108646) * [#[target_feature] is allowed on #[panic_handler] with target_feature 1.1 rust-lang#109411](rust-lang#109411) * [Prevent using `#[target_feature]` on lang item functions rust-lang#115910](rust-lang#115910) ## Documentation * Reference: [Document the `target_feature_11` feature reference#1181](rust-lang/reference#1181) --- cc tracking issue rust-lang#69098 cc ```@workingjubilee``` cc ```@RalfJung``` r? ```@rust-lang/lang```
Rollup merge of rust-lang#134090 - veluca93:stable-tf11, r=oli-obk Stabilize target_feature_11 # Stabilization report This is an updated version of rust-lang#116114, which is itself a redo of rust-lang#99767. Most of this commit and report were copied from those PRs. Thanks ```@LeSeulArtichaut``` and ```@calebzulawski!``` ## 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 *generally* 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(); } ``` Moreover, once rust-lang#135504 is merged, they can be converted to safe function pointers in a context in which calling them is safe: ```rust // Demonstration function #[target_feature(enable = "avx2")] fn avx2() {} fn foo() -> fn() { // Converting `avx2` to fn() is a compilation error here. avx2 } #[target_feature(enable = "avx2")] fn bar() -> fn() { // `avx2` coerces to fn() here avx2 } ``` See the section "Closures" below for justification of this behaviour. ## Test cases Tests for this feature can be found in [`tests/ui/target_feature/`](https://github.com/rust-lang/rust/tree/f6cb952dc115fd1311b02b694933e31d8dc8b002/tests/ui/target-feature). ## Edge cases ### Closures * [target-feature 1.1: should closures inherit target-feature annotations? rust-lang#73631](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 guarantee that the target-feature is available while the function, any closures defined inside it, as well as any safe function pointers obtained from target-feature functions inside it, execute. This is usually ensured because target features are assumed to never disappear, and: - on any unsafe call to a `#[target_feature]` function, presence of the target feature is guaranteed by the programmer through the safety requirements of the unsafe call. - on any safe call, this is guaranteed recursively by the caller. If you work in an environment where target features can be disabled, it is your responsibility to ensure that no code inside a target feature function (including inside a closure) runs after this (until the feature is enabled again). **Note:** this has an effect on existing code, as nowadays closures do not inherit features from the enclosing function, and thus this strengthens a safety requirement. It was originally proposed in rust-lang#73631 to solve this by adding a new type of UB: “taking a target feature away from your process after having run code that uses that target feature is UB” . This was motivated by userspace code already assuming in a few places that CPU features never disappear from a program during execution (see i.e. https://github.com/rust-lang/stdarch/blob/2e29bdf90832931ea499755bb4ad7a6b0809295a/crates/std_detect/src/detect/arch/x86.rs); however, concerns were raised in the context of the Linux kernel; thus, we propose to relax that requirement to "causing the set of usable features to be reduced is unsafe; when doing so, the programmer is required to ensure that no closures or safe fn pointers that use removed features are still in scope". * [Fix #[inline(always)] on closures with target feature 1.1 rust-lang#111836](rust-lang#111836) Closures accept `#[inline(always)]`, even within functions marked with `#[target_feature]`. Since these attributes conflict, `#[inline(always)]` wins out to maintain compatibility. ### ABI concerns * [The extern "C" ABI of SIMD vector types depends on target features rust-lang#116558](rust-lang#116558) The ABI of some types can change when compiling a function with different target features. This could have introduced unsoundness with target_feature_11, but recent fixes (rust-lang#133102, rust-lang#132173) either make those situations invalid or make the ABI no longer dependent on features. Thus, those issues should no longer occur. ### Special functions The `#[target_feature]` attribute is forbidden from a variety of special functions, such as main, current and future lang items (e.g. `#[start]`, `#[panic_handler]`), safe default trait implementations and safe trait methods. This was not disallowed at the time of the first stabilization PR for target_features_11, and resulted in the following issues/PRs: * [`#[target_feature]` is allowed on `main` rust-lang#108645](rust-lang#108645) * [`#[target_feature]` is allowed on default implementations rust-lang#108646](rust-lang#108646) * [#[target_feature] is allowed on #[panic_handler] with target_feature 1.1 rust-lang#109411](rust-lang#109411) * [Prevent using `#[target_feature]` on lang item functions rust-lang#115910](rust-lang#115910) ## Documentation * Reference: [Document the `target_feature_11` feature reference#1181](rust-lang/reference#1181) --- cc tracking issue rust-lang#69098 cc ```@workingjubilee``` cc ```@RalfJung``` r? ```@rust-lang/lang```
Stabilize target_feature_11 # Stabilization report This is an updated version of rust-lang/rust#116114, which is itself a redo of rust-lang/rust#99767. Most of this commit and report were copied from those PRs. Thanks ```@LeSeulArtichaut``` and ```@calebzulawski!``` ## 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 *generally* 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(); } ``` Moreover, once rust-lang/rust#135504 is merged, they can be converted to safe function pointers in a context in which calling them is safe: ```rust // Demonstration function #[target_feature(enable = "avx2")] fn avx2() {} fn foo() -> fn() { // Converting `avx2` to fn() is a compilation error here. avx2 } #[target_feature(enable = "avx2")] fn bar() -> fn() { // `avx2` coerces to fn() here avx2 } ``` See the section "Closures" below for justification of this behaviour. ## Test cases Tests for this feature can be found in [`tests/ui/target_feature/`](https://github.com/rust-lang/rust/tree/f6cb952dc115fd1311b02b694933e31d8dc8b002/tests/ui/target-feature). ## Edge cases ### Closures * [target-feature 1.1: should closures inherit target-feature annotations? #73631](rust-lang/rust#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 guarantee that the target-feature is available while the function, any closures defined inside it, as well as any safe function pointers obtained from target-feature functions inside it, execute. This is usually ensured because target features are assumed to never disappear, and: - on any unsafe call to a `#[target_feature]` function, presence of the target feature is guaranteed by the programmer through the safety requirements of the unsafe call. - on any safe call, this is guaranteed recursively by the caller. If you work in an environment where target features can be disabled, it is your responsibility to ensure that no code inside a target feature function (including inside a closure) runs after this (until the feature is enabled again). **Note:** this has an effect on existing code, as nowadays closures do not inherit features from the enclosing function, and thus this strengthens a safety requirement. It was originally proposed in #73631 to solve this by adding a new type of UB: “taking a target feature away from your process after having run code that uses that target feature is UB” . This was motivated by userspace code already assuming in a few places that CPU features never disappear from a program during execution (see i.e. https://github.com/rust-lang/stdarch/blob/2e29bdf90832931ea499755bb4ad7a6b0809295a/crates/std_detect/src/detect/arch/x86.rs); however, concerns were raised in the context of the Linux kernel; thus, we propose to relax that requirement to "causing the set of usable features to be reduced is unsafe; when doing so, the programmer is required to ensure that no closures or safe fn pointers that use removed features are still in scope". * [Fix #[inline(always)] on closures with target feature 1.1 #111836](rust-lang/rust#111836) Closures accept `#[inline(always)]`, even within functions marked with `#[target_feature]`. Since these attributes conflict, `#[inline(always)]` wins out to maintain compatibility. ### ABI concerns * [The extern "C" ABI of SIMD vector types depends on target features #116558](rust-lang/rust#116558) The ABI of some types can change when compiling a function with different target features. This could have introduced unsoundness with target_feature_11, but recent fixes (#133102, #132173) either make those situations invalid or make the ABI no longer dependent on features. Thus, those issues should no longer occur. ### Special functions The `#[target_feature]` attribute is forbidden from a variety of special functions, such as main, current and future lang items (e.g. `#[start]`, `#[panic_handler]`), safe default trait implementations and safe trait methods. This was not disallowed at the time of the first stabilization PR for target_features_11, and resulted in the following issues/PRs: * [`#[target_feature]` is allowed on `main` #108645](rust-lang/rust#108645) * [`#[target_feature]` is allowed on default implementations #108646](rust-lang/rust#108646) * [#[target_feature] is allowed on #[panic_handler] with target_feature 1.1 #109411](rust-lang/rust#109411) * [Prevent using `#[target_feature]` on lang item functions #115910](rust-lang/rust#115910) ## Documentation * Reference: [Document the `target_feature_11` feature reference#1181](rust-lang/reference#1181) --- cc tracking issue rust-lang/rust#69098 cc ```@workingjubilee``` cc ```@RalfJung``` r? ```@rust-lang/lang```
Stabilize target_feature_11 # Stabilization report This is an updated version of rust-lang/rust#116114, which is itself a redo of rust-lang/rust#99767. Most of this commit and report were copied from those PRs. Thanks ```@LeSeulArtichaut``` and ```@calebzulawski!``` ## 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 *generally* 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(); } ``` Moreover, once rust-lang/rust#135504 is merged, they can be converted to safe function pointers in a context in which calling them is safe: ```rust // Demonstration function #[target_feature(enable = "avx2")] fn avx2() {} fn foo() -> fn() { // Converting `avx2` to fn() is a compilation error here. avx2 } #[target_feature(enable = "avx2")] fn bar() -> fn() { // `avx2` coerces to fn() here avx2 } ``` See the section "Closures" below for justification of this behaviour. ## Test cases Tests for this feature can be found in [`tests/ui/target_feature/`](https://github.com/rust-lang/rust/tree/f6cb952dc115fd1311b02b694933e31d8dc8b002/tests/ui/target-feature). ## Edge cases ### Closures * [target-feature 1.1: should closures inherit target-feature annotations? #73631](rust-lang/rust#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 guarantee that the target-feature is available while the function, any closures defined inside it, as well as any safe function pointers obtained from target-feature functions inside it, execute. This is usually ensured because target features are assumed to never disappear, and: - on any unsafe call to a `#[target_feature]` function, presence of the target feature is guaranteed by the programmer through the safety requirements of the unsafe call. - on any safe call, this is guaranteed recursively by the caller. If you work in an environment where target features can be disabled, it is your responsibility to ensure that no code inside a target feature function (including inside a closure) runs after this (until the feature is enabled again). **Note:** this has an effect on existing code, as nowadays closures do not inherit features from the enclosing function, and thus this strengthens a safety requirement. It was originally proposed in #73631 to solve this by adding a new type of UB: “taking a target feature away from your process after having run code that uses that target feature is UB” . This was motivated by userspace code already assuming in a few places that CPU features never disappear from a program during execution (see i.e. https://github.com/rust-lang/stdarch/blob/2e29bdf90832931ea499755bb4ad7a6b0809295a/crates/std_detect/src/detect/arch/x86.rs); however, concerns were raised in the context of the Linux kernel; thus, we propose to relax that requirement to "causing the set of usable features to be reduced is unsafe; when doing so, the programmer is required to ensure that no closures or safe fn pointers that use removed features are still in scope". * [Fix #[inline(always)] on closures with target feature 1.1 #111836](rust-lang/rust#111836) Closures accept `#[inline(always)]`, even within functions marked with `#[target_feature]`. Since these attributes conflict, `#[inline(always)]` wins out to maintain compatibility. ### ABI concerns * [The extern "C" ABI of SIMD vector types depends on target features #116558](rust-lang/rust#116558) The ABI of some types can change when compiling a function with different target features. This could have introduced unsoundness with target_feature_11, but recent fixes (#133102, #132173) either make those situations invalid or make the ABI no longer dependent on features. Thus, those issues should no longer occur. ### Special functions The `#[target_feature]` attribute is forbidden from a variety of special functions, such as main, current and future lang items (e.g. `#[start]`, `#[panic_handler]`), safe default trait implementations and safe trait methods. This was not disallowed at the time of the first stabilization PR for target_features_11, and resulted in the following issues/PRs: * [`#[target_feature]` is allowed on `main` #108645](rust-lang/rust#108645) * [`#[target_feature]` is allowed on default implementations #108646](rust-lang/rust#108646) * [#[target_feature] is allowed on #[panic_handler] with target_feature 1.1 #109411](rust-lang/rust#109411) * [Prevent using `#[target_feature]` on lang item functions #115910](rust-lang/rust#115910) ## Documentation * Reference: [Document the `target_feature_11` feature reference#1181](rust-lang/reference#1181) --- cc tracking issue rust-lang/rust#69098 cc ```@workingjubilee``` cc ```@RalfJung``` r? ```@rust-lang/lang```
This is a tracking issue for the RFC "target_feature 1.1" (rust-lang/rfcs#2396).
Issues: F-target_feature_11target feature 1.1 RFC
People
Last updated in Mar 2023:
gnzlbg@workingjubilee (person who can help answer tricky questions that arise during implementation)Step
#[target_feature]
1.1 #69274target_feature_11
feature reference#1181#![feature(target_feature_11)]
#108654#[target_feature]
is allowed onmain
#108645#[target_feature]
is allowed on default implementations #108646target_feature_11
rejects code that was previously accepted #108655extern "C"
ABI of SIMD vector types depends on target features (tracking issue forabi_unsupported_vector_types
future-incompatibility lint) #116558neon
aarch64 target feature is unsound: it changes the float ABI #131058Unresolved questions
target_feature_11 allows bypassing safety checks through Fn* traits #72012 -- soundness hole where safe target-feature functions implement theFn
traits.target-feature 1.1: should closures inherit target-feature annotations? #73631 -- behavior of closures and target-featuresThe text was updated successfully, but these errors were encountered: