about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-02-28 09:17:24 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-03-16 23:13:15 +0300
commit8371caf5ee13e775d2b2dc64c9b08e37dab49eda (patch)
tree630bb9b91f6f46469c6ec3eb51b21733c8e02e46 /src/libsyntax
parente2009ea5ffdacd767ea85d463fbe40d0e8b06951 (diff)
downloadrust-8371caf5ee13e775d2b2dc64c9b08e37dab49eda.tar.gz
rust-8371caf5ee13e775d2b2dc64c9b08e37dab49eda.zip
syntax: Do not accidentally treat multi-segment meta-items as single-segment
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/attr/builtin.rs94
-rw-r--r--src/libsyntax/attr/mod.rs77
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs11
-rw-r--r--src/libsyntax/feature_gate.rs33
-rw-r--r--src/libsyntax/test.rs5
5 files changed, 109 insertions, 111 deletions
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index f7a000935ca..f3caf16e1a7 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -1,6 +1,6 @@
 //! Parsing and validation of builtin attributes
 
-use crate::ast::{self, Attribute, MetaItem, Name, NestedMetaItemKind};
+use crate::ast::{self, Attribute, MetaItem, NestedMetaItemKind};
 use crate::feature_gate::{Features, GatedCfg};
 use crate::parse::ParseSess;
 
@@ -10,8 +10,8 @@ use syntax_pos::{symbol::Symbol, Span};
 use super::{mark_used, MetaItemKind};
 
 enum AttrError {
-    MultipleItem(Name),
-    UnknownMetaItem(Name, &'static [&'static str]),
+    MultipleItem(String),
+    UnknownMetaItem(String, &'static [&'static str]),
     MissingSince,
     MissingFeature,
     MultipleStabilityLevels,
@@ -155,10 +155,7 @@ pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool {
     attrs.iter().any(|item| {
         item.check_name("feature") &&
         item.meta_item_list().map(|list| {
-            list.iter().any(|mi| {
-                mi.word().map(|w| w.name() == feature_name)
-                         .unwrap_or(false)
-            })
+            list.iter().any(|mi| mi.is_word() && mi.check_name(feature_name))
         }).unwrap_or(false)
     })
 }
