Skip to content

Commit f79d0f0

Browse files
committed
target_feature 1.1
1 parent 8bffc2f commit f79d0f0

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed

text/0000-target-feature-1.1.md

+174
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
- Feature Name: `#[target_feature]` 1.1
2+
- Start Date: 2018-04-06
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
This RFC attempts to resolve some of the unresolved questions in [RFC 2045
10+
(`target_feature`)]. In particular, it allows:
11+
12+
* specifying `#[target_feature]` functions without making them `unsafe fn`
13+
* calling `#[target_feature]` functions in some contexts without `unsafe { }` blocks
14+
15+
It achieves this by proposing three incremental steps that we can sequentially
16+
make to improve the ergonomics and the safety of target-specific functionality
17+
without adding run-time overhead.
18+
19+
[RFC 2045 (`target_feature`)]: https://github.com/rust-lang/rfcs/pull/2045
20+
21+
# Motivation
22+
[motivation]: #motivation
23+
24+
> This is a brief recap of [RFC 2045 (`target_feature`)].
25+
26+
The `#[target_feature]` attribute allows Rust to generate machine code for a
27+
function under the assumption that the hardware where the function will be
28+
executed on supports some specific "features".
29+
30+
If the hardware does not support the features, the machine code was generated
31+
under assumptions that do not hold, and the behavior of executing the function
32+
is undefined.
33+
34+
[RFC 2045 (`target_feature`)] guarantees safety by requiring all
35+
`#[target_feature]` functions to be `unsafe fn`, thus preventing them from being
36+
called from safe code. That is, users have to open an `unsafe { }` block to call
37+
these functions, and they have to manually ensure that their pre-conditions
38+
hold - for example, that they will only be executed on the appropriate hardware
39+
by doing run-time feature detection, or using conditional compilation.
40+
41+
And that's it. That's all [RFC 2045 (`target_feature`)] had to say about this.
42+
Back then, there were many other problems that needed to be solved for all of
43+
this to be minially useful, and [RFC 2045 (`target_feature`)] dealt with those.
44+
45+
However, everybody agreed, and still agrees, that this is far from ideal for
46+
many reasons:
47+
48+
* when calling `#[target_feature]` functions from other `#[target_feature]`
49+
functions with the same features, the calls are currently still `unsafe` but
50+
they are actually safe to call.
51+
* making all `#[target_feature]` functions `unsafe fn`s and requiring `unsafe
52+
{}` to call them everywhere hides other potential sources of `unsafe` within
53+
these functions. Users get used to upholding `#[target_feature]`-related
54+
pre-conditions, and other types of pre-conditions get glossed by.
55+
56+
This RFC proposes concrete solutions for these two problems.
57+
58+
# Guide-level explanation
59+
[guide-level-explanation]: #guide-level-explanation
60+
61+
62+
Currently, we require that `#[target_feature]` functions be declared as `unsafe
63+
fn`. This RFC relaxes this restriction:
64+
65+
* safe `#[target_feature]` functions can be called _without_ an `unsafe {}`
66+
block _only_ from functions with the exact same set of `#[target_feature]`s.
67+
Calling them from other contexts (other functions, static variable initializers,
68+
etc.) requires opening an `unsafe {}` even though they are not marked as
69+
`unsafe`:
70+
71+
```rust
72+
// Example 1:
73+
#[target_feature = "sse2"] unsafe fn foo() { } // RFC2045
74+
#[target_feature = "sse2"] fn bar() { } // NEW
75+
76+
// This function does not have the "sse2" target feature:
77+
fn meow() {
78+
foo(); // ERROR (unsafe block required)
79+
unsafe { foo() }; // OK
80+
bar(); // ERROR (meow is not sse2)
81+
unsafe { bar() }; // OK
82+
}
83+
84+
#[target_feature = "sse2"]
85+
fn bark() {
86+
foo(); // ERROR (foo is unsafe: unsafe block required)
87+
unsafe { foo() }; // OK
88+
bar(); // OK (bark is sse2 and bar is safe)
89+
unsafe { bar() }; // OK (as well - warning: unnecessary unsafe block)
90+
}
91+
92+
#[target_feature = "avx"] // avx != sse2
93+
fn moo() {
94+
foo(); // ERROR (unsafe block required)
95+
unsafe { foo() }; // OK
96+
bar(); // ERROR (bark is not sse2)
97+
unsafe { bar() }; // OK
98+
}
99+
```
100+
101+
> Note: while it is safe to call an SSE2 function from an AVX one, this would
102+
> require specifying how features relate to each other in hierarchies. This
103+
> would unnecessary complicate this RFC and can be done later once we agree on
104+
> the fundamentals.
105+
106+
107+
The `#[target_feature]` attribute continues to not be allowed on safe trait
108+
method implementations:
109+
110+
```rust
111+
// Example 2:
112+
trait Foo { fn foo(); }
113+
struct Fooish();
114+
impl Foo for Fooish {
115+
#[target_feature = "sse2"] fn foo() { }
116+
// ^ ERROR: #[target_feature] on trait method impl requires
117+
// unsafe fn but Foo::foo is safe
118+
// (this is already an error per RFC2045)
119+
}
120+
121+
trait Bar { unsafe fn bar(); }
122+
struct Barish();
123+
impl Bar for Barish {
124+
#[target_feature = "sse2"] unsafe fn bar() { } // OK (RFC2045)
125+
}
126+
```
127+
128+
* safe `#[target_feature]` functions are not assignable to safe `fn` pointers.
129+
130+
131+
```
132+
// Example 3
133+
#[target_feature] fn meow() {}
134+
135+
static x: fn () -> () = meow;
136+
// ^ ERROR: meow can only be assigned to unsafe fn pointers due to
137+
// #[target_feature] but function pointer x with type fn()->() is safe.
138+
static y: unsafe fn () -> () = meow as unsafe fn()->(); // OK
139+
```
140+
141+
# Reference-level explanation
142+
[reference-level-explanation]: #reference-level-explanation
143+
144+
This RFC proposes to changes to the language with respect to [RFC 2045 (`target_feature`)]:
145+
146+
* safe `#[target_feature]` functions can be called _without_ an `unsafe {}`
147+
block _only_ from functions with the exact same set of `#[target_feature]`s.
148+
Calling them from other contexts (other functions, static variable initializers,
149+
etc.) requires opening an `unsafe {}` even though they are not marked as
150+
`unsafe`
151+
152+
* safe `#[target_feature]` functions are not assignable to safe `fn` pointers.
153+
154+
# Drawbacks
155+
[drawbacks]: #drawbacks
156+
157+
TBD.
158+
159+
# Rationale and alternatives
160+
[alternatives]: #alternatives
161+
162+
TBD.
163+
164+
# Prior art
165+
[prior-art]: #prior-art
166+
167+
[RFC2212 target feature unsafe](https://github.com/rust-lang/rfcs/pull/2212)
168+
attempted to solve this problem. This RFC builds on the discussion that was
169+
produced by that RFC and by many discussions in the `stdsimd` repo.
170+
171+
# Unresolved questions
172+
[unresolved]: #unresolved-questions
173+
174+
TBD.

0 commit comments

Comments
 (0)