about summary refs log tree commit diff
path: root/src/libsyntax/attr
diff options
context:
space:
mode:
authorNicholas Nethercote <nnethercote@mozilla.com>2019-10-24 06:33:12 +1100
committerNicholas Nethercote <nnethercote@mozilla.com>2019-11-06 23:05:07 +1100
commiteea6f23a0ed67fd8c6b8e1b02cda3628fee56b2f (patch)
treeeffdb244138f311440b21c9fd52e4028edb575ea /src/libsyntax/attr
parent69bc4aba785e071740d2d46f109623b9951aae5d (diff)
downloadrust-eea6f23a0ed67fd8c6b8e1b02cda3628fee56b2f.tar.gz
rust-eea6f23a0ed67fd8c6b8e1b02cda3628fee56b2f.zip
Make doc comments cheaper with `AttrKind`.
`AttrKind` is a new type with two variants, `Normal` and `DocComment`. It's a
big performance win (over 10% in some cases) because `DocComment` lets doc
comments (which are common) be represented very cheaply.

`Attribute` gets some new helper methods to ease the transition:
- `has_name()`: check if the attribute name matches a single `Symbol`; for
  `DocComment` variants it succeeds if the symbol is `sym::doc`.
- `is_doc_comment()`: check if it has a `DocComment` kind.
- `{get,unwrap}_normal_item()`: extract the item from a `Normal` variant;
  panic otherwise.

Fixes #60935.
Diffstat (limited to 'src/libsyntax/attr')
-rw-r--r--src/libsyntax/attr/builtin.rs8
-rw-r--r--src/libsyntax/attr/mod.rs110
2 files changed, 83 insertions, 35 deletions
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index e77d9ef326a..787d69f5e99 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -228,7 +228,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
             sym::stable,
             sym::rustc_promotable,
             sym::rustc_allow_const_fn_ptr,
-        ].iter().any(|&s| attr.item.path == s) {
+        ].iter().any(|&s| attr.has_name(s)) {
             continue // not a stability level
         }
 
@@ -236,10 +236,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
 
         let meta = attr.meta();
 
