From 69bc4aba785e071740d2d46f109623b9951aae5d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Oct 2019 06:40:35 +1100 Subject: [PATCH 1/2] Remove unnecessary `Deref` impl for `Attribute`. This kind of thing just makes the code harder to read. --- src/librustc/hir/lowering.rs | 4 ++-- src/librustc_lint/builtin.rs | 2 +- src/librustc_metadata/link_args.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/macros.rs | 5 ++++- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_typeck/collect.rs | 4 ++-- src/libsyntax/ast.rs | 6 ------ src/libsyntax/attr/builtin.rs | 8 ++++---- src/libsyntax/attr/mod.rs | 10 +++++----- src/libsyntax/config.rs | 4 ++-- src/libsyntax/feature_gate/check.rs | 2 +- src/libsyntax/parse/mod.rs | 8 ++++---- src/libsyntax/visit.rs | 2 +- src/libsyntax_expand/expand.rs | 8 ++++---- src/libsyntax_expand/proc_macro.rs | 4 ++-- src/libsyntax_ext/proc_macro_harness.rs | 12 ++++++------ 17 files changed, 41 insertions(+), 44 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c8bb35202f518..067fefd321041 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -999,8 +999,8 @@ impl<'a> LoweringContext<'a> { // the `HirId`s. We don't actually need HIR version of attributes anyway. Attribute { item: AttrItem { - path: attr.path.clone(), - tokens: self.lower_token_stream(attr.tokens.clone()), + path: attr.item.path.clone(), + tokens: self.lower_token_stream(attr.item.tokens.clone()), }, id: attr.id, style: attr.style, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 30d68fd0bfcb1..5bc8a0e16a2a8 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -706,7 +706,7 @@ impl EarlyLintPass for DeprecatedAttr { } } if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) { - let path_str = pprust::path_to_string(&attr.path); + let path_str = pprust::path_to_string(&attr.item.path); let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str); lint_deprecated_attr(cx, attr, &msg, None); } diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index 4291f3a4ae34e..1b10cff56898c 100644 --- a/src/librustc_metadata/link_args.rs +++ b/src/librustc_metadata/link_args.rs @@ -11,7 +11,7 @@ crate fn collect(tcx: TyCtxt<'_>) -> Vec { tcx.hir().krate().visit_all_item_likes(&mut collector); for attr in tcx.hir().krate().attrs.iter() { - if attr.path == sym::link_args { + if attr.item.path == sym::link_args { if let Some(linkarg) = attr.value_str() { collector.add_link_args(&linkarg.as_str()); } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 648c5104b1af7..4849ec25560bf 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -1230,7 +1230,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { fn visit_attribute(&mut self, attr: &'b ast::Attribute) { if !attr.is_sugared_doc && is_builtin_attr(attr) { - self.r.builtin_attrs.push((attr.path.segments[0].ident, self.parent_scope)); + self.r.builtin_attrs.push((attr.item.path.segments[0].ident, self.parent_scope)); } visit::walk_attribute(self, attr); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 0fbd6b0e5d306..f4338d2462954 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -179,7 +179,10 @@ impl<'a> base::Resolver for Resolver<'a> { let (path, kind, derives, after_derive) = match invoc.kind { InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => - (&attr.path, MacroKind::Attr, self.arenas.alloc_ast_paths(derives), after_derive), + (&attr.item.path, + MacroKind::Attr, + self.arenas.alloc_ast_paths(derives), + after_derive), InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, &[][..], false), InvocationKind::Derive { ref path, .. } => diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 1cfb84bb511e4..7592df57fc635 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -1195,7 +1195,7 @@ fn null_id() -> rls_data::Id { fn lower_attributes(attrs: Vec, scx: &SaveContext<'_, '_>) -> Vec { attrs.into_iter() // Only retain real attributes. Doc comments are lowered separately. - .filter(|attr| attr.path != sym::doc) + .filter(|attr| attr.item.path != sym::doc) .map(|mut attr| { // Remove the surrounding '#[..]' or '#![..]' of the pretty printed // attribute. First normalize all inner attribute (#![..]) to outer diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ffe034759a80c..09e372ac8306d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2706,7 +2706,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { - if attr.path != sym::inline { + if attr.item.path != sym::inline { return ia; } match attr.meta().map(|i| i.kind) { @@ -2746,7 +2746,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { }); codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| { - if attr.path != sym::optimize { + if attr.item.path != sym::optimize { return ia; } let err = |sp, s| span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 8af38507b48d1..df1fb5d97d74d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2202,12 +2202,6 @@ pub struct Attribute { pub span: Span, } -// Compatibility impl to avoid churn, consider removing. -impl std::ops::Deref for Attribute { - type Target = AttrItem; - fn deref(&self) -> &Self::Target { &self.item } -} - /// `TraitRef`s appear in impls. /// /// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 84c86c9651fcf..e77d9ef326a64 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.path == s) { + ].iter().any(|&s| attr.item.path == s) { continue // not a stability level } @@ -236,10 +236,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let meta = attr.meta(); - if attr.path == sym::rustc_promotable { + if attr.item.path == sym::rustc_promotable { promotable = true; } - if attr.path == sym::rustc_allow_const_fn_ptr { + if attr.item.path == 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 { let mut acc = Vec::new(); let diagnostic = &sess.span_diagnostic; - if attr.path == sym::repr { + if attr.item.path == 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 3e240a855e280..0c46c501be9b7 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -150,7 +150,7 @@ impl Attribute { /// /// 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.path == name; + let matches = self.item.path == name; if matches { mark_used(self); } @@ -159,8 +159,8 @@ impl Attribute { /// For a single-segment attribute, returns its name; otherwise, returns `None`. pub fn ident(&self) -> Option { - if self.path.segments.len() == 1 { - Some(self.path.segments[0].ident) + if self.item.path.segments.len() == 1 { + Some(self.item.path.segments[0].ident) } else { None } @@ -181,7 +181,7 @@ impl Attribute { } pub fn is_word(&self) -> bool { - self.tokens.is_empty() + self.item.tokens.is_empty() } pub fn is_meta_item_list(&self) -> bool { @@ -282,7 +282,7 @@ impl Attribute { pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { Ok(MetaItem { - path: self.path.clone(), + path: self.item.path.clone(), kind: parse::parse_in_attr(sess, self, |p| p.parse_meta_item_kind())?, span: self.span, }) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 6003fd1d2861a..682c8f71dc88a 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -93,10 +93,10 @@ impl<'a> StripUnconfigured<'a> { /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { - if attr.path != sym::cfg_attr { + if attr.item.path != sym::cfg_attr { return vec![attr]; } - if attr.tokens.is_empty() { + if attr.item.tokens.is_empty() { self.sess.span_diagnostic .struct_span_err( attr.span, diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index d9cc5f6c169b6..c19ed7745074d 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -329,7 +329,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some((name, _, template, _)) if name != sym::rustc_dummy => check_builtin_attribute(self.parse_sess, attr, name, template), - _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() { + _ => if let Some(TokenTree::Token(token)) = attr.item.tokens.trees().next() { if token == token::Eq { // All key-value attributes are restricted to meta-item syntax. attr.parse_meta(self.parse_sess).map_err(|mut err| err.emit()).ok(); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 6d8ecdf805b01..6cfa0dfad8240 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -287,7 +287,7 @@ pub fn parse_in_attr<'a, T>( ) -> PResult<'a, T> { let mut parser = Parser::new( sess, - attr.tokens.clone(), + attr.item.tokens.clone(), None, false, false, @@ -403,8 +403,8 @@ fn prepend_attrs( let mut brackets = tokenstream::TokenStreamBuilder::new(); // For simple paths, push the identifier directly - if attr.path.segments.len() == 1 && attr.path.segments[0].args.is_none() { - let ident = attr.path.segments[0].ident; + if attr.item.path.segments.len() == 1 && attr.item.path.segments[0].args.is_none() { + let ident = attr.item.path.segments[0].ident; let token = token::Ident(ident.name, ident.as_str().starts_with("r#")); brackets.push(tokenstream::TokenTree::token(token, ident.span)); @@ -415,7 +415,7 @@ fn prepend_attrs( brackets.push(stream); } - brackets.push(attr.tokens.clone()); + brackets.push(attr.item.tokens.clone()); // The span we list here for `#` and for `[ ... ]` are both wrong in // that it encompasses more than each token, but it hopefully is "good diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a36783e2b642d..64393a295de44 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -846,7 +846,7 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { } pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) { - visitor.visit_tts(attr.tokens.clone()); + visitor.visit_tts(attr.item.tokens.clone()); } pub fn walk_tt<'a, V: Visitor<'a>>(visitor: &mut V, tt: TokenTree) { diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index da70fdbb0f308..392563587ba8b 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -419,7 +419,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } let mut item = self.fully_configure(item); - item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); + item.visit_attrs(|attrs| attrs.retain(|a| a.item.path != sym::derive)); let mut helper_attrs = Vec::new(); let mut has_copy = false; for ext in exts { @@ -974,7 +974,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { -> Option { let attr = attrs.iter() .position(|a| { - if a.path == sym::derive { + if a.item.path == sym::derive { *after_derive = true; } !attr::is_known(a) && !is_builtin_attr(a) @@ -982,7 +982,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { .map(|i| attrs.remove(i)); if let Some(attr) = &attr { if !self.cx.ecfg.custom_inner_attributes() && - attr.style == ast::AttrStyle::Inner && attr.path != sym::test { + attr.style == ast::AttrStyle::Inner && attr.item.path != sym::test { emit_feature_err(&self.cx.parse_sess, sym::custom_inner_attributes, attr.span, GateIssue::Language, "non-builtin inner attributes are unstable"); @@ -1032,7 +1032,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { feature_gate::check_attribute(attr, self.cx.parse_sess, features); // macros are expanded before any lint passes so this warning has to be hardcoded - if attr.path == sym::derive { + if attr.item.path == sym::derive { self.cx.struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations") .note("this may become a hard error in a future release") .emit(); diff --git a/src/libsyntax_expand/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs index bda9478ce96a9..53cd4d3519fe0 100644 --- a/src/libsyntax_expand/proc_macro.rs +++ b/src/libsyntax_expand/proc_macro.rs @@ -181,7 +181,7 @@ impl<'a> Visitor<'a> for MarkAttrs<'a> { crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) -> Vec { let mut result = Vec::new(); attrs.retain(|attr| { - if attr.path != sym::derive { + if attr.item.path != sym::derive { return true; } if !attr.is_meta_item_list() { @@ -196,7 +196,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) } let parse_derive_paths = |attr: &ast::Attribute| { - if attr.tokens.is_empty() { + if attr.item.tokens.is_empty() { return Ok(Vec::new()); } parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths()) diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index fc4a7a0a0fe47..bef913999270f 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -249,9 +249,9 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { for attr in &item.attrs { if is_proc_macro_attr(&attr) { if let Some(prev_attr) = found_attr { - let path_str = pprust::path_to_string(&attr.path); - let msg = if attr.path.segments[0].ident.name == - prev_attr.path.segments[0].ident.name { + let path_str = pprust::path_to_string(&attr.item.path); + let msg = if attr.item.path.segments[0].ident.name == + prev_attr.item.path.segments[0].ident.name { format!( "only one `#[{}]` attribute is allowed on any given function", path_str, @@ -261,7 +261,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { "`#[{}]` and `#[{}]` attributes cannot both be applied to the same function", path_str, - pprust::path_to_string(&prev_attr.path), + pprust::path_to_string(&prev_attr.item.path), ) }; @@ -290,7 +290,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !is_fn { let msg = format!( "the `#[{}]` attribute may only be used on bare functions", - pprust::path_to_string(&attr.path), + pprust::path_to_string(&attr.item.path), ); self.handler.span_err(attr.span, &msg); @@ -304,7 +304,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !self.is_proc_macro_crate { let msg = format!( "the `#[{}]` attribute is only usable with crates of the `proc-macro` crate type", - pprust::path_to_string(&attr.path), + pprust::path_to_string(&attr.item.path), ); self.handler.span_err(attr.span, &msg); From eea6f23a0ed67fd8c6b8e1b02cda3628fee56b2f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Oct 2019 06:33:12 +1100 Subject: [PATCH 2/2] 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. --- src/librustc/hir/lowering.rs | 16 ++- src/librustc/ich/impls_syntax.rs | 25 ++--- src/librustc_lint/builtin.rs | 6 +- src/librustc_metadata/link_args.rs | 2 +- src/librustc_passes/ast_validation.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 6 +- src/librustc_resolve/macros.rs | 2 +- src/librustc_save_analysis/lib.rs | 4 +- src/librustc_typeck/collect.rs | 4 +- src/librustdoc/clean/mod.rs | 47 +++++---- src/libsyntax/ast.rs | 19 +++- src/libsyntax/attr/builtin.rs | 8 +- src/libsyntax/attr/mod.rs | 110 ++++++++++++++------ src/libsyntax/config.rs | 9 +- src/libsyntax/feature_gate/check.rs | 3 +- src/libsyntax/mut_visit.rs | 12 ++- src/libsyntax/parse/mod.rs | 22 ++-- src/libsyntax/parse/parser/attr.rs | 7 +- src/libsyntax/parse/parser/item.rs | 12 ++- src/libsyntax/parse/tests.rs | 2 +- src/libsyntax/print/pprust.rs | 21 ++-- src/libsyntax/visit.rs | 5 +- src/libsyntax_expand/expand.rs | 18 ++-- src/libsyntax_expand/proc_macro.rs | 4 +- src/libsyntax_ext/proc_macro_harness.rs | 14 +-- 25 files changed, 233 insertions(+), 147 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 067fefd321041..230fbb16b87bc 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -997,14 +997,20 @@ impl<'a> LoweringContext<'a> { // Note that we explicitly do not walk the path. Since we don't really // lower attributes (we use the AST version) there is nowhere to keep // the `HirId`s. We don't actually need HIR version of attributes anyway. + let kind = match attr.kind { + AttrKind::Normal(ref item) => { + AttrKind::Normal(AttrItem { + path: item.path.clone(), + tokens: self.lower_token_stream(item.tokens.clone()), + }) + } + AttrKind::DocComment(comment) => AttrKind::DocComment(comment) + }; + Attribute { - item: AttrItem { - path: attr.item.path.clone(), - tokens: self.lower_token_stream(attr.item.tokens.clone()), - }, + kind, id: attr.id, style: attr.style, - is_sugared_doc: attr.is_sugared_doc, span: attr.span, } } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 304735fb1c7ed..aa147462e3d3b 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -177,7 +177,7 @@ impl<'a> HashStable> for [ast::Attribute] { let filtered: SmallVec<[&ast::Attribute; 8]> = self .iter() .filter(|attr| { - !attr.is_sugared_doc && + !attr.is_doc_comment() && !attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name)) }) .collect(); @@ -207,19 +207,16 @@ impl<'a> HashStable> for ast::Attribute { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { // Make sure that these have been filtered out. debug_assert!(!self.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name))); - debug_assert!(!self.is_sugared_doc); - - let ast::Attribute { - ref item, - id: _, - style, - is_sugared_doc: _, - span, - } = *self; - - item.hash_stable(hcx, hasher); - style.hash_stable(hcx, hasher); - span.hash_stable(hcx, hasher); + debug_assert!(!self.is_doc_comment()); + + let ast::Attribute { kind, id: _, style, span } = self; + if let ast::AttrKind::Normal(item) = kind { + item.hash_stable(hcx, hasher); + style.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + } else { + unreachable!(); + } } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 5bc8a0e16a2a8..d40af615eb181 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -706,7 +706,7 @@ impl EarlyLintPass for DeprecatedAttr { } } if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) { - let path_str = pprust::path_to_string(&attr.item.path); + let path_str = pprust::path_to_string(&attr.get_normal_item().path); let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str); lint_deprecated_attr(cx, attr, &msg, None); } @@ -736,7 +736,7 @@ impl UnusedDocComment { let mut sugared_span: Option = None; while let Some(attr) = attrs.next() { - if attr.is_sugared_doc { + if attr.is_doc_comment() { sugared_span = Some( sugared_span.map_or_else( || attr.span, @@ -745,7 +745,7 @@ impl UnusedDocComment { ); } - if attrs.peek().map(|next_attr| next_attr.is_sugared_doc).unwrap_or_default() { + if attrs.peek().map(|next_attr| next_attr.is_doc_comment()).unwrap_or_default() { continue; } diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index 1b10cff56898c..b40d58a681976 100644 --- a/src/librustc_metadata/link_args.rs +++ b/src/librustc_metadata/link_args.rs @@ -11,7 +11,7 @@ crate fn collect(tcx: TyCtxt<'_>) -> Vec { tcx.hir().krate().visit_all_item_likes(&mut collector); for attr in tcx.hir().krate().attrs.iter() { - if attr.item.path == sym::link_args { + if attr.has_name(sym::link_args) { if let Some(linkarg) = attr.value_str() { collector.add_link_args(&linkarg.as_str()); } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index e625334040e0a..d1a801b3006d7 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -328,7 +328,7 @@ impl<'a> AstValidator<'a> { let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn]; !arr.contains(&attr.name_or_empty()) && is_builtin_attr(attr) }) - .for_each(|attr| if attr.is_sugared_doc { + .for_each(|attr| if attr.is_doc_comment() { let mut err = self.err_handler().struct_span_err( attr.span, "documentation comments cannot be applied to function parameters" diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 4849ec25560bf..55f054d0be323 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -1229,8 +1229,10 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { } fn visit_attribute(&mut self, attr: &'b ast::Attribute) { - if !attr.is_sugared_doc && is_builtin_attr(attr) { - self.r.builtin_attrs.push((attr.item.path.segments[0].ident, self.parent_scope)); + if !attr.is_doc_comment() && is_builtin_attr(attr) { + self.r.builtin_attrs.push( + (attr.get_normal_item().path.segments[0].ident, self.parent_scope) + ); } visit::walk_attribute(self, attr); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index f4338d2462954..3d5a7f26eda55 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -179,7 +179,7 @@ impl<'a> base::Resolver for Resolver<'a> { let (path, kind, derives, after_derive) = match invoc.kind { InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => - (&attr.item.path, + (&attr.get_normal_item().path, MacroKind::Attr, self.arenas.alloc_ast_paths(derives), after_derive), diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 7592df57fc635..9408bbe557a21 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -885,7 +885,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { for attr in attrs { if attr.check_name(sym::doc) { if let Some(val) = attr.value_str() { - if attr.is_sugared_doc { + if attr.is_doc_comment() { result.push_str(&strip_doc_comment_decoration(&val.as_str())); } else { result.push_str(&val.as_str()); @@ -1195,7 +1195,7 @@ fn null_id() -> rls_data::Id { fn lower_attributes(attrs: Vec, scx: &SaveContext<'_, '_>) -> Vec { attrs.into_iter() // Only retain real attributes. Doc comments are lowered separately. - .filter(|attr| attr.item.path != sym::doc) + .filter(|attr| !attr.has_name(sym::doc)) .map(|mut attr| { // Remove the surrounding '#[..]' or '#![..]' of the pretty printed // attribute. First normalize all inner attribute (#![..]) to outer diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 09e372ac8306d..71a7b52a27ba9 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2706,7 +2706,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { - if attr.item.path != sym::inline { + if !attr.has_name(sym::inline) { return ia; } match attr.meta().map(|i| i.kind) { @@ -2746,7 +2746,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { }); codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| { - if attr.item.path != sym::optimize { + if !attr.has_name(sym::optimize) { return ia; } let err = |sp, s| span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e7f7615525292..32c8ca234a0c3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,7 +26,7 @@ use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind}; use rustc::ty::fold::TypeFolder; use rustc::ty::layout::VariantIdx; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use syntax::ast::{self, Attribute, AttrStyle, AttrItem, Ident}; +use syntax::ast::{self, Attribute, AttrStyle, AttrKind, Ident}; use syntax::attr; use syntax::parse::lexer::comments; use syntax::source_map::DUMMY_SP; @@ -859,31 +859,32 @@ impl Attributes { let mut cfg = Cfg::True; let mut doc_line = 0; - /// Converts `attr` to a normal `#[doc="foo"]` comment, if it is a - /// comment like `///` or `/** */`. (Returns `attr` unchanged for - /// non-sugared doc attributes.) - pub fn with_desugared_doc(attr: &Attribute, f: impl FnOnce(&Attribute) -> T) -> T { - if attr.is_sugared_doc { - let comment = attr.value_str().unwrap(); - let meta = attr::mk_name_value_item_str( - Ident::with_dummy_span(sym::doc), - Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str())), - DUMMY_SP, - ); - f(&Attribute { - item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, - id: attr.id, - style: attr.style, - is_sugared_doc: true, - span: attr.span, - }) - } else { - f(attr) + /// If `attr` is a doc comment, strips the leading and (if present) + /// trailing comments symbols, e.g. `///`, `/**`, and `*/`. Otherwise, + /// returns `attr` unchanged. + pub fn with_doc_comment_markers_stripped( + attr: &Attribute, + f: impl FnOnce(&Attribute) -> T + ) -> T { + match attr.kind { + AttrKind::Normal(_) => { + f(attr) + } + AttrKind::DocComment(comment) => { + let comment = + Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str())); + f(&Attribute { + kind: AttrKind::DocComment(comment), + id: attr.id, + style: attr.style, + span: attr.span, + }) + } } } let other_attrs = attrs.iter().filter_map(|attr| { - with_desugared_doc(attr, |attr| { + with_doc_comment_markers_stripped(attr, |attr| { if attr.check_name(sym::doc) { if let Some(mi) = attr.meta() { if let Some(value) = mi.value_str() { @@ -892,7 +893,7 @@ impl Attributes { let line = doc_line; doc_line += value.lines().count(); - if attr.is_sugared_doc { + if attr.is_doc_comment() { doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value)); } else { doc_strings.push(DocFragment::RawDoc(line, attr.span, value)); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index df1fb5d97d74d..2392b809150d4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2190,18 +2190,31 @@ pub struct AttrItem { } /// Metadata associated with an item. -/// Doc-comments are promoted to attributes that have `is_sugared_doc = true`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Attribute { - pub item: AttrItem, + pub kind: AttrKind, pub id: AttrId, /// Denotes if the attribute decorates the following construct (outer) /// or the construct this attribute is contained within (inner). pub style: AttrStyle, - pub is_sugared_doc: bool, pub span: Span, } +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub enum AttrKind { + /// A normal attribute. + Normal(AttrItem), + + /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). + /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal` + /// variant (which is much less compact and thus more expensive). + /// + /// Note: `self.has_name(sym::doc)` and `self.check_name(sym::doc)` succeed + /// for this variant, but this may change in the future. + /// ``` + DocComment(Symbol), +} + /// `TraitRef`s appear in impls. /// /// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index e77d9ef326a64..787d69f5e9964 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 { 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 0c46c501be9b7..c663995eb8fcb 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 { - 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 { - 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> { - 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 { - 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, } } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 682c8f71dc88a..5f89ed36e2a7d 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -93,10 +93,10 @@ impl<'a> StripUnconfigured<'a> { /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { - if attr.item.path != sym::cfg_attr { + if !attr.has_name(sym::cfg_attr) { return vec![attr]; } - if attr.item.tokens.is_empty() { + if attr.get_normal_item().tokens.is_empty() { self.sess.span_diagnostic .struct_span_err( attr.span, @@ -136,10 +136,9 @@ impl<'a> StripUnconfigured<'a> { // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs.into_iter() .flat_map(|(item, span)| self.process_cfg_attr(ast::Attribute { - item, + kind: ast::AttrKind::Normal(item), id: attr::mk_attr_id(), style: attr.style, - is_sugared_doc: false, span, })) .collect() @@ -212,7 +211,7 @@ impl<'a> StripUnconfigured<'a> { GateIssue::Language, EXPLAIN_STMT_ATTR_SYNTAX); - if attr.is_sugared_doc { + if attr.is_doc_comment() { err.help("`///` is for documentation comments. For a plain comment, use `//`."); } diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index c19ed7745074d..b7e75ff3a7e38 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -329,7 +329,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some((name, _, template, _)) if name != sym::rustc_dummy => check_builtin_attribute(self.parse_sess, attr, name, template), - _ => if let Some(TokenTree::Token(token)) = attr.item.tokens.trees().next() { + _ => if let Some(TokenTree::Token(token)) = + attr.get_normal_item().tokens.trees().next() { if token == token::Eq { // All key-value attributes are restricted to meta-item syntax. attr.parse_meta(self.parse_sess).map_err(|mut err| err.emit()).ok(); diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 60ee17d09b755..7261601e14491 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -550,10 +550,14 @@ pub fn noop_visit_local(local: &mut P, vis: &mut T) { } pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { - let Attribute { item: AttrItem { path, tokens }, id: _, style: _, is_sugared_doc: _, span } - = attr; - vis.visit_path(path); - vis.visit_tts(tokens); + let Attribute { kind, id: _, style: _, span } = attr; + match kind { + AttrKind::Normal(AttrItem { path, tokens }) => { + vis.visit_path(path); + vis.visit_tts(tokens); + } + AttrKind::DocComment(_) => {} + } vis.visit_span(span); } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 6cfa0dfad8240..b688dce87c138 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -287,7 +287,7 @@ pub fn parse_in_attr<'a, T>( ) -> PResult<'a, T> { let mut parser = Parser::new( sess, - attr.item.tokens.clone(), + attr.get_normal_item().tokens.clone(), None, false, false, @@ -393,18 +393,22 @@ fn prepend_attrs( let source = pprust::attribute_to_string(attr); let macro_filename = FileName::macro_expansion_source_code(&source); - if attr.is_sugared_doc { - let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); - builder.push(stream); - continue - } + + let item = match attr.kind { + ast::AttrKind::Normal(ref item) => item, + ast::AttrKind::DocComment(_) => { + let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); + builder.push(stream); + continue + } + }; // synthesize # [ $path $tokens ] manually here let mut brackets = tokenstream::TokenStreamBuilder::new(); // For simple paths, push the identifier directly - if attr.item.path.segments.len() == 1 && attr.item.path.segments[0].args.is_none() { - let ident = attr.item.path.segments[0].ident; + if item.path.segments.len() == 1 && item.path.segments[0].args.is_none() { + let ident = item.path.segments[0].ident; let token = token::Ident(ident.name, ident.as_str().starts_with("r#")); brackets.push(tokenstream::TokenTree::token(token, ident.span)); @@ -415,7 +419,7 @@ fn prepend_attrs( brackets.push(stream); } - brackets.push(attr.item.tokens.clone()); + brackets.push(item.tokens.clone()); // The span we list here for `#` and for `[ ... ]` are both wrong in // that it encompasses more than each token, but it hopefully is "good diff --git a/src/libsyntax/parse/parser/attr.rs b/src/libsyntax/parse/parser/attr.rs index 188a144cac9de..1c292661f2440 100644 --- a/src/libsyntax/parse/parser/attr.rs +++ b/src/libsyntax/parse/parser/attr.rs @@ -43,7 +43,7 @@ impl<'a> Parser<'a> { just_parsed_doc_comment = false; } token::DocComment(s) => { - let attr = attr::mk_sugared_doc_attr(s, self.token.span); + let attr = attr::mk_doc_comment(s, self.token.span); if attr.style != ast::AttrStyle::Outer { let mut err = self.fatal("expected outer doc comment"); err.note("inner doc comments like this (starting with \ @@ -150,10 +150,9 @@ impl<'a> Parser<'a> { }; Ok(ast::Attribute { - item, + kind: ast::AttrKind::Normal(item), id: attr::mk_attr_id(), style, - is_sugared_doc: false, span, }) } @@ -229,7 +228,7 @@ impl<'a> Parser<'a> { } token::DocComment(s) => { // We need to get the position of this token before we bump. - let attr = attr::mk_sugared_doc_attr(s, self.token.span); + let attr = attr::mk_doc_comment(s, self.token.span); if attr.style == ast::AttrStyle::Inner { attrs.push(attr); self.bump(); diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 5b60e7e6dba05..cc6235c6fc772 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -3,8 +3,8 @@ use super::diagnostics::{Error, dummy_arg, ConsumeClosingDelim}; use crate::maybe_whole; use crate::ptr::P; -use crate::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle, AnonConst, Item, ItemKind}; -use crate::ast::{ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind}; +use crate::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item}; +use crate::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind}; use crate::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness}; use crate::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind}; use crate::ast::{Ty, TyKind, Generics, GenericBounds, TraitRef, EnumDef, VariantData, StructField}; @@ -483,12 +483,14 @@ impl<'a> Parser<'a> { /// Emits an expected-item-after-attributes error. fn expected_item_err(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> { let message = match attrs.last() { - Some(&Attribute { is_sugared_doc: true, .. }) => "expected item after doc comment", - _ => "expected item after attributes", + Some(&Attribute { kind: AttrKind::DocComment(_), .. }) => + "expected item after doc comment", + _ => + "expected item after attributes", }; let mut err = self.diagnostic().struct_span_err(self.prev_span, message); - if attrs.last().unwrap().is_sugared_doc { + if attrs.last().unwrap().is_doc_comment() { err.span_label(self.prev_span, "this doc comment doesn't document anything"); } Err(err) diff --git a/src/libsyntax/parse/tests.rs b/src/libsyntax/parse/tests.rs index 3bdb9227b4edd..169eb954efadf 100644 --- a/src/libsyntax/parse/tests.rs +++ b/src/libsyntax/parse/tests.rs @@ -246,7 +246,7 @@ let mut fflags: c_int = wb(); let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_2, source, &sess) .unwrap().unwrap(); - let docs = item.attrs.iter().filter(|a| a.path == sym::doc) + let docs = item.attrs.iter().filter(|a| a.has_name(sym::doc)) .map(|a| a.value_str().unwrap().to_string()).collect::>(); let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; assert_eq!(&docs[..], b); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 74ab5c790193d..c8afe8a1ff459 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -622,16 +622,19 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.hardbreak_if_not_bol(); } self.maybe_print_comment(attr.span.lo()); - if attr.is_sugared_doc { - self.word(attr.value_str().unwrap().to_string()); - self.hardbreak() - } else { - match attr.style { - ast::AttrStyle::Inner => self.word("#!["), - ast::AttrStyle::Outer => self.word("#["), + match attr.kind { + ast::AttrKind::Normal(ref item) => { + match attr.style { + ast::AttrStyle::Inner => self.word("#!["), + ast::AttrStyle::Outer => self.word("#["), + } + self.print_attr_item(&item, attr.span); + self.word("]"); + } + ast::AttrKind::DocComment(comment) => { + self.word(comment.to_string()); + self.hardbreak() } - self.print_attr_item(&attr.item, attr.span); - self.word("]"); } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 64393a295de44..117787d08c750 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -846,7 +846,10 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { } pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) { - visitor.visit_tts(attr.item.tokens.clone()); + match attr.kind { + AttrKind::Normal(ref item) => visitor.visit_tts(item.tokens.clone()), + AttrKind::DocComment(_) => {} + } } pub fn walk_tt<'a, V: Visitor<'a>>(visitor: &mut V, tt: TokenTree) { diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index 392563587ba8b..7dbc778701006 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -419,7 +419,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } let mut item = self.fully_configure(item); - item.visit_attrs(|attrs| attrs.retain(|a| a.item.path != sym::derive)); + item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive))); let mut helper_attrs = Vec::new(); let mut has_copy = false; for ext in exts { @@ -634,9 +634,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { | Annotatable::Variant(..) => panic!("unexpected annotatable"), })), DUMMY_SP).into(); - let input = self.extract_proc_macro_attr_input(attr.item.tokens, span); + let item = attr.unwrap_normal_item(); + let input = self.extract_proc_macro_attr_input(item.tokens, span); let tok_result = expander.expand(self.cx, span, input, item_tok); - self.parse_ast_fragment(tok_result, fragment_kind, &attr.item.path, span) + self.parse_ast_fragment(tok_result, fragment_kind, &item.path, span) } SyntaxExtensionKind::LegacyAttr(expander) => { match attr.parse_meta(self.cx.parse_sess) { @@ -974,7 +975,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { -> Option { let attr = attrs.iter() .position(|a| { - if a.item.path == sym::derive { + if a.has_name(sym::derive) { *after_derive = true; } !attr::is_known(a) && !is_builtin_attr(a) @@ -982,7 +983,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { .map(|i| attrs.remove(i)); if let Some(attr) = &attr { if !self.cx.ecfg.custom_inner_attributes() && - attr.style == ast::AttrStyle::Inner && attr.item.path != sym::test { + attr.style == ast::AttrStyle::Inner && !attr.has_name(sym::test) { emit_feature_err(&self.cx.parse_sess, sym::custom_inner_attributes, attr.span, GateIssue::Language, "non-builtin inner attributes are unstable"); @@ -1032,7 +1033,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { feature_gate::check_attribute(attr, self.cx.parse_sess, features); // macros are expanded before any lint passes so this warning has to be hardcoded - if attr.item.path == sym::derive { + if attr.has_name(sym::derive) { self.cx.struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations") .note("this may become a hard error in a future release") .emit(); @@ -1547,11 +1548,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items); *at = attr::Attribute { - item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, + kind: ast::AttrKind::Normal( + AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, + ), span: at.span, id: at.id, style: at.style, - is_sugared_doc: false, }; } else { noop_visit_attribute(at, self) diff --git a/src/libsyntax_expand/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs index 53cd4d3519fe0..1f4c481e3ea04 100644 --- a/src/libsyntax_expand/proc_macro.rs +++ b/src/libsyntax_expand/proc_macro.rs @@ -181,7 +181,7 @@ impl<'a> Visitor<'a> for MarkAttrs<'a> { crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) -> Vec { let mut result = Vec::new(); attrs.retain(|attr| { - if attr.item.path != sym::derive { + if !attr.has_name(sym::derive) { return true; } if !attr.is_meta_item_list() { @@ -196,7 +196,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) } let parse_derive_paths = |attr: &ast::Attribute| { - if attr.item.tokens.is_empty() { + if attr.get_normal_item().tokens.is_empty() { return Ok(Vec::new()); } parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths()) diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index bef913999270f..792c97d8508fe 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -249,9 +249,11 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { for attr in &item.attrs { if is_proc_macro_attr(&attr) { if let Some(prev_attr) = found_attr { - let path_str = pprust::path_to_string(&attr.item.path); - let msg = if attr.item.path.segments[0].ident.name == - prev_attr.item.path.segments[0].ident.name { + let prev_item = prev_attr.get_normal_item(); + let item = attr.get_normal_item(); + let path_str = pprust::path_to_string(&item.path); + let msg = if item.path.segments[0].ident.name == + prev_item.path.segments[0].ident.name { format!( "only one `#[{}]` attribute is allowed on any given function", path_str, @@ -261,7 +263,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { "`#[{}]` and `#[{}]` attributes cannot both be applied to the same function", path_str, - pprust::path_to_string(&prev_attr.item.path), + pprust::path_to_string(&prev_item.path), ) }; @@ -290,7 +292,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !is_fn { let msg = format!( "the `#[{}]` attribute may only be used on bare functions", - pprust::path_to_string(&attr.item.path), + pprust::path_to_string(&attr.get_normal_item().path), ); self.handler.span_err(attr.span, &msg); @@ -304,7 +306,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !self.is_proc_macro_crate { let msg = format!( "the `#[{}]` attribute is only usable with crates of the `proc-macro` crate type", - pprust::path_to_string(&attr.item.path), + pprust::path_to_string(&attr.get_normal_item().path), ); self.handler.span_err(attr.span, &msg);