Skip to content

Commit fed1f9f

Browse files
committed
RFC for attributes on match arms and statements.
1 parent a260073 commit fed1f9f

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed

active/0000-more-attributes.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
- Start Date: 2014-03-20
2+
- RFC PR #: (leave this empty)
3+
- Rust Issue #: (leave this empty)
4+
5+
# Summary
6+
7+
Allow attributes on more places inside functions, such as match arms
8+
and statements.
9+
10+
# Motivation
11+
12+
One sometimes wishes to annotate things inside functions with, for
13+
example, lint `#[allow]`s, conditional compilation `#[cfg]`s, branch
14+
weight hints and even extra semantic (or otherwise) annotations for
15+
external tools.
16+
17+
For the lints, one can currently only activate lints at the level of
18+
the function which is possibly larger than one needs, and so may allow
19+
other "bad" things to sneak through accidentally. E.g.
20+
21+
```rust
22+
#[allow(uppercase_variable)]
23+
let L = List::new(); // lowercase looks like one or capital i
24+
```
25+
26+
For the conditional compilation, the work-around is duplicating the
27+
whole containing function with a `#[cfg]`. A case study is
28+
[sfackler's bindings to OpenSSL](https://github.com/sfackler/rust-openssl),
29+
where many distributions remove SSLv2 support, and so that portion of
30+
Rust bindings needs to be conditionally disabled. The obvious way to
31+
support the various different SSL versions is an enum
32+
33+
```rust
34+
pub enum SslMethod {
35+
#[cfg(sslv2)]
36+
/// Only support the SSLv2 protocol
37+
Sslv2,
38+
/// Only support the SSLv3 protocol
39+
Sslv3,
40+
/// Only support the TLSv1 protocol
41+
Tlsv1,
42+
/// Support the SSLv2, SSLv3 and TLSv1 protocols
43+
Sslv23,
44+
}
45+
```
46+
47+
However, all `match`s can only mention `Sslv2` when the `cfg` is
48+
active, i.e. the following is invalid:
49+
50+
```rust
51+
fn name(method: SslMethod) -> &'static str {
52+
match method {
53+
Sslv2 => "SSLv2",
54+
Sslv3 => "SSLv3",
55+
_ => "..."
56+
}
57+
}
58+
```
59+
60+
A valid method would be to have two definitions: `#[cfg(sslv2)] fn
61+
name(...)` and `#[cfg(not(sslv2)] fn name(...)`. The former has the
62+
`Sslv2` arm, the latter does not. Clearly, this explodes exponentially
63+
for each additional `cfg`'d variant in an enum.
64+
65+
Branch weights would allow the careful micro-optimiser to inform the
66+
compiler that, for example, a certain match arm is rarely taken:
67+
68+
```rust
69+
match foo {
70+
Common => {}
71+
#[cold]
72+
Rare => {}
73+
}
74+
```
75+
76+
The sort of things one could do with other arbitrary annotations are
77+
78+
```rust
79+
#[allowed_unsafe_actions(ffi)]
80+
#[audited="2014-04-22"]
81+
unsafe { ... }
82+
```
83+
84+
and then have an external tool that checks that that `unsafe` block's
85+
only unsafe actions are FFI, or a tool that lists blocks that have
86+
been changed since the last audit or haven't been audited ever.
87+
88+
89+
# Detailed design
90+
91+
Normal attribute syntax:
92+
93+
```rust
94+
fn foo() {
95+
#[attr]
96+
let x = 1;
97+
98+
#[attr]
99+
foo();
100+
101+
#[attr]
102+
match x {
103+
#[attr]
104+
Thing => {}
105+
}
106+
107+
#[attr]
108+
if foo {
109+
} else {
110+
}
111+
}
112+
```
113+
114+
# Alternatives
115+
116+
There aren't really any general alternatives; one could probably hack
117+
around the conditional-enum-variants & matches with some macros and
118+
helper functions to share as much code as possible; but in general
119+
this won't work.
120+
121+
The other instances could be approximated with macros and helper
122+
functions, but to an even lesser degree (e.g. how would one annotate a
123+
general `unsafe` block).
124+
125+
# Unresolved questions
126+
127+
- Should one be able to annotate the `else` branch(es) of an `if`? e.g.
128+
129+
```rust
130+
if foo {
131+
} #[attr] else if bar {
132+
} #[attr] else {
133+
}
134+
```
135+
136+
or maybe
137+
138+
```rust
139+
if foo {
140+
} else #[attr] if bar {
141+
} else #[attr] {
142+
}
143+
```

0 commit comments

Comments
 (0)