Skip to content

Commit 1a867dc

Browse files
committed
cfg_attr_multi: Basic implementation
Does not implement the warning or a feature flag.
1 parent 9568ec6 commit 1a867dc

14 files changed

+252
-45
lines changed

src/libsyntax/config.rs

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -73,49 +73,76 @@ impl<'a> StripUnconfigured<'a> {
7373
if self.in_cfg(node.attrs()) { Some(node) } else { None }
7474
}
7575

76+
/// Parse and expand all `cfg_attr` attributes into a list of attributes
77+
/// that are within each `cfg_attr` that has a true configuration predicate.
78+
///
79+
/// Gives compiler warnigns if any `cfg_attr` does not contain any
80+
/// attributes and is in the original source code. Gives compiler errors if
81+
/// the syntax of any `cfg_attr` is incorrect.
7682
pub fn process_cfg_attrs<T: HasAttrs>(&mut self, node: T) -> T {
7783
node.map_attrs(|attrs| {
78-
attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect()
84+
attrs.into_iter().flat_map(|attr| self.process_cfg_attr(attr)).collect()
7985
})
8086
}
8187

82-
fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
88+
/// Parse and expand a single `cfg_attr` attribute into a list of attributes
89+
/// when the configuration predicate is true, or otherwise expand into an
90+
/// empty list of attributes.
91+
///
92+
/// Gives a compiler warning when the `cfg_attr` contains no attribtes and
93+
/// is in the original source file. Gives a compiler error if the syntax of
94+
/// the attribute is incorrect
95+
fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
8396
if !attr.check_name("cfg_attr") {
84-
return Some(attr);
97+
return vec![attr];
8598
}
8699

87-
let (cfg, path, tokens, span) = match attr.parse(self.sess, |parser| {
100+
let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| {
88101
parser.expect(&token::OpenDelim(token::Paren))?;
89-
let cfg = parser.parse_meta_item()?;
102+
103+
let cfg_predicate = parser.parse_meta_item()?;
90104
parser.expect(&token::Comma)?;
91-
let lo = parser.span.lo();
92-
let (path, tokens) = parser.parse_meta_item_unrestricted()?;
93-
parser.eat(&token::Comma); // Optional trailing comma
105+
106+
// Presumably, the majority of the time there will only be one attr.
107+
let mut expanded_attrs = Vec::with_capacity(1);
108+
109+
while !parser.check(&token::CloseDelim(token::Paren)) {
110+
let lo = parser.span.lo();
111+
let (path, tokens) = parser.parse_meta_item_unrestricted()?;
112+
expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo)));
113+
parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?;
114+
}
115+
94116
parser.expect(&token::CloseDelim(token::Paren))?;
95-
Ok((cfg, path, tokens, parser.prev_span.with_lo(lo)))
117+
Ok((cfg_predicate, expanded_attrs))
96118
}) {
97119
Ok(result) => result,
98120
Err(mut e) => {
99121
e.emit();
100-
return None;
122+
return Vec::new();
101123
}
102124
};
103125

104-
if attr::cfg_matches(&cfg, self.sess, self.features) {
105-
self.process_cfg_attr(ast::Attribute {
126+
if attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
127+
// We call `process_cfg_attr` recursively in case there's a
128+
// `cfg_attr` inside of another `cfg_attr`. E.g.
129+
// `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
130+
expanded_attrs.into_iter()
131+
.flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute {
106132
id: attr::mk_attr_id(),
107133
style: attr.style,
108134
path,
109135
tokens,
110136
is_sugared_doc: false,
111137
span,
112-
})
138+
}))
139+
.collect()
113140
} else {
114-
None
141+
Vec::new()
115142
}
116143
}
117144

118-
// Determine if a node with the given attributes should be included in this configuration.
145+
/// Determine if a node with the given attributes should be included in this configuration.
119146
pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
120147
attrs.iter().all(|attr| {
121148
if !is_cfg(attr) {
@@ -165,7 +192,7 @@ impl<'a> StripUnconfigured<'a> {
165192
})
166193
}
167194

168-
// Visit attributes on expression and statements (but not attributes on items in blocks).
195+
/// Visit attributes on expression and statements (but not attributes on items in blocks).
169196
fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
170197
// flag the offending attributes
171198
for attr in attrs.iter() {

src/libsyntax/parse/parser.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ impl<'a> Parser<'a> {
678678
/// Expect next token to be edible or inedible token. If edible,
679679
/// then consume it; if inedible, then return without consuming
680680
/// anything. Signal a fatal error if next token is unexpected.
681-
fn expect_one_of(&mut self,
681+
pub fn expect_one_of(&mut self,
682682
edible: &[token::Token],
683683
inedible: &[token::Token]) -> PResult<'a, ()>{
684684
fn tokens_to_string(tokens: &[TokenType]) -> String {

src/test/ui/cfg-attr-trailing-comma.rs

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/test/ui/cfg-attr-trailing-comma.stderr

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0658]: no_core is experimental (see issue #29639)
22
--> $DIR/cfg-attr-crate-2.rs:15:21
33
|
44
LL | #![cfg_attr(broken, no_core)] //~ ERROR no_core is experimental
5-
| ^^^^^^^^
5+
| ^^^^^^^
66
|
77
= help: add #![feature(no_core)] to the crate attributes to enable
88

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Test that cfg_attr doesn't emit any attributes when the
2+
// configuation variable is false. This mirrors `cfg-attr-multi-true.rs`
3+
4+
// compile-pass
5+
6+
#![warn(unused_must_use)]
7+
8+
#[cfg_attr(any(), deprecated, must_use)]
9+
struct Struct {}
10+
11+
impl Struct {
12+
fn new() -> Struct {
13+
Struct {}
14+
}
15+
}
16+
17+
fn main() {
18+
Struct::new();
19+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
//
11+
// compile-flags: --cfg broken
12+
13+
#![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental
14+
15+
fn main() { }
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0658]: no_core is experimental (see issue #29639)
2+
--> $DIR/cfg-attr-multi-invalid-1.rs:13:21
3+
|
4+
LL | #![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental
5+
| ^^^^^^^
6+
|
7+
= help: add #![feature(no_core)] to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0658`.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
//
11+
// compile-flags: --cfg broken
12+
13+
#![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental
14+
15+
fn main() { }
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0658]: no_core is experimental (see issue #29639)
2+
--> $DIR/cfg-attr-multi-invalid-2.rs:13:29
3+
|
4+
LL | #![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental
5+
| ^^^^^^^
6+
|
7+
= help: add #![feature(no_core)] to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)