-        if attr.item.path == sym::rustc_promotable {
+        if attr.has_name(sym::rustc_promotable) {
             promotable = true;
         }
-        if attr.item.path == sym::rustc_allow_const_fn_ptr {
+        if attr.has_name(sym::rustc_allow_const_fn_ptr) {
             allow_const_fn_ptr = true;
         }
         // attributes with data
@@ -778,7 +778,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
 
     let mut acc = Vec::new();
     let diagnostic = &sess.span_diagnostic;
-    if attr.item.path == sym::repr {
+    if attr.has_name(sym::repr) {
         if let Some(items) = attr.meta_item_list() {
             mark_used(attr);
             for item in items {
diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs
index 0c46c501be9..c663995eb8f 100644
--- a/src/libsyntax/attr/mod.rs
+++ b/src/libsyntax/attr/mod.rs
@@ -9,7 +9,7 @@ pub use StabilityLevel::*;
 pub use crate::ast::Attribute;
 
 use crate::ast;
-use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment};
+use crate::ast::{AttrItem, AttrId, AttrKind, AttrStyle, Name, Ident, Path, PathSegment};
 use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
 use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
 use crate::mut_visit::visit_clobber;
@@ -145,12 +145,17 @@ impl NestedMetaItem {
 }
 
 impl Attribute {
+    pub fn has_name(&self, name: Symbol) -> bool {
+        match self.kind {
+            AttrKind::Normal(ref item) => item.path == name,
+            AttrKind::DocComment(_) => name == sym::doc,
+        }
+    }
+
     /// Returns `true` if the attribute's path matches the argument. If it matches, then the
     /// attribute is marked as used.
-    ///
-    /// To check the attribute name without marking it used, use the `path` field directly.
     pub fn check_name(&self, name: Symbol) -> bool {
-        let matches = self.item.path == name;
+        let matches = self.has_name(name);
         if matches {
             mark_used(self);
         }
@@ -159,10 +164,15 @@ impl Attribute {
 
     /// For a single-segment attribute, returns its name; otherwise, returns `None`.
     pub fn ident(&self) -> Option<Ident> {
-        if self.item.path.segments.len() == 1 {
-            Some(self.item.path.segments[0].ident)
-        } else {
-            None
+        match self.kind {
+            AttrKind::Normal(ref item) => {
+                if item.path.segments.len() == 1 {
+                    Some(item.path.segments[0].ident)
+                } else {
+                    None
+                }
+            }
+            AttrKind::DocComment(_) => Some(Ident::new(sym::doc, self.span)),
         }
     }
     pub fn name_or_empty(&self) -> Symbol {
@@ -170,18 +180,32 @@ impl Attribute {
     }
 
     pub fn value_str(&self) -> Option<Symbol> {
-        self.meta().and_then(|meta| meta.value_str())
+        match self.kind {
+            AttrKind::Normal(ref item) => {
+                item.meta(self.span).and_then(|meta| meta.value_str())
+            }
+            AttrKind::DocComment(comment) => Some(comment),
+        }
     }
 
     pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
-        match self.meta() {
-            Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list),
-            _ => None
+        match self.kind {
+            AttrKind::Normal(ref item) => {
+                match item.meta(self.span) {
+                    Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list),
+                    _ => None
+                }
+            }
+            AttrKind::DocComment(_) => None,
         }
     }
 
     pub fn is_word(&self) -> bool {
-        self.item.tokens.is_empty()
+        if let AttrKind::Normal(item) = &self.kind {
+            item.tokens.is_empty()
+        } else {
+            false
+        }
     }
 
     pub fn is_meta_item_list(&self) -> bool {
@@ -275,17 +299,49 @@ impl AttrItem {
 }
 
 impl Attribute {
+    pub fn is_doc_comment(&self) -> bool {
+        match self.kind {
+            AttrKind::Normal(_) => false,
+            AttrKind::DocComment(_) => true,
+        }
+    }
+
+    pub fn get_normal_item(&self) -> &AttrItem {
+        match self.kind {
+            AttrKind::Normal(ref item) => item,
+            AttrKind::DocComment(_) => panic!("unexpected sugared doc"),
+        }
+    }
+
+    pub fn unwrap_normal_item(self) -> AttrItem {
+        match self.kind {
+            AttrKind::Normal(item) => item,
+            AttrKind::DocComment(_) => panic!("unexpected sugared doc"),
+        }
+    }
+
     /// Extracts the MetaItem from inside this Attribute.
     pub fn meta(&self) -> Option<MetaItem> {
-        self.item.meta(self.span)
+        match self.kind {
+            AttrKind::Normal(ref item) => item.meta(self.span),
+            AttrKind::DocComment(comment) =>
+                Some(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span)),
+        }
     }
 
     pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> {
-        Ok(MetaItem {
-            path: self.item.path.clone(),
-            kind: parse::parse_in_attr(sess, self, |p| p.parse_meta_item_kind())?,
-            span: self.span,
-        })
+        match self.kind {
+            AttrKind::Normal(ref item) => {
+                Ok(MetaItem {
+                    path: item.path.clone(),
+                    kind: parse::parse_in_attr(sess, self, |parser| parser.parse_meta_item_kind())?,
+                    span: self.span,
+                })
+            }
+            AttrKind::DocComment(comment) => {
+                Ok(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span))
+            }
+        }
     }
 }
 
@@ -327,10 +383,9 @@ crate fn mk_attr_id() -> AttrId {
 
 pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute {
     Attribute {
-        item: AttrItem { path, tokens },
+        kind: AttrKind::Normal(AttrItem { path, tokens }),
         id: mk_attr_id(),
         style,
-        is_sugared_doc: false,
         span,
     }
 }
@@ -345,18 +400,11 @@ pub fn mk_attr_outer(item: MetaItem) -> Attribute {
     mk_attr(AttrStyle::Outer, item.path, item.kind.tokens(item.span), item.span)
 }
 
-pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute {
-    let style = doc_comment_style(&text.as_str());
-    let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked);
-    let lit = Lit::from_lit_kind(lit_kind, span);
+pub fn mk_doc_comment(comment: Symbol, span: Span) -> Attribute {
     Attribute {
-        item: AttrItem {
-            path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)),
-            tokens: MetaItemKind::NameValue(lit).tokens(span),
-        },
+        kind: AttrKind::DocComment(comment),
         id: mk_attr_id(),
-        style,
-        is_sugared_doc: true,
+        style: doc_comment_style(&comment.as_str()),
         span,
     }
 }