Skip to content

Commit b6093bb

Browse files
committed
Merge remote-tracking branch 'sfackler/cfg-syntax'
2 parents d864cb5 + 499cf52 commit b6093bb

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

active/0000-cfg-syntax.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
- Start Date: 2014-08-09
2+
- RFC PR:
3+
- Rust Issue:
4+
5+
# Summary
6+
7+
The `#[cfg(...)]` attribute provides a mechanism for conditional compilation of
8+
items in a Rust crate. This RFC proposes to change the syntax of `#[cfg]` to
9+
make more sense as well as enable expansion of the conditional compilation
10+
system to attributes while maintaining a single syntax.
11+
12+
# Motivation
13+
14+
In the current implementation, `#[cfg(...)]` takes a comma separated list of
15+
`key`, `key = "value"`, `not(key)`, or `not(key = "value")`. An individual
16+
`#[cfg(...)]` attribute "matches" if *all* of the contained cfg patterns match
17+
the compilation environment, and an item preserved if it *either* has no
18+
`#[cfg(...)]` attributes or *any* of the `#[cfg(...)]` attributes present
19+
match.
20+
21+
This is problematic for several reasons:
22+
23+
* It is excessively verbose in certain situations. For example, implementing
24+
the equivalent of `(a AND (b OR c OR d))` requires three separate
25+
attributes and `a` to be duplicated in each.
26+
* It differs from all other attributes in that all `#[cfg(...)]` attributes on
27+
an item must be processed together instead of in isolation. This change
28+
will move `#[cfg(...)]` closer to implementation as a normal syntax
29+
extension.
30+
31+
# Detailed design
32+
33+
The `<p>` inside of `#[cfg(<p>)]` will be called a *cfg pattern* and have a
34+
simple recursive syntax:
35+
36+
* `key` is a cfg pattern and will match if `key` is present in the
37+
compilation environment.
38+
* `key = "value"` is a cfg pattern and will match if a mapping from `key`
39+
to `value` is present in the compilation environment. At present, key-value
40+
pairs only exist for compiler defined keys such as `target_os` and
41+
`endian`.
42+
* `not(<p>)` is a cfg pattern if `<p>` is and matches if `<p>` does not match.
43+
* `all(<p>, ...)` is a cfg pattern if all of the comma-separated `<p>`s are cfg
44+
patterns and all of them match.
45+
* `any(<p>, ...)` is a cfg pattern if all of the comma-separated `<p>`s are cfg
46+
patterns and any of them match.
47+
48+
If an item is tagged with `#[cfg(<p>)]`, that item will be stripped from the
49+
AST if the cfg pattern `<p>` does not match.
50+
51+
One implementation hazard is that the semantics of
52+
```rust
53+
#[cfg(a)]
54+
#[cfg(b)]
55+
fn foo() {}
56+
```
57+
will change from "include `foo` if *either of* `a` and `b` are present in the
58+
compilation environment" to "include `foo` if *both of* `a` and `b` are present
59+
in the compilation environment". To ease the transition, the old semantics of
60+
multiple `#[cfg(...)]` attributes will be maintained as a special case, with a
61+
warning. After some reasonable period of time, the special case will be
62+
removed.
63+
64+
In addition, `#[cfg(a, b, c)]` will be accepted with a warning and be
65+
equivalent to `#[cfg(all(a, b, c))]`. Again, after some reasonable period of
66+
time, this behavior will be removed as well.
67+
68+
The `cfg!()` syntax extension will be modified to accept cfg patterns as well.
69+
A `#[cfg_attr(<p>, <attr>)]` syntax extension will be added
70+
([PR 16230](https://github.com/rust-lang/rust/pull/16230)) which will expand to
71+
`#[<attr>]` if the cfg pattern `<p>` matches. The test harness's
72+
`#[ignore]` attribute will have its built-in cfg filtering
73+
functionality stripped in favor of `#[cfg_attr(<p>, ignore)]`.
74+
75+
# Drawbacks
76+
77+
While the implementation of this change in the compiler will be
78+
straightforward, the effects on downstream code will be significant, especially
79+
in the standard library.
80+
81+
# Alternatives
82+
83+
`all` and `any` could be renamed to `and` and `or`, though I feel that the
84+
proposed names read better with the function-like syntax and are consistent
85+
with `Iterator::all` and `Iterator::any`.
86+
87+
Issue [#2119](https://github.com/rust-lang/rust/issues/2119) proposed the
88+
addition of `||` and `&&` operators and parantheses to the attribute syntax
89+
to result in something like `#[cfg(a || (b && c)]`. I don't favor this proposal
90+
since it would result in a major change to the attribute syntax for relatively
91+
little readability gain.
92+
93+
# Unresolved questions
94+
95+
How long should multiple `#[cfg(...)]` attributes on a single item be
96+
forbidden? It should probably be at least until after 0.12 releases.
97+
98+
Should we permanently keep the behavior of treating `#[cfg(a, b)]` as
99+
`#[cfg(all(a, b))]`? It is the common case, and adding this interpretation
100+
can reduce the noise level a bit. On the other hand, it may be a bit confusing
101+
to read as it's not immediately clear if it will be processed as `and(..)` or
102+
`all(..)`.

0 commit comments

Comments
 (0)