Skip to content

Commit b0a05c5

Browse files
committed
Validate syntax of cfg attributes
1 parent 780b0c7 commit b0a05c5

File tree

4 files changed

+139
-13
lines changed

4 files changed

+139
-13
lines changed

src/libsyntax/attr/builtin.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,21 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
433433
if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) {
434434
gated_cfg.check_and_emit(sess, feats);
435435
}
436-
sess.config.contains(&(cfg.name(), cfg.value_str()))
436+
let error = |span, msg| { sess.span_diagnostic.span_err(span, msg); true };
437+
if cfg.ident.segments.len() != 1 {
438+
return error(cfg.ident.span, "`cfg` predicate key must be an identifier");
439+
}
440+
match &cfg.node {
441+
MetaItemKind::List(..) => {
442+
error(cfg.span, "unexpected parentheses after `cfg` predicate key")
443+
}
444+
MetaItemKind::NameValue(lit) if !lit.node.is_str() => {
445+
error(lit.span, "literal in `cfg` predicate value must be a string")
446+
}
447+
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
448+
sess.config.contains(&(cfg.name(), cfg.value_str()))
449+
}
450+
}
437451
})
438452
}
439453

src/libsyntax/config.rs

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,25 +116,45 @@ impl<'a> StripUnconfigured<'a> {
116116
// Determine if a node with the given attributes should be included in this configuration.
117117
pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
118118
attrs.iter().all(|attr| {
119-
let mis = if !is_cfg(attr) {
119+
if !is_cfg(attr) {
120120
return true;
121-
} else if let Some(mis) = attr.meta_item_list() {
122-
mis
121+
}
122+
123+
let error = |span, msg, suggestion: &str| {
124+
let mut err = self.sess.span_diagnostic.struct_span_err(span, msg);
125+
if !suggestion.is_empty() {
126+
err.span_suggestion(span, "expected syntax is", suggestion.into());
127+
}
128+
err.emit();
129+
true
130+
};
131+
132+
let meta_item = if let Some(meta_item) = attr.meta() {
133+
meta_item
123134
} else {
124-
return true;
135+
// Not a well-formed meta-item. Why? We don't know.
136+
return error(attr.span, "`cfg` is not a well-formed meta-item",
137+
"#[cfg(/* predicate */)]");
138+
};
139+
let nested_meta_items = if let Some(nested_meta_items) = meta_item.meta_item_list() {
140+
nested_meta_items
141+
} else {
142+
return error(meta_item.span, "`cfg` is not followed by parentheses",
143+
"cfg(/* predicate */)");
125144
};
126145

127-
if mis.len() != 1 {
128-
self.sess.span_diagnostic.span_err(attr.span, "expected 1 cfg-pattern");
129-
return true;
146+
if nested_meta_items.is_empty() {
147+
return error(meta_item.span, "`cfg` predicate is not specified", "");
148+
} else if nested_meta_items.len() > 1 {
149+
return error(nested_meta_items.last().unwrap().span,
150+
"multiple `cfg` predicates are specified", "");
130151
}
131152

132-
if !mis[0].is_meta_item() {
133-
self.sess.span_diagnostic.span_err(mis[0].span, "unexpected literal");
134-
return true;
153+
match nested_meta_items[0].meta_item() {
154+
Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features),
155+
None => error(nested_meta_items[0].span,
156+
"`cfg` predicate key cannot be a literal", ""),
135157
}
136-
137-
attr::cfg_matches(mis[0].meta_item().unwrap(), self.sess, self.features)
138158
})
139159
}
140160

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#[cfg] //~ ERROR `cfg` is not followed by parentheses
2+
struct S1;
3+
4+
#[cfg = 10] //~ ERROR `cfg` is not followed by parentheses
5+
struct S2;
6+
7+
#[cfg()] //~ ERROR `cfg` predicate is not specified
8+
struct S3;
9+
10+
#[cfg(a, b)] //~ ERROR multiple `cfg` predicates are specified
11+
struct S4;
12+
13+
#[cfg("str")] //~ ERROR `cfg` predicate key cannot be a literal
14+
struct S5;
15+
16+
#[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier
17+
struct S6;
18+
19+
#[cfg(a())] //~ ERROR invalid predicate `a`
20+
struct S7;
21+
22+
#[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string
23+
struct S8;
24+
25+
macro_rules! generate_s9 {
26+
($expr: expr) => {
27+
#[cfg(feature = $expr)] //~ ERROR `cfg` is not a well-formed meta-item
28+
struct S9;
29+
}
30+
}
31+
32+
generate_s9!(concat!("nonexistent"));
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
error: `cfg` is not followed by parentheses
2+
--> $DIR/cfg-attr-syntax-validation.rs:1:1
3+
|
4+
LL | #[cfg] //~ ERROR `cfg` is not followed by parentheses
5+
| ^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
6+
7+
error: `cfg` is not followed by parentheses
8+
--> $DIR/cfg-attr-syntax-validation.rs:4:1
9+
|
10+
LL | #[cfg = 10] //~ ERROR `cfg` is not followed by parentheses
11+
| ^^^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
12+
13+
error: `cfg` predicate is not specified
14+
--> $DIR/cfg-attr-syntax-validation.rs:7:1
15+
|
16+
LL | #[cfg()] //~ ERROR `cfg` predicate is not specified
17+
| ^^^^^^^^
18+
19+
error: multiple `cfg` predicates are specified
20+
--> $DIR/cfg-attr-syntax-validation.rs:10:10
21+
|
22+
LL | #[cfg(a, b)] //~ ERROR multiple `cfg` predicates are specified
23+
| ^
24+
25+
error: `cfg` predicate key cannot be a literal
26+
--> $DIR/cfg-attr-syntax-validation.rs:13:7
27+
|
28+
LL | #[cfg("str")] //~ ERROR `cfg` predicate key cannot be a literal
29+
| ^^^^^
30+
31+
error: `cfg` predicate key must be an identifier
32+
--> $DIR/cfg-attr-syntax-validation.rs:16:7
33+
|
34+
LL | #[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier
35+
| ^^^^
36+
37+
error[E0537]: invalid predicate `a`
38+
--> $DIR/cfg-attr-syntax-validation.rs:19:7
39+
|
40+
LL | #[cfg(a())] //~ ERROR invalid predicate `a`
41+
| ^^^
42+
43+
error: literal in `cfg` predicate value must be a string
44+
--> $DIR/cfg-attr-syntax-validation.rs:22:11
45+
|
46+
LL | #[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string
47+
| ^^
48+
49+
error: `cfg` is not a well-formed meta-item
50+
--> $DIR/cfg-attr-syntax-validation.rs:27:9
51+
|
52+
LL | #[cfg(feature = $expr)] //~ ERROR `cfg` is not a well-formed meta-item
53+
| ^^^^^^^^^^^^^^^^^^^^^^^ help: expected syntax is: `#[cfg(/* predicate */)]`
54+
...
55+
LL | generate_s9!(concat!("nonexistent"));
56+
| ------------------------------------- in this macro invocation
57+
58+
error: aborting due to 9 previous errors
59+
60+
For more information about this error, try `rustc --explain E0537`.

0 commit comments

Comments
 (0)