@@ -206,7 +203,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
             let meta = meta.as_ref().unwrap();
             let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
                 if item.is_some() {
-                    handle_errors(sess, meta.span, AttrError::MultipleItem(meta.name()));
+                    handle_errors(sess, meta.span, AttrError::MultipleItem(meta.ident.to_string()));
                     return false
                 }
                 if let Some(v) = meta.value_str() {
@@ -225,9 +222,9 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                     )+
                     for meta in metas {
                         if let Some(mi) = meta.meta_item() {
-                            match &*mi.name().as_str() {
+                            match mi.ident_str() {
                                 $(
-                                    stringify!($name)
+                                    Some(stringify!($name))
                                         => if !get(mi, &mut $name) { continue 'outer },
                                 )+
                                 _ => {
@@ -235,7 +232,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                                     handle_errors(
                                         sess,
                                         mi.span,
-                                        AttrError::UnknownMetaItem(mi.name(), expected),
+                                        AttrError::UnknownMetaItem(mi.ident.to_string(), expected),
                                     );
                                     continue 'outer
                                 }
@@ -255,7 +252,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                 }
             }
 
-            match &*meta.name().as_str() {
+            match meta.ident_str().expect("not a stability level") {
                 "rustc_deprecated" => {
                     if rustc_depr.is_some() {
                         span_err!(diagnostic, item_sp, E0540,
@@ -309,16 +306,16 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                     let mut issue = None;
                     for meta in metas {
                         if let Some(mi) = meta.meta_item() {
-                            match &*mi.name().as_str() {
-                                "feature" => if !get(mi, &mut feature) { continue 'outer },
-                                "reason" => if !get(mi, &mut reason) { continue 'outer },
-                                "issue" => if !get(mi, &mut issue) { continue 'outer },
+                            match mi.ident_str() {
+                                Some("feature") => if !get(mi, &mut feature) { continue 'outer },
+                                Some("reason") => if !get(mi, &mut reason) { continue 'outer },
+                                Some("issue") => if !get(mi, &mut issue) { continue 'outer },
                                 _ => {
                                     handle_errors(
                                         sess,
                                         meta.span,
                                         AttrError::UnknownMetaItem(
-                                            mi.name(),
+                                            mi.ident.to_string(),
                                             &["feature", "reason", "issue"]
                                         ),
                                     );
@@ -380,15 +377,17 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                     for meta in metas {
                         match &meta.node {
                             NestedMetaItemKind::MetaItem(mi) => {
-                                match &*mi.name().as_str() {
-                                    "feature" => if !get(mi, &mut feature) { continue 'outer },
-                                    "since" => if !get(mi, &mut since) { continue 'outer },
+                                match mi.ident_str() {
+                                    Some("feature") =>
+                                        if !get(mi, &mut feature) { continue 'outer },
+                                    Some("since") =>
+                                        if !get(mi, &mut since) { continue 'outer },
                                     _ => {
                                         handle_errors(
                                             sess,
                                             meta.span,
                                             AttrError::UnknownMetaItem(
-                                                mi.name(), &["since", "note"],
+                                                mi.ident.to_string(), &["since", "note"],
                                             ),
                                         );
                                         continue 'outer
@@ -502,7 +501,8 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
                 true
             }
             MetaItemKind::NameValue(..) | MetaItemKind::Word => {
-                sess.config.contains(&(cfg.name(), cfg.value_str()))
+                let ident = cfg.ident().expect("multi-segment cfg predicate");
+                sess.config.contains(&(ident.name, cfg.value_str()))
             }
         }
     })
@@ -532,14 +532,14 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
 
             // The unwraps below may look dangerous, but we've already asserted
             // that they won't fail with the loop above.
-            match &*cfg.name().as_str() {
-                "any" => mis.iter().any(|mi| {
+            match cfg.ident_str() {
+                Some("any") => mis.iter().any(|mi| {
                     eval_condition(mi.meta_item().unwrap(), sess, eval)
                 }),
-                "all" => mis.iter().all(|mi| {
+                Some("all") => mis.iter().all(|mi| {
                     eval_condition(mi.meta_item().unwrap(), sess, eval)
                 }),
-                "not" => {
+                Some("not") => {
                     if mis.len() != 1 {
                         span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern");
                         return false;
@@ -547,8 +547,9 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
 
                     !eval_condition(mis[0].meta_item().unwrap(), sess, eval)
                 },
-                p => {
-                    span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p);
+                _ => {
+                    span_err!(sess.span_diagnostic, cfg.span, E0537,
+                              "invalid predicate `{}`", cfg.ident);
                     false
                 }
             }
@@ -602,7 +603,9 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess,
             MetaItemKind::List(list) => {
                 let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
                     if item.is_some() {
-                        handle_errors(sess, meta.span, AttrError::MultipleItem(meta.name()));
+                        handle_errors(
+                            sess, meta.span, AttrError::MultipleItem(meta.ident.to_string())
+                        );
                         return false
                     }
                     if let Some(v) = meta.value_str() {
@@ -632,14 +635,15 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess,
                 for meta in list {
                     match &meta.node {
                         NestedMetaItemKind::MetaItem(mi) => {
-                            match &*mi.name().as_str() {
-                                "since" => if !get(mi, &mut since) { continue 'outer },
-                                "note" => if !get(mi, &mut note) { continue 'outer },
+                            match mi.ident_str() {
+                                Some("since") => if !get(mi, &mut since) { continue 'outer },
+                                Some("note") => if !get(mi, &mut note) { continue 'outer },
                                 _ => {
                                     handle_errors(
                                         sess,
-                                        meta.span,
-                                        AttrError::UnknownMetaItem(mi.name(), &["since", "note"]),
+                                        meta.span(),
+                                        AttrError::UnknownMetaItem(mi.ident.to_string(),
+                                                                   &["since", "note"]),
                                     );
                                     continue 'outer
                                 }
@@ -724,19 +728,13 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
                 }
 
                 let mut recognised = false;
-                if let Some(mi) = item.word() {
-                    let word = &*mi.name().as_str();
-                    let hint = match word {
-                        "C" => Some(ReprC),
-                        "packed" => Some(ReprPacked(1)),
-                        "simd" => Some(ReprSimd),
-                        "transparent" => Some(ReprTransparent),
-                        _ => match int_type_of_word(word) {
-                            Some(ity) => Some(ReprInt(ity)),
-                            None => {
-                                None
-                            }
-                        }
+                if item.is_word() {
+                    let hint = match item.ident_str() {
+                        Some("C") => Some(ReprC),
+                        Some("packed") => Some(ReprPacked(1)),
+                        Some("simd") => Some(ReprSimd),
+                        Some("transparent") => Some(ReprTransparent),
+                        name => name.and_then(|name| int_type_of_word(name)).map(ReprInt),
                     };
 
                     if let Some(h) = hint {
@@ -782,7 +780,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
                     }
                 } else {
                     if let Some(meta_item) = item.meta_item() {
-                        if meta_item.name() == "align" {
+                        if meta_item.check_name("align") {
                             if let MetaItemKind::NameValue(ref value) = meta_item.node {
                                 recognised = true;
                                 let mut err = struct_span_err!(diagnostic, item.span, E0693,
diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs
index b5fc8507314..857325681c6 100644
--- a/src/libsyntax/attr/mod.rs
+++ b/src/libsyntax/attr/mod.rs
@@ -90,10 +90,12 @@ impl NestedMetaItem {
         self.meta_item().map_or(false, |meta_item| meta_item.check_name(name))
     }
 
-    /// Returns the name of the meta item, e.g., `foo` in `#[foo]`,
-    /// `#[foo="bar"]` and `#[foo(bar)]`, if self is a MetaItem
-    pub fn name(&self) -> Option<Name> {
-        self.meta_item().and_then(|meta_item| Some(meta_item.name()))
+    /// For a single-segment meta-item returns its name, otherwise returns `None`.
+    pub fn ident(&self) -> Option<Ident> {
+        self.meta_item().and_then(|meta_item| meta_item.ident())
+    }
+    pub fn ident_str(&self) -> Option<&str> {
+        self.ident().map(|name| name.as_str().get())
     }
 
     /// Gets the string value if self is a MetaItem and the MetaItem is a
@@ -108,25 +110,14 @@ impl NestedMetaItem {
             |meta_item| meta_item.meta_item_list().and_then(
                 |meta_item_list| {
                     if meta_item_list.len() == 1 {
-                        let nested_item = &meta_item_list[0];
-                        if nested_item.is_literal() {
-                            Some((meta_item.name(), nested_item.literal().unwrap()))
-                        } else {
-                            None
+                        if let Some(ident) = meta_item.ident() {
+                            if let Some(lit) = meta_item_list[0].literal() {
+                                return Some((ident.name, lit));
+                            }
                         }
                     }
-                    else {
-                        None
-                    }}))
-    }
-
-    /// Returns a MetaItem if self is a MetaItem with Kind Word.
-    pub fn word(&self) -> Option<&MetaItem> {
-        self.meta_item().and_then(|meta_item| if meta_item.is_word() {
-            Some(meta_item)
-        } else {
-            None
-        })
+                    None
+                }))
     }
 
     /// Gets a list of inner meta items from a list MetaItem type.
@@ -146,7 +137,7 @@ impl NestedMetaItem {
 
     /// Returns `true` if self is a MetaItem and the meta item is a word.
     pub fn is_word(&self) -> bool {
-        self.word().is_some()
+        self.meta_item().map_or(false, |meta_item| meta_item.is_word())
     }
 
     /// Returns `true` if self is a MetaItem and the meta item is a ValueString.
@@ -160,10 +151,6 @@ impl NestedMetaItem {
     }
 }
 
-fn name_from_path(path: &Path) -> Name {
-    path.segments.last().expect("empty path in attribute").ident.name
-}
-
 impl Attribute {
     /// Returns `true` if the attribute's path matches the argument. If it matches, then the
     /// attribute is marked as used.
@@ -177,10 +164,16 @@ impl Attribute {
         matches
     }
 
-    /// Returns the **last** segment of the name of this attribute.
-    /// e.g., `foo` for `#[foo]`, `skip` for `#[rustfmt::skip]`.
-    pub fn name(&self) -> Name {
-        name_from_path(&self.path)
+    /// For a single-segment attribute returns its name, otherwise returns `None`.
+    pub fn ident(&self) -> Option<Ident> {
+        if self.path.segments.len() == 1 {
+            Some(self.path.segments[0].ident)
+        } else {
+            None
+        }
+    }
+    pub fn ident_str(&self) -> Option<&str> {
+        self.ident().map(|name| name.as_str().get())
     }
 
     pub fn value_str(&self) -> Option<Symbol> {
@@ -195,7 +188,7 @@ impl Attribute {
     }
 
     pub fn is_word(&self) -> bool {
-        self.path.segments.len() == 1 && self.tokens.is_empty()
+        self.tokens.is_empty()
     }
 
     pub fn span(&self) -> Span {
@@ -213,8 +206,16 @@ impl Attribute {
 }
 
 impl MetaItem {
-    pub fn name(&self) -> Name {
-        name_from_path(&self.ident)
+    /// For a single-segment meta-item returns its name, otherwise returns `None`.
+    pub fn ident(&self) -> Option<Ident> {
+        if self.ident.segments.len() == 1 {
+            Some(self.ident.segments[0].ident)
+        } else {
+            None
+        }
+    }
+    pub fn ident_str(&self) -> Option<&str> {
+        self.ident().map(|name| name.as_str().get())
     }
 
     // #[attribute(name = "value")]
@@ -255,7 +256,7 @@ impl MetaItem {
     pub fn span(&self) -> Span { self.span }
 
     pub fn check_name(&self, name: &str) -> bool {
-        self.name() == name
+        self.ident == name
     }
 
     pub fn is_value_str(&self) -> bool {
@@ -265,14 +266,6 @@ impl MetaItem {
     pub fn is_meta_item_list(&self) -> bool {
         self.meta_item_list().is_some()
     }
-
-    pub fn is_scoped(&self) -> Option<Ident> {
-        if self.ident.segments.len() > 1 {
-            Some(self.ident.segments[0].ident)
-        } else {
-            None
-        }
-    }
 }
 
 impl Attribute {
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index bd64bb01021..12912044e4e 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -380,9 +380,14 @@ pub fn compile(
             .map(|attr| attr
                 .meta_item_list()
                 .map(|list| list.iter()
-                    .map(|it| it.name().unwrap_or_else(|| sess.span_diagnostic.span_bug(
-                        it.span, "allow internal unstable expects feature names",
-                    )))
+                    .filter_map(|it| {
+                        let name = it.ident().map(|ident| ident.name);
+                        if name.is_none() {
+                            sess.span_diagnostic.span_err(it.span(),
+                                "allow internal unstable expects feature names")
+                        }
+                        name
+                    })
                     .collect::<Vec<Symbol>>().into()
                 )
                 .unwrap_or_else(|| {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 280b17da0be..4acacf2b68e 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -1289,9 +1289,8 @@ pub struct GatedCfg {
 
 impl GatedCfg {
     pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
-        let name = cfg.name().as_str();
         GATED_CFGS.iter()
-                  .position(|info| info.0 == name)
+                  .position(|info| cfg.check_name(info.0))
                   .map(|idx| {
                       GatedCfg {
                           span: cfg.span,
@@ -1342,16 +1341,16 @@ macro_rules! gate_feature {
 impl<'a> Context<'a> {
     fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
         debug!("check_attribute(attr = {:?})", attr);
-        let name = attr.name().as_str();
+        let name = attr.ident_str();
         for &(n, ty, _template, ref gateage) in BUILTIN_ATTRIBUTES {
-            if name == n {
+            if name == Some(n) {
                 if let Gated(_, name, desc, ref has_feature) = *gateage {
                     if !attr.span.allows_unstable(name) {
                         gate_feature_fn!(
                             self, has_feature, attr.span, name, desc, GateStrength::Hard
                         );
                     }
-                } else if name == "doc" {
+                } else if n == "doc" {
                     if let Some(content) = attr.meta_item_list() {
                         if content.iter().any(|c| c.check_name("include")) {
                             gate_feature!(self, external_doc, attr.span,
@@ -1374,7 +1373,7 @@ impl<'a> Context<'a> {
             }
         }
         if !attr::is_known(attr) {
-            if name.starts_with("rustc_") {
+            if name.map_or(false, |name| name.starts_with("rustc_")) {
                 let msg = "unless otherwise specified, attributes with the prefix `rustc_` \
                            are reserved for internal compiler diagnostics";
                 gate_feature!(self, rustc_attrs, attr.span, msg);
@@ -2055,13 +2054,12 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
         };
 
         for mi in list {
-            let name = if let Some(word) = mi.word() {
-                word.name()
-            } else {
-                continue
+            let name = match mi.ident_str() {
+                Some(name) if mi.is_word() => name,
+                _ => continue,
             };
 
-            if incomplete_features.iter().any(|f| *f == name.as_str()) {
+            if incomplete_features.iter().any(|f| *f == name) {
                 span_handler.struct_span_warn(
                     mi.span,
                     &format!(
@@ -2101,12 +2099,13 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
         };
 
         for mi in list {
-            let name = if let Some(word) = mi.word() {
-                word.name()
-            } else {
-                span_err!(span_handler, mi.span, E0556,
-                          "malformed feature, expected just one word");
-                continue
+            let name = match mi.ident() {
+                Some(ident) if mi.is_word() => ident.name,
+                _ => {
+                    span_err!(span_handler, mi.span, E0556,
+                            "malformed feature, expected just one word");
+                    continue
+                }
             };
 
             if let Some(edition) = edition_enabled_features.get(&name) {
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 56290fa771b..3afd55899c8 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -438,6 +438,9 @@ fn get_test_runner(sd: &errors::Handler, krate: &ast::Crate) -> Option<ast::Path
             sd.span_fatal(test_attr.span(),
                 "#![test_runner(..)] accepts exactly 1 argument").raise()
         }
-        meta_list[0].word().as_ref().unwrap().ident.clone()
+        match meta_list[0].meta_item() {
+            Some(meta_item) if meta_item.is_word() => meta_item.ident.clone(),
+            _ => sd.span_fatal(test_attr.span, "`test_runner` argument must be a path").raise()
+        }
     })
 }