Skip to content

Commit

Permalink
cfg_attr_multi: Feature gate
Browse files Browse the repository at this point in the history
  • Loading branch information
Havvy committed Oct 7, 2018
1 parent 1a867dc commit 35e6c65
Show file tree
Hide file tree
Showing 16 changed files with 115 additions and 8 deletions.
20 changes: 20 additions & 0 deletions src/doc/unstable-book/src/language-features/cfg-attr-multi.md
@@ -0,0 +1,20 @@
# `cfg_attr_multi`

The tracking issue for this feature is: [#555666]
The RFC for this feature is: [#2539]

[#555666]: https://github.com/rust-lang/rust/issues/555666
[#2539]: https://github.com/rust-lang/rfcs/pull/2539

------------------------

This feature flag lets you put multiple attributes into a `cfg_attr` attribute.

Example:

```rust,ignore
#[cfg_attr(all(), must_use, optimize)]
```

Because `cfg_attr` resolves before procedural macros, this does not affect
macro resolution at all.
36 changes: 35 additions & 1 deletion src/libsyntax/config.rs
Expand Up @@ -9,7 +9,14 @@
// except according to those terms.

use attr::HasAttrs;
use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
use feature_gate::{
feature_err,
EXPLAIN_STMT_ATTR_SYNTAX,
Features,
get_features,
GateIssue,
emit_feature_err,
};
use {fold, attr};
use ast;
use source_map::Spanned;
Expand Down Expand Up @@ -97,6 +104,13 @@ impl<'a> StripUnconfigured<'a> {
return vec![attr];
}

let gate_cfg_attr_multi = if let Some(ref features) = self.features {
!features.cfg_attr_multi
} else {
false
};
let cfg_attr_span = attr.span;

let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| {
parser.expect(&token::OpenDelim(token::Paren))?;

Expand All @@ -123,6 +137,26 @@ impl<'a> StripUnconfigured<'a> {
}
};

// Check feature gate and lint on zero attributes in source. Even if the feature is gated,
// we still compute as if it wasn't, since the emitted error will stop compilation futher
// along the compilation.
match (expanded_attrs.len(), gate_cfg_attr_multi) {
(0, false) => {
// FIXME: Emit unused attribute lint here.
},
(1, _) => {},
(_, true) => {
emit_feature_err(
self.sess,
"cfg_attr_multi",
cfg_attr_span,
GateIssue::Language,
"cfg_attr with zero or more than one attributes is experimental",
);
},
(_, false) => {}
}

if attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
// We call `process_cfg_attr` recursively in case there's a
// `cfg_attr` inside of another `cfg_attr`. E.g.
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/feature_gate.rs
Expand Up @@ -515,6 +515,9 @@ declare_features! (

// Allows `impl Trait` in bindings (`let`, `const`, `static`)
(active, impl_trait_in_bindings, "1.30.0", Some(34511), None),

// #[cfg_attr(predicate, multiple, attributes, here)]
(active, cfg_attr_multi, "1.31.0", Some(555666), None),
);

declare_features! (
Expand Down
Expand Up @@ -4,6 +4,7 @@
// compile-pass

#![warn(unused_must_use)]
#![feature(cfg_attr_multi)]

#[cfg_attr(any(), deprecated, must_use)]
struct Struct {}
Expand Down
Expand Up @@ -10,6 +10,7 @@
//
// compile-flags: --cfg broken

#![feature(cfg_attr_multi)]
#![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental

fn main() { }
@@ -1,5 +1,5 @@
error[E0658]: no_core is experimental (see issue #29639)
--> $DIR/cfg-attr-multi-invalid-1.rs:13:21
--> $DIR/cfg-attr-multi-invalid-1.rs:14:21
|
LL | #![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental
| ^^^^^^^
Expand Down
Expand Up @@ -10,6 +10,7 @@
//
// compile-flags: --cfg broken

#![feature(cfg_attr_multi)]
#![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental

fn main() { }
@@ -1,5 +1,5 @@
error[E0658]: no_core is experimental (see issue #29639)
--> $DIR/cfg-attr-multi-invalid-2.rs:13:29
--> $DIR/cfg-attr-multi-invalid-2.rs:14:29
|
LL | #![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental
| ^^^^^^^
Expand Down
1 change: 1 addition & 0 deletions src/test/ui/conditional-compilation/cfg-attr-multi-true.rs
Expand Up @@ -5,6 +5,7 @@
// compile-pass

#![warn(unused_must_use)]
#![feature(cfg_attr_multi)]

#[cfg_attr(all(), deprecated, must_use)]
struct MustUseDeprecated {}
Expand Down
10 changes: 5 additions & 5 deletions src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr
@@ -1,31 +1,31 @@
warning: use of deprecated item 'MustUseDeprecated'
--> $DIR/cfg-attr-multi-true.rs:12:6
--> $DIR/cfg-attr-multi-true.rs:13:6
|
LL | impl MustUseDeprecated { //~ warning: use of deprecated item
| ^^^^^^^^^^^^^^^^^
|
= note: #[warn(deprecated)] on by default

warning: use of deprecated item 'MustUseDeprecated'
--> $DIR/cfg-attr-multi-true.rs:19:5
--> $DIR/cfg-attr-multi-true.rs:20:5
|
LL | MustUseDeprecated::new(); //~ warning: use of deprecated item
| ^^^^^^^^^^^^^^^^^^^^^^

warning: use of deprecated item 'MustUseDeprecated'
--> $DIR/cfg-attr-multi-true.rs:13:17
--> $DIR/cfg-attr-multi-true.rs:14:17
|
LL | fn new() -> MustUseDeprecated { //~ warning: use of deprecated item
| ^^^^^^^^^^^^^^^^^

warning: use of deprecated item 'MustUseDeprecated'
--> $DIR/cfg-attr-multi-true.rs:14:9
--> $DIR/cfg-attr-multi-true.rs:15:9
|
LL | MustUseDeprecated {} //~ warning: use of deprecated item
| ^^^^^^^^^^^^^^^^^

warning: unused `MustUseDeprecated` which must be used
--> $DIR/cfg-attr-multi-true.rs:19:5
--> $DIR/cfg-attr-multi-true.rs:20:5
|
LL | MustUseDeprecated::new(); //~ warning: use of deprecated item
| ^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.rs
@@ -0,0 +1,5 @@
// gate-test-cfg_attr_multi

#![cfg_attr(all(), warn(nonstandard_style), allow(unused_attributes))]
//~^ ERROR cfg_attr with zero or more than one attributes is experimental
fn main() {}
11 changes: 11 additions & 0 deletions src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr
@@ -0,0 +1,11 @@
error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #555666)
--> $DIR/feature-gate-cfg-attr-multi-1.rs:3:1
|
LL | #![cfg_attr(all(), warn(nonstandard_style), allow(unused_attributes))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(cfg_attr_multi)] to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
3 changes: 3 additions & 0 deletions src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.rs
@@ -0,0 +1,3 @@
#![cfg_attr(all(),)]
//~^ ERROR cfg_attr with zero or more than one attributes is experimental
fn main() {}
11 changes: 11 additions & 0 deletions src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr
@@ -0,0 +1,11 @@
error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #555666)
--> $DIR/feature-gate-cfg-attr-multi-2.rs:1:1
|
LL | #![cfg_attr(all(),)]
| ^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(cfg_attr_multi)] to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
@@ -0,0 +1,7 @@
// Test that settingt the featute gate while using its functionality doesn't error.

// compile-pass

#![cfg_attr(all(), feature(cfg_attr_multi), crate_type="bin")]

fn main() {}
@@ -0,0 +1,9 @@
// Test that settingt the featute gate while using its functionality doesn't error.
// Specifically, if there's a cfg-attr *before* the feature gate.

// compile-pass

#![cfg_attr(all(),)]
#![cfg_attr(all(), feature(cfg_attr_multi), crate_type="bin")]

fn main() {}

0 comments on commit 35e6c65

Please sign in to comment.