Skip to content

Commit fbc120c

Browse files
petrochenkovpietroalbini
authored andcommitted
Validate syntax of cfg attributes
1 parent 309e21c commit fbc120c

File tree

4 files changed

+139
-13
lines changed

4 files changed

+139
-13
lines changed

src/libsyntax/attr/builtin.rs

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

src/libsyntax/config.rs

+32-12
Original file line numberDiff line numberDiff line change
@@ -123,25 +123,45 @@ impl<'a> StripUnconfigured<'a> {
123123
return false;
124124
}
125125

126-
let mis = if !is_cfg(attr) {
126+
if !is_cfg(attr) {
127127
return true;
128-
} else if let Some(mis) = attr.meta_item_list() {
129-
mis
128+
}
129+
130+
let error = |span, msg, suggestion: &str| {
131+
let mut err = self.sess.span_diagnostic.struct_span_err(span, msg);
132+
if !suggestion.is_empty() {
133+
err.span_suggestion(span, "expected syntax is", suggestion.into());
134+
}
135+
err.emit();
136+
true
137+
};
138+
139+
let meta_item = if let Some(meta_item) = attr.meta() {
140+
meta_item
130141
} else {
131-
return true;
142+
// Not a well-formed meta-item. Why? We don't know.
143+
return error(attr.span, "`cfg` is not a well-formed meta-item",
144+
"#[cfg(/* predicate */)]");
145+
};
146+
let nested_meta_items = if let Some(nested_meta_items) = meta_item.meta_item_list() {
147+
nested_meta_items
148+
} else {
149+
return error(meta_item.span, "`cfg` is not followed by parentheses",
150+
"cfg(/* predicate */)");
132151
};
133152

134-
if mis.len() != 1 {
135-
self.sess.span_diagnostic.span_err(attr.span, "expected 1 cfg-pattern");
136-
return true;
153+
if nested_meta_items.is_empty() {
154+
return error(meta_item.span, "`cfg` predicate is not specified", "");
155+
} else if nested_meta_items.len() > 1 {
156+
return error(nested_meta_items.last().unwrap().span,
157+
"multiple `cfg` predicates are specified", "");
137158
}
138159

139-
if !mis[0].is_meta_item() {
140-
self.sess.span_diagnostic.span_err(mis[0].span, "unexpected literal");
141-
return true;
160+
match nested_meta_items[0].meta_item() {
161+
Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features),
162+
None => error(nested_meta_items[0].span,
163+
"`cfg` predicate key cannot be a literal", ""),
142164
}
143-
144-
attr::cfg_matches(mis[0].meta_item().unwrap(), self.sess, self.features)
145165
})
146166
}
147167

+32
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"));
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)