diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2018-09-02 00:13:22 +0300 |
|---|---|---|
| committer | Pietro Albini <pietro@pietroalbini.org> | 2018-09-07 20:30:19 +0200 |
| commit | fbc120c5ed5610e6a329dcce34f048832ec51e29 (patch) | |
| tree | df02ce1aaa5acd0879753582b669775fff4f3c1d | |
| parent | 309e21c88d0893bdcd747b4924678d117ac36da5 (diff) | |
| download | rust-fbc120c5ed5610e6a329dcce34f048832ec51e29.tar.gz rust-fbc120c5ed5610e6a329dcce34f048832ec51e29.zip | |
Validate syntax of `cfg` attributes
| -rw-r--r-- | src/libsyntax/attr/builtin.rs | 16 | ||||
| -rw-r--r-- | src/libsyntax/config.rs | 44 | ||||
| -rw-r--r-- | src/test/ui/cfg-attr-syntax-validation.rs | 32 | ||||
| -rw-r--r-- | src/test/ui/cfg-attr-syntax-validation.stderr | 60 |
4 files changed, 139 insertions, 13 deletions
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index ecd52a62eab..da11c3d652c 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -435,7 +435,21 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { gated_cfg.check_and_emit(sess, feats); } - sess.config.contains(&(cfg.name(), cfg.value_str())) + let error = |span, msg| { sess.span_diagnostic.span_err(span, msg); true }; + if cfg.ident.segments.len() != 1 { + return error(cfg.ident.span, "`cfg` predicate key must be an identifier"); + } + match &cfg.node { + MetaItemKind::List(..) => { + error(cfg.span, "unexpected parentheses after `cfg` predicate key") + } + MetaItemKind::NameValue(lit) if !lit.node.is_str() => { + error(lit.span, "literal in `cfg` predicate value must be a string") + } + MetaItemKind::NameValue(..) | MetaItemKind::Word => { + sess.config.contains(&(cfg.name(), cfg.value_str())) + } + } }) } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 33643789139..d6ecf87a65d 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -123,25 +123,45 @@ impl<'a> StripUnconfigured<'a> { return false; } - let mis = if !is_cfg(attr) { + if !is_cfg(attr) { return true; - } else if let Some(mis) = attr.meta_item_list() { - mis + } + + let error = |span, msg, suggestion: &str| { + let mut err = self.sess.span_diagnostic.struct_span_err(span, msg); + if !suggestion.is_empty() { + err.span_suggestion(span, "expected syntax is", suggestion.into()); + } + err.emit(); + true + }; + + let meta_item = if let Some(meta_item) = attr.meta() { + meta_item } else { - return true; + // Not a well-formed meta-item. Why? We don't know. + return error(attr.span, "`cfg` is not a well-formed meta-item", + "#[cfg(/* predicate */)]"); + }; + let nested_meta_items = if let Some(nested_meta_items) = meta_item.meta_item_list() { + nested_meta_items + } else { + return error(meta_item.span, "`cfg` is not followed by parentheses", + "cfg(/* predicate */)"); }; - if mis.len() != 1 { - self.sess.span_diagnostic.span_err(attr.span, "expected 1 cfg-pattern"); - return true; + if nested_meta_items.is_empty() { + return error(meta_item.span, "`cfg` predicate is not specified", ""); + } else if nested_meta_items.len() > 1 { + return error(nested_meta_items.last().unwrap().span, + "multiple `cfg` predicates are specified", ""); } - if !mis[0].is_meta_item() { - self.sess.span_diagnostic.span_err(mis[0].span, "unexpected literal"); - return true; + match nested_meta_items[0].meta_item() { + Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features), + None => error(nested_meta_items[0].span, + "`cfg` predicate key cannot be a literal", ""), } - - attr::cfg_matches(mis[0].meta_item().unwrap(), self.sess, self.features) }) } diff --git a/src/test/ui/cfg-attr-syntax-validation.rs b/src/test/ui/cfg-attr-syntax-validation.rs new file mode 100644 index 00000000000..06a22eff25c --- /dev/null +++ b/src/test/ui/cfg-attr-syntax-validation.rs @@ -0,0 +1,32 @@ +#[cfg] //~ ERROR `cfg` is not followed by parentheses +struct S1; + +#[cfg = 10] //~ ERROR `cfg` is not followed by parentheses +struct S2; + +#[cfg()] //~ ERROR `cfg` predicate is not specified +struct S3; + +#[cfg(a, b)] //~ ERROR multiple `cfg` predicates are specified +struct S4; + +#[cfg("str")] //~ ERROR `cfg` predicate key cannot be a literal +struct S5; + +#[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier +struct S6; + +#[cfg(a())] //~ ERROR invalid predicate `a` +struct S7; + +#[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string +struct S8; + +macro_rules! generate_s9 { + ($expr: expr) => { + #[cfg(feature = $expr)] //~ ERROR `cfg` is not a well-formed meta-item + struct S9; + } +} + +generate_s9!(concat!("nonexistent")); diff --git a/src/test/ui/cfg-attr-syntax-validation.stderr b/src/test/ui/cfg-attr-syntax-validation.stderr new file mode 100644 index 00000000000..7773fdb8cf9 --- /dev/null +++ b/src/test/ui/cfg-attr-syntax-validation.stderr @@ -0,0 +1,60 @@ +error: `cfg` is not followed by parentheses + --> $DIR/cfg-attr-syntax-validation.rs:1:1 + | +LL | #[cfg] //~ ERROR `cfg` is not followed by parentheses + | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + +error: `cfg` is not followed by parentheses + --> $DIR/cfg-attr-syntax-validation.rs:4:1 + | +LL | #[cfg = 10] //~ ERROR `cfg` is not followed by parentheses + | ^^^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + +error: `cfg` predicate is not specified + --> $DIR/cfg-attr-syntax-validation.rs:7:1 + | +LL | #[cfg()] //~ ERROR `cfg` predicate is not specified + | ^^^^^^^^ + +error: multiple `cfg` predicates are specified + --> $DIR/cfg-attr-syntax-validation.rs:10:10 + | +LL | #[cfg(a, b)] //~ ERROR multiple `cfg` predicates are specified + | ^ + +error: `cfg` predicate key cannot be a literal + --> $DIR/cfg-attr-syntax-validation.rs:13:7 + | +LL | #[cfg("str")] //~ ERROR `cfg` predicate key cannot be a literal + | ^^^^^ + +error: `cfg` predicate key must be an identifier + --> $DIR/cfg-attr-syntax-validation.rs:16:7 + | +LL | #[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier + | ^^^^ + +error[E0537]: invalid predicate `a` + --> $DIR/cfg-attr-syntax-validation.rs:19:7 + | +LL | #[cfg(a())] //~ ERROR invalid predicate `a` + | ^^^ + +error: literal in `cfg` predicate value must be a string + --> $DIR/cfg-attr-syntax-validation.rs:22:11 + | +LL | #[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string + | ^^ + +error: `cfg` is not a well-formed meta-item + --> $DIR/cfg-attr-syntax-validation.rs:27:9 + | +LL | #[cfg(feature = $expr)] //~ ERROR `cfg` is not a well-formed meta-item + | ^^^^^^^^^^^^^^^^^^^^^^^ help: expected syntax is: `#[cfg(/* predicate */)]` +... +LL | generate_s9!(concat!("nonexistent")); + | ------------------------------------- in this macro invocation + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0537`. |
