From 7bfa11d931a39f0419ff0f693544c3a54462a243 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 21 Mar 2021 03:58:32 +0300 Subject: [PATCH] [WIP] Expand attributes in left-to-right order --- compiler/rustc_attr/src/builtin.rs | 12 + compiler/rustc_builtin_macros/src/cfg_eval.rs | 46 +- compiler/rustc_builtin_macros/src/test.rs | 7 + compiler/rustc_expand/src/base.rs | 60 +- compiler/rustc_expand/src/config.rs | 127 ++- compiler/rustc_expand/src/expand.rs | 897 +++++++++++------- src/bootstrap/test.rs | 4 +- .../cfg-attr-empty-is-unused.rs | 5 +- .../cfg-attr-empty-is-unused.stderr | 21 - .../cfg-attr-syntax-validation.rs | 1 - .../cfg-attr-syntax-validation.stderr | 13 +- src/test/ui/macros/macro-attributes.rs | 6 +- src/test/ui/proc-macro/cfg-eval-fail.rs | 1 - src/test/ui/proc-macro/cfg-eval-fail.stderr | 8 +- src/test/ui/proc-macro/cfg-eval.rs | 4 + ...-54400-unused-extern-crate-attr-span.fixed | 3 +- ...sue-54400-unused-extern-crate-attr-span.rs | 4 +- ...54400-unused-extern-crate-attr-span.stderr | 7 +- 18 files changed, 782 insertions(+), 444 deletions(-) delete mode 100644 src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 20971ebb95748..3ce4e39e7331c 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -15,6 +15,18 @@ pub fn is_builtin_attr(attr: &Attribute) -> bool { attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some() } +pub fn is_inert_builtin_attr(attr: &Attribute) -> bool { + attr.is_doc_comment() + || attr + .ident() + .filter(|ident| { + ident.name != sym::cfg + && ident.name != sym::cfg_attr + && is_builtin_attr_name(ident.name) + }) + .is_some() +} + enum AttrError { MultipleItem(String), UnknownMetaItem(String, &'static [&'static str]), diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 79dc857074d59..95e19b7c38fe7 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -35,50 +35,48 @@ crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Vec { cfg: &'a mut StripUnconfigured<'b>, } -fn flat_map_annotatable(vis: &mut impl MutVisitor, annotatable: Annotatable) -> Annotatable { +fn flat_map_annotatable( + vis: &mut impl MutVisitor, + annotatable: Annotatable, +) -> Option { // Since the item itself has already been configured by the InvocationCollector, // we know that fold result vector will contain exactly one element match annotatable { - Annotatable::Item(item) => Annotatable::Item(vis.flat_map_item(item).pop().unwrap()), + Annotatable::Item(item) => vis.flat_map_item(item).pop().map(Annotatable::Item), Annotatable::TraitItem(item) => { - Annotatable::TraitItem(vis.flat_map_trait_item(item).pop().unwrap()) + vis.flat_map_trait_item(item).pop().map(Annotatable::TraitItem) } Annotatable::ImplItem(item) => { - Annotatable::ImplItem(vis.flat_map_impl_item(item).pop().unwrap()) + vis.flat_map_impl_item(item).pop().map(Annotatable::ImplItem) } Annotatable::ForeignItem(item) => { - Annotatable::ForeignItem(vis.flat_map_foreign_item(item).pop().unwrap()) + vis.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem) } Annotatable::Stmt(stmt) => { - Annotatable::Stmt(stmt.map(|stmt| vis.flat_map_stmt(stmt).pop().unwrap())) + vis.flat_map_stmt(stmt.into_inner()).pop().map(P).map(Annotatable::Stmt) } - Annotatable::Expr(mut expr) => Annotatable::Expr({ + Annotatable::Expr(mut expr) => { vis.visit_expr(&mut expr); - expr - }), - Annotatable::Arm(arm) => Annotatable::Arm(vis.flat_map_arm(arm).pop().unwrap()), - Annotatable::ExprField(field) => { - Annotatable::ExprField(vis.flat_map_expr_field(field).pop().unwrap()) + Some(Annotatable::Expr(expr)) } - Annotatable::PatField(fp) => { - Annotatable::PatField(vis.flat_map_pat_field(fp).pop().unwrap()) + Annotatable::Arm(arm) => vis.flat_map_arm(arm).pop().map(Annotatable::Arm), + Annotatable::ExprField(field) => { + vis.flat_map_expr_field(field).pop().map(Annotatable::ExprField) } + Annotatable::PatField(fp) => vis.flat_map_pat_field(fp).pop().map(Annotatable::PatField), Annotatable::GenericParam(param) => { - Annotatable::GenericParam(vis.flat_map_generic_param(param).pop().unwrap()) - } - Annotatable::Param(param) => Annotatable::Param(vis.flat_map_param(param).pop().unwrap()), - Annotatable::FieldDef(sf) => { - Annotatable::FieldDef(vis.flat_map_field_def(sf).pop().unwrap()) + vis.flat_map_generic_param(param).pop().map(Annotatable::GenericParam) } - Annotatable::Variant(v) => Annotatable::Variant(vis.flat_map_variant(v).pop().unwrap()), + Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param), + Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef), + Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant), } } @@ -123,11 +121,11 @@ impl CfgEval<'_, '_> { self.cfg.configure(node) } - pub fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Annotatable { + pub fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option { // Tokenizing and re-parsing the `Annotatable` can have a significant // performance impact, so try to avoid it if possible if !CfgFinder::has_cfg_or_cfg_attr(&annotatable) { - return annotatable; + return Some(annotatable); } // The majority of parsed attribute targets will never need to have early cfg-expansion diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index e845f9ec55ad5..6aace9a67391e 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -7,6 +7,7 @@ use rustc_ast::attr; use rustc_ast::ptr::P; use rustc_ast_pretty::pprust; use rustc_expand::base::*; +use rustc_expand::config::StripUnconfigured; use rustc_session::Session; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; @@ -55,6 +56,12 @@ pub fn expand_test( item: Annotatable, ) -> Vec { check_builtin_macro_attribute(cx, meta_item, sym::test); + let mut cfg = + StripUnconfigured { sess: cx.sess, features: cx.ecfg.features, config_tokens: true }; + let item = match cfg.configure(item) { + Some(item) => item, + None => return Vec::new(), + }; expand_test_or_bench(cx, attr_sp, item, false) } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 5950584281649..be9ce5929ccd8 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -3,7 +3,7 @@ use crate::module::DirOwnership; use rustc_ast::ptr::P; use rustc_ast::token::{self, Nonterminal}; -use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream}; +use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, LazyTokenStream, TokenStream}; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind}; use rustc_attr::{self as attr, Deprecation, Stability}; @@ -46,6 +46,64 @@ pub enum Annotatable { Variant(ast::Variant), } +impl AstLike for Annotatable { + const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true; + + fn attrs(&self) -> &[Attribute] { + match *self { + Annotatable::Item(ref item) => &item.attrs, + Annotatable::TraitItem(ref trait_item) => &trait_item.attrs, + Annotatable::ImplItem(ref impl_item) => &impl_item.attrs, + Annotatable::ForeignItem(ref foreign_item) => &foreign_item.attrs, + Annotatable::Stmt(ref stmt) => stmt.attrs(), + Annotatable::Expr(ref expr) => &expr.attrs, + Annotatable::Arm(ref arm) => &arm.attrs, + Annotatable::ExprField(ref field) => &field.attrs, + Annotatable::PatField(ref fp) => &fp.attrs, + Annotatable::GenericParam(ref gp) => &gp.attrs, + Annotatable::Param(ref p) => &p.attrs, + Annotatable::FieldDef(ref sf) => &sf.attrs, + Annotatable::Variant(ref v) => &v.attrs(), + } + } + + fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { + match self { + Annotatable::Item(item) => item.visit_attrs(f), + Annotatable::TraitItem(trait_item) => trait_item.visit_attrs(f), + Annotatable::ImplItem(impl_item) => impl_item.visit_attrs(f), + Annotatable::ForeignItem(foreign_item) => foreign_item.visit_attrs(f), + Annotatable::Stmt(stmt) => stmt.visit_attrs(f), + Annotatable::Expr(expr) => expr.visit_attrs(f), + Annotatable::Arm(arm) => arm.visit_attrs(f), + Annotatable::ExprField(field) => field.visit_attrs(f), + Annotatable::PatField(fp) => fp.visit_attrs(f), + Annotatable::GenericParam(gp) => gp.visit_attrs(f), + Annotatable::Param(p) => p.visit_attrs(f), + Annotatable::FieldDef(sf) => sf.visit_attrs(f), + Annotatable::Variant(v) => v.visit_attrs(f), + } + } + + fn tokens_mut(&mut self) -> Option<&mut Option> { + match self { + Annotatable::Item(item) => item.tokens_mut(), + Annotatable::TraitItem(trait_item) => trait_item.tokens_mut(), + Annotatable::ImplItem(impl_item) => impl_item.tokens_mut(), + Annotatable::ForeignItem(foreign_item) => foreign_item.tokens_mut(), + Annotatable::Stmt(stmt) => stmt.tokens_mut(), + Annotatable::Expr(expr) => expr.tokens_mut(), + Annotatable::Arm(arm) => arm.tokens_mut(), + Annotatable::ExprField(field) => field.tokens_mut(), + Annotatable::PatField(fp) => fp.tokens_mut(), + Annotatable::GenericParam(gp) => gp.tokens_mut(), + Annotatable::Param(p) => p.tokens_mut(), + Annotatable::FieldDef(sf) => sf.tokens_mut(), + Annotatable::Variant(v) => v.tokens_mut(), + } + } +} + impl Annotatable { pub fn span(&self) -> Span { match *self { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 03c83f9c07b5d..2d3be0169dbe4 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -415,6 +415,66 @@ impl<'a> StripUnconfigured<'a> { .collect() } + crate fn expand_cfg_attr(&mut self, attr: Attribute) -> Vec { + let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) { + None => return vec![], + Some(r) => r, + }; + + if !attr::cfg_matches(&cfg_predicate, &self.sess.parse_sess, self.features) { + return vec![]; + } + + // We call `process_cfg_attr` recursively in case there's a + // `cfg_attr` inside of another `cfg_attr`. E.g. + // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. + expanded_attrs + .into_iter() + .map(|(item, span)| { + let orig_tokens = attr.tokens().to_tokenstream(); + + // We are taking an attribute of the form `#[cfg_attr(pred, attr)]` + // and producing an attribute of the form `#[attr]`. We + // have captured tokens for `attr` itself, but we need to + // synthesize tokens for the wrapper `#` and `[]`, which + // we do below. + + // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token + // for `attr` when we expand it to `#[attr]` + let mut orig_trees = orig_tokens.trees(); + let pound_token = match orig_trees.next().unwrap() { + TokenTree::Token(token @ Token { kind: TokenKind::Pound, .. }) => token, + _ => panic!("Bad tokens for attribute {:?}", attr), + }; + let pound_span = pound_token.span; + + let mut trees = vec![(AttrAnnotatedTokenTree::Token(pound_token), Spacing::Alone)]; + if attr.style == AttrStyle::Inner { + // For inner attributes, we do the same thing for the `!` in `#![some_attr]` + let bang_token = match orig_trees.next().unwrap() { + TokenTree::Token(token @ Token { kind: TokenKind::Not, .. }) => token, + _ => panic!("Bad tokens for attribute {:?}", attr), + }; + trees.push((AttrAnnotatedTokenTree::Token(bang_token), Spacing::Alone)); + } + // We don't really have a good span to use for the syntheized `[]` + // in `#[attr]`, so just use the span of the `#` token. + let bracket_group = AttrAnnotatedTokenTree::Delimited( + DelimSpan::from_single(pound_span), + DelimToken::Bracket, + item.tokens + .as_ref() + .unwrap_or_else(|| panic!("Missing tokens for {:?}", item)) + .create_token_stream(), + ); + trees.push((bracket_group, Spacing::Alone)); + let tokens = Some(LazyTokenStream::new(AttrAnnotatedTokenStream::new(trees))); + + attr::mk_attr_from_item(item, tokens, attr.style, span) + }) + .collect() + } + fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { match attr.get_normal_item().args { ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => { @@ -453,43 +513,42 @@ impl<'a> StripUnconfigured<'a> { /// Determines if a node with the given attributes should be included in this configuration. fn in_cfg(&self, attrs: &[Attribute]) -> bool { - attrs.iter().all(|attr| { - if !is_cfg(self.sess, attr) { + attrs.iter().all(|attr| !is_cfg(self.sess, attr) || self.cfg_true(attr)) + } + + crate fn cfg_true(&self, attr: &Attribute) -> bool { + let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) { + Ok(meta_item) => meta_item, + Err(mut err) => { + err.emit(); return true; } - let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) { - Ok(meta_item) => meta_item, - Err(mut err) => { - err.emit(); - return true; - } - }; - let error = |span, msg, suggestion: &str| { - let mut err = self.sess.parse_sess.span_diagnostic.struct_span_err(span, msg); - if !suggestion.is_empty() { - err.span_suggestion( - span, - "expected syntax is", - suggestion.into(), - Applicability::MaybeIncorrect, - ); - } - err.emit(); - true - }; - let span = meta_item.span; - match meta_item.meta_item_list() { - None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"), - Some([]) => error(span, "`cfg` predicate is not specified", ""), - Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""), - Some([single]) => match single.meta_item() { - Some(meta_item) => { - attr::cfg_matches(meta_item, &self.sess.parse_sess, self.features) - } - None => error(single.span(), "`cfg` predicate key cannot be a literal", ""), - }, + }; + let error = |span, msg, suggestion: &str| { + let mut err = self.sess.parse_sess.span_diagnostic.struct_span_err(span, msg); + if !suggestion.is_empty() { + err.span_suggestion( + span, + "expected syntax is", + suggestion.into(), + Applicability::MaybeIncorrect, + ); } - }) + err.emit(); + true + }; + let span = meta_item.span; + match meta_item.meta_item_list() { + None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"), + Some([]) => error(span, "`cfg` predicate is not specified", ""), + Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""), + Some([single]) => match single.meta_item() { + Some(meta_item) => { + attr::cfg_matches(meta_item, &self.sess.parse_sess, self.features) + } + None => error(single.span(), "`cfg` predicate key cannot be a literal", ""), + }, + } } /// If attributes are not allowed on expressions, emit an error for `attr` diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 3347c93948ccc..4a063e971beb4 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1,6 +1,5 @@ use crate::base::*; use crate::config::StripUnconfigured; -use crate::configure; use crate::hygiene::SyntaxContext; use crate::mbe::macro_rules::annotate_err_with_kind; use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; @@ -16,7 +15,7 @@ use rustc_ast::{AstLike, AttrItem, Block, Inline, ItemKind, LitKind, MacArgs}; use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem}; use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe}; use rustc_ast_pretty::pprust; -use rustc_attr::{self as attr, is_builtin_attr}; +use rustc_attr::{self as attr, is_inert_builtin_attr}; use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; @@ -33,7 +32,6 @@ use rustc_span::{ExpnId, FileName, Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::io::ErrorKind; -use std::ops::DerefMut; use std::path::PathBuf; use std::rc::Rc; use std::{iter, mem, slice}; @@ -506,10 +504,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let item = match &fragment { AstFragment::Items(items) => match &items[..] { [item] => AnnotatableRef::Item(item), + [] => return Vec::new(), _ => unreachable!(), }, AstFragment::Stmts(stmts) => match &stmts[..] { [stmt] => AnnotatableRef::Stmt(stmt), + [] => return Vec::new(), _ => unreachable!(), }, _ => unreachable!(), @@ -1061,7 +1061,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { item.visit_attrs(|attrs| { attr = attrs .iter() - .position(|a| !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a)) + .position(|a| !self.cx.sess.is_attr_known(a) && !is_inert_builtin_attr(a)) .map(|attr_pos| { let attr = attrs.remove(attr_pos); let following_derives = attrs[attr_pos..] @@ -1085,10 +1085,6 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { attr } - fn configure(&mut self, node: T) -> Option { - self.cfg.configure(node) - } - // Detect use of feature-gated or invalid attributes on macro invocations // since they will not be detected after macro expansion. fn check_attributes(&mut self, attrs: &[ast::Attribute]) { @@ -1121,177 +1117,349 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_expr(&mut self, expr: &mut P) { - self.cfg.configure_expr(expr); - visit_clobber(expr.deref_mut(), |mut expr| { - if let Some(attr) = self.take_first_attr(&mut expr) { - // Collect the invoc regardless of whether or not attributes are permitted here - // expansion will eat the attribute so it won't error later. - self.cfg.maybe_emit_expr_attr_err(&attr.0); - - // AstFragmentKind::Expr requires the macro to emit an expression. - return self - .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::Expr) - .make_expr() - .into_inner(); - } + // FIXME: Feature gating is performed inconsistently between `Expr` and `OptExpr`. + if let Some(attr) = expr.attrs.first() { + self.cfg.maybe_emit_expr_attr_err(attr); + } - if let ast::ExprKind::MacCall(mac) = expr.kind { - self.check_attributes(&expr.attrs); - self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner() - } else { - ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self)); - expr - } - }); + loop { + return match self.take_first_attr(expr) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + let msg = "removing an expression is not supported in this position"; + self.cx.span_err(attr.span, msg); + continue; + } + sym::cfg_attr => { + expr.visit_attrs(|attrs| { + attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + }); + continue; + } + _ => visit_clobber(expr, |expr| { + self.collect_attr( + (attr, pos, derives), + Annotatable::Expr(expr), + AstFragmentKind::Expr, + ) + .make_expr() + }), + }, + None => match expr.kind { + ast::ExprKind::MacCall(..) => { + self.check_attributes(&expr.attrs); + visit_clobber(expr, |mut expr| { + match mem::replace(&mut expr.kind, ast::ExprKind::Err) { + ast::ExprKind::MacCall(mac) => self + .collect_bang(mac, expr.span, AstFragmentKind::Expr) + .make_expr(), + _ => unreachable!(), + } + }) + } + _ => ensure_sufficient_stack(|| noop_visit_expr(expr, self)), + }, + }; + } } - fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { - let mut arm = configure!(self, arm); - - if let Some(attr) = self.take_first_attr(&mut arm) { - return self - .collect_attr(attr, Annotatable::Arm(arm), AstFragmentKind::Arms) - .make_arms(); + fn flat_map_arm(&mut self, mut arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> { + loop { + return match self.take_first_attr(&mut arm) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() + } + sym::cfg_attr => { + arm.attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + continue; + } + _ => self + .collect_attr( + (attr, pos, derives), + Annotatable::Arm(arm), + AstFragmentKind::Arms, + ) + .make_arms(), + }, + None => noop_flat_map_arm(arm, self), + }; } - - noop_flat_map_arm(arm, self) } - fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> { - let mut field = configure!(self, field); - - if let Some(attr) = self.take_first_attr(&mut field) { - return self - .collect_attr(attr, Annotatable::ExprField(field), AstFragmentKind::Fields) - .make_expr_fields(); + fn flat_map_expr_field(&mut self, mut field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> { + loop { + return match self.take_first_attr(&mut field) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() + } + sym::cfg_attr => { + field.visit_attrs(|attrs| { + attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + }); + continue; + } + _ => self + .collect_attr( + (attr, pos, derives), + Annotatable::ExprField(field), + AstFragmentKind::Fields, + ) + .make_expr_fields(), + }, + None => noop_flat_map_expr_field(field, self), + }; } - - noop_flat_map_expr_field(field, self) } - fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> { - let mut fp = configure!(self, fp); - - if let Some(attr) = self.take_first_attr(&mut fp) { - return self - .collect_attr(attr, Annotatable::PatField(fp), AstFragmentKind::FieldPats) - .make_pat_fields(); + fn flat_map_pat_field(&mut self, mut fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> { + loop { + return match self.take_first_attr(&mut fp) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() + } + sym::cfg_attr => { + fp.visit_attrs(|attrs| { + attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + }); + continue; + } + _ => self + .collect_attr( + (attr, pos, derives), + Annotatable::PatField(fp), + AstFragmentKind::FieldPats, + ) + .make_pat_fields(), + }, + None => noop_flat_map_pat_field(fp, self), + }; } - - noop_flat_map_pat_field(fp, self) } - fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> { - let mut p = configure!(self, p); - - if let Some(attr) = self.take_first_attr(&mut p) { - return self - .collect_attr(attr, Annotatable::Param(p), AstFragmentKind::Params) - .make_params(); + fn flat_map_param(&mut self, mut p: ast::Param) -> SmallVec<[ast::Param; 1]> { + loop { + return match self.take_first_attr(&mut p) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() + } + sym::cfg_attr => { + p.visit_attrs(|attrs| { + attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + }); + continue; + } + _ => self + .collect_attr( + (attr, pos, derives), + Annotatable::Param(p), + AstFragmentKind::Params, + ) + .make_params(), + }, + None => noop_flat_map_param(p, self), + }; } - - noop_flat_map_param(p, self) } - fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> { - let mut sf = configure!(self, sf); - - if let Some(attr) = self.take_first_attr(&mut sf) { - return self - .collect_attr(attr, Annotatable::FieldDef(sf), AstFragmentKind::StructFields) - .make_field_defs(); + fn flat_map_field_def(&mut self, mut sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> { + loop { + return match self.take_first_attr(&mut sf) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() + } + sym::cfg_attr => { + sf.attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + continue; + } + _ => self + .collect_attr( + (attr, pos, derives), + Annotatable::FieldDef(sf), + AstFragmentKind::StructFields, + ) + .make_field_defs(), + }, + None => noop_flat_map_field_def(sf, self), + }; } - - noop_flat_map_field_def(sf, self) } - fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { - let mut variant = configure!(self, variant); - - if let Some(attr) = self.take_first_attr(&mut variant) { - return self - .collect_attr(attr, Annotatable::Variant(variant), AstFragmentKind::Variants) - .make_variants(); + fn flat_map_variant(&mut self, mut variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> { + loop { + return match self.take_first_attr(&mut variant) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() + } + sym::cfg_attr => { + variant.attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + continue; + } + _ => self + .collect_attr( + (attr, pos, derives), + Annotatable::Variant(variant), + AstFragmentKind::Variants, + ) + .make_variants(), + }, + None => noop_flat_map_variant(variant, self), + }; } - - noop_flat_map_variant(variant, self) } - fn filter_map_expr(&mut self, expr: P) -> Option> { - let expr = configure!(self, expr); - expr.filter_map(|mut expr| { - if let Some(attr) = self.take_first_attr(&mut expr) { - self.cfg.maybe_emit_expr_attr_err(&attr.0); - - return self - .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr) - .make_opt_expr() - .map(|expr| expr.into_inner()); - } - - if let ast::ExprKind::MacCall(mac) = expr.kind { - self.check_attributes(&expr.attrs); - self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr) - .make_opt_expr() - .map(|expr| expr.into_inner()) - } else { - Some({ - noop_visit_expr(&mut expr, self); - expr - }) - } - }) + fn filter_map_expr(&mut self, mut expr: P) -> Option> { + loop { + return match self.take_first_attr(&mut expr) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() + } + sym::cfg_attr => { + expr.visit_attrs(|attrs| { + attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + }); + continue; + } + _ => { + // FIXME: Feature gating is performed inconsistently + // between `Expr` and `OptExpr`. + self.cfg.maybe_emit_expr_attr_err(&attr); + self.collect_attr( + (attr, pos, derives), + Annotatable::Expr(expr), + AstFragmentKind::OptExpr, + ) + .make_opt_expr() + } + }, + None => match expr.kind { + ast::ExprKind::MacCall(..) => { + let expr = expr.into_inner(); + let mac = match expr.kind { + ast::ExprKind::MacCall(mac) => mac, + _ => unreachable!(), + }; + self.check_attributes(&expr.attrs); + self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr).make_opt_expr() + } + _ => Some({ + noop_visit_expr(&mut expr, self); + expr + }), + }, + }; + } } fn visit_pat(&mut self, pat: &mut P) { match pat.kind { - PatKind::MacCall(_) => {} - _ => return noop_visit_pat(pat, self), - } - - visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) { - PatKind::MacCall(mac) => { - self.collect_bang(mac, pat.span, AstFragmentKind::Pat).make_pat() + PatKind::MacCall(_) => { + visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) { + PatKind::MacCall(mac) => { + self.collect_bang(mac, pat.span, AstFragmentKind::Pat).make_pat() + } + _ => unreachable!(), + }) } - _ => unreachable!(), - }); + _ => noop_visit_pat(pat, self), + } } - fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { - let mut stmt = configure!(self, stmt); - - // we'll expand attributes on expressions separately - if !stmt.is_expr() { - if let Some(attr) = self.take_first_attr(&mut stmt) { - return self - .collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts) - .make_stmts(); - } + fn flat_map_stmt(&mut self, mut stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { + // FIXME: Expression statements are currently expanded as expressions, + // expand them as statements instead (#61733). + if stmt.is_expr() { + // The placeholder expander gives ids to statements, so we avoid folding the id here. + // FIXME: Avoid special treatment of node ids in statements. + let ast::Stmt { id, kind, span } = stmt; + return noop_flat_map_stmt_kind(kind, self) + .into_iter() + .map(|kind| ast::Stmt { id, kind, span }) + .collect(); } - if let StmtKind::MacCall(mac) = stmt.kind { - let MacCallStmt { mac, style, attrs, tokens: _ } = mac.into_inner(); - self.check_attributes(&attrs); - let mut placeholder = - self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts(); - - // If this is a macro invocation with a semicolon, then apply that - // semicolon to the final statement produced by expansion. - if style == MacStmtStyle::Semicolon { - if let Some(stmt) = placeholder.pop() { - placeholder.push(stmt.add_trailing_semicolon()); - } - } + loop { + return match self.take_first_attr(&mut stmt) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() + } + sym::cfg_attr => { + stmt.visit_attrs(|attrs| { + attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + }); + continue; + } + _ => self + .collect_attr( + (attr, pos, derives), + Annotatable::Stmt(P(stmt)), + AstFragmentKind::Stmts, + ) + .make_stmts(), + }, + None => match stmt.kind { + StmtKind::MacCall(mac) => { + let MacCallStmt { mac, style, attrs, tokens: _ } = mac.into_inner(); + self.check_attributes(&attrs); + let mut placeholder = + self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts(); + + // If this is a macro invocation with a semicolon, then apply that + // semicolon to the final statement produced by expansion. + if style == MacStmtStyle::Semicolon { + if let Some(stmt) = placeholder.pop() { + placeholder.push(stmt.add_trailing_semicolon()); + } + } - return placeholder; + placeholder + } + _ => { + // The placeholder expander gives ids to statements, so we avoid folding the id here. + // FIXME: Avoid special treatment of node ids in statements. + let ast::Stmt { id, kind, span } = stmt; + noop_flat_map_stmt_kind(kind, self) + .into_iter() + .map(|kind| ast::Stmt { id, kind, span }) + .collect() + } + }, + }; } - - // The placeholder expander gives ids to statements, so we avoid folding the id here. - let ast::Stmt { id, kind, span } = stmt; - noop_flat_map_stmt_kind(kind, self) - .into_iter() - .map(|kind| ast::Stmt { id, kind, span }) - .collect() } fn visit_block(&mut self, block: &mut P) { @@ -1303,223 +1471,296 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.cx.current_expansion.dir_ownership = orig_dir_ownership; } - fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { - let mut item = configure!(self, item); - - if let Some(attr) = self.take_first_attr(&mut item) { - return self - .collect_attr(attr, Annotatable::Item(item), AstFragmentKind::Items) - .make_items(); - } - - let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck. - let ident = item.ident; - let span = item.span; - - match item.kind { - ast::ItemKind::MacCall(..) => { - item.attrs = attrs; - self.check_attributes(&item.attrs); - item.and_then(|item| match item.kind { - ItemKind::MacCall(mac) => { - self.collect_bang(mac, span, AstFragmentKind::Items).make_items() + fn flat_map_item(&mut self, mut item: P) -> SmallVec<[P; 1]> { + loop { + return match self.take_first_attr(&mut item) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() } - _ => unreachable!(), - }) - } - ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => { - let (file_path, dir_path, dir_ownership) = match mod_kind { - ModKind::Loaded(_, inline, _) => { - // Inline `mod foo { ... }`, but we still need to push directories. - let (dir_path, dir_ownership) = mod_dir_path( - &self.cx.sess, - ident, - &attrs, - &self.cx.current_expansion.module, - self.cx.current_expansion.dir_ownership, - *inline, - ); - item.attrs = attrs; - (None, dir_path, dir_ownership) + sym::cfg_attr => { + item.attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + continue; } - ModKind::Unloaded => { - // We have an outline `mod foo;` so we need to parse the file. - let old_attrs_len = attrs.len(); - let ParsedExternalMod { - mut items, - inner_span, - file_path, - dir_path, - dir_ownership, - } = parse_external_mod( - &self.cx.sess, - ident, - span, - &self.cx.current_expansion.module, - self.cx.current_expansion.dir_ownership, - &mut attrs, - ); - - if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded { - (attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span); + _ => self + .collect_attr( + (attr, pos, derives), + Annotatable::Item(item), + AstFragmentKind::Items, + ) + .make_items(), + }, + None => { + let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck. + let ident = item.ident; + let span = item.span; + + match item.kind { + ast::ItemKind::MacCall(..) => { + item.attrs = attrs; + self.check_attributes(&item.attrs); + item.and_then(|item| match item.kind { + ItemKind::MacCall(mac) => self + .collect_bang(mac, span, AstFragmentKind::Items) + .make_items(), + _ => unreachable!(), + }) } + ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => { + let (file_path, dir_path, dir_ownership) = match mod_kind { + ModKind::Loaded(_, inline, _) => { + // Inline `mod foo { ... }`, but we still need to push directories. + let (dir_path, dir_ownership) = mod_dir_path( + &self.cx.sess, + ident, + &attrs, + &self.cx.current_expansion.module, + self.cx.current_expansion.dir_ownership, + *inline, + ); + item.attrs = attrs; + (None, dir_path, dir_ownership) + } + ModKind::Unloaded => { + // We have an outline `mod foo;` so we need to parse the file. + let old_attrs_len = attrs.len(); + let ParsedExternalMod { + mut items, + inner_span, + file_path, + dir_path, + dir_ownership, + } = parse_external_mod( + &self.cx.sess, + ident, + span, + &self.cx.current_expansion.module, + self.cx.current_expansion.dir_ownership, + &mut attrs, + ); + + if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded { + (attrs, items) = + extern_mod_loaded(ident, attrs, items, inner_span); + } + + *mod_kind = ModKind::Loaded(items, Inline::No, inner_span); + item.attrs = attrs; + if item.attrs.len() > old_attrs_len { + // If we loaded an out-of-line module and added some inner attributes, + // then we need to re-configure it and re-collect attributes for + // resolution and expansion. + continue; + } + (Some(file_path), dir_path, dir_ownership) + } + }; - *mod_kind = ModKind::Loaded(items, Inline::No, inner_span); - item.attrs = attrs; - if item.attrs.len() > old_attrs_len { - // If we loaded an out-of-line module and added some inner attributes, - // then we need to re-configure it and re-collect attributes for - // resolution and expansion. - item = configure!(self, item); - - if let Some(attr) = self.take_first_attr(&mut item) { - return self - .collect_attr( - attr, - Annotatable::Item(item), - AstFragmentKind::Items, - ) - .make_items(); + // Set the module info before we flat map. + let mut module = + self.cx.current_expansion.module.with_dir_path(dir_path); + module.mod_path.push(ident); + if let Some(file_path) = file_path { + module.file_path_stack.push(file_path); } - } - (Some(file_path), dir_path, dir_ownership) - } - }; - - // Set the module info before we flat map. - let mut module = self.cx.current_expansion.module.with_dir_path(dir_path); - module.mod_path.push(ident); - if let Some(file_path) = file_path { - module.file_path_stack.push(file_path); - } - let orig_module = - mem::replace(&mut self.cx.current_expansion.module, Rc::new(module)); - let orig_dir_ownership = - mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership); + let orig_module = mem::replace( + &mut self.cx.current_expansion.module, + Rc::new(module), + ); + let orig_dir_ownership = mem::replace( + &mut self.cx.current_expansion.dir_ownership, + dir_ownership, + ); - let result = noop_flat_map_item(item, self); + let result = noop_flat_map_item(item, self); - // Restore the module info. - self.cx.current_expansion.dir_ownership = orig_dir_ownership; - self.cx.current_expansion.module = orig_module; + // Restore the module info. + self.cx.current_expansion.dir_ownership = orig_dir_ownership; + self.cx.current_expansion.module = orig_module; - result - } - _ => { - item.attrs = attrs; - noop_flat_map_item(item, self) - } + result + } + _ => { + item.attrs = attrs; + noop_flat_map_item(item, self) + } + } + } + }; } } - fn flat_map_trait_item(&mut self, item: P) -> SmallVec<[P; 1]> { - let mut item = configure!(self, item); - - if let Some(attr) = self.take_first_attr(&mut item) { - return self - .collect_attr(attr, Annotatable::TraitItem(item), AstFragmentKind::TraitItems) - .make_trait_items(); - } - - match item.kind { - ast::AssocItemKind::MacCall(..) => { - self.check_attributes(&item.attrs); - item.and_then(|item| match item.kind { - ast::AssocItemKind::MacCall(mac) => self - .collect_bang(mac, item.span, AstFragmentKind::TraitItems) + fn flat_map_trait_item( + &mut self, + mut item: P, + ) -> SmallVec<[P; 1]> { + loop { + return match self.take_first_attr(&mut item) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() + } + sym::cfg_attr => { + item.attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + continue; + } + _ => self + .collect_attr( + (attr, pos, derives), + Annotatable::TraitItem(item), + AstFragmentKind::TraitItems, + ) .make_trait_items(), - _ => unreachable!(), - }) - } - _ => noop_flat_map_assoc_item(item, self), + }, + None => match item.kind { + ast::AssocItemKind::MacCall(..) => { + self.check_attributes(&item.attrs); + item.and_then(|item| match item.kind { + ast::AssocItemKind::MacCall(mac) => self + .collect_bang(mac, item.span, AstFragmentKind::TraitItems) + .make_trait_items(), + _ => unreachable!(), + }) + } + _ => noop_flat_map_assoc_item(item, self), + }, + }; } } - fn flat_map_impl_item(&mut self, item: P) -> SmallVec<[P; 1]> { - let mut item = configure!(self, item); - - if let Some(attr) = self.take_first_attr(&mut item) { - return self - .collect_attr(attr, Annotatable::ImplItem(item), AstFragmentKind::ImplItems) - .make_impl_items(); - } - - match item.kind { - ast::AssocItemKind::MacCall(..) => { - self.check_attributes(&item.attrs); - item.and_then(|item| match item.kind { - ast::AssocItemKind::MacCall(mac) => self - .collect_bang(mac, item.span, AstFragmentKind::ImplItems) + fn flat_map_impl_item( + &mut self, + mut item: P, + ) -> SmallVec<[P; 1]> { + loop { + return match self.take_first_attr(&mut item) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() + } + sym::cfg_attr => { + item.attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + continue; + } + _ => self + .collect_attr( + (attr, pos, derives), + Annotatable::ImplItem(item), + AstFragmentKind::ImplItems, + ) .make_impl_items(), - _ => unreachable!(), - }) - } - _ => noop_flat_map_assoc_item(item, self), + }, + None => match item.kind { + ast::AssocItemKind::MacCall(..) => { + self.check_attributes(&item.attrs); + item.and_then(|item| match item.kind { + ast::AssocItemKind::MacCall(mac) => self + .collect_bang(mac, item.span, AstFragmentKind::ImplItems) + .make_impl_items(), + _ => unreachable!(), + }) + } + _ => noop_flat_map_assoc_item(item, self), + }, + }; } } fn visit_ty(&mut self, ty: &mut P) { match ty.kind { - ast::TyKind::MacCall(_) => {} - _ => return noop_visit_ty(ty, self), - }; - - visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) { - ast::TyKind::MacCall(mac) => { - self.collect_bang(mac, ty.span, AstFragmentKind::Ty).make_ty() + ast::TyKind::MacCall(_) => { + visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) { + ast::TyKind::MacCall(mac) => { + self.collect_bang(mac, ty.span, AstFragmentKind::Ty).make_ty() + } + _ => unreachable!(), + }) } - _ => unreachable!(), - }); + _ => noop_visit_ty(ty, self), + } } fn flat_map_foreign_item( &mut self, - foreign_item: P, + mut foreign_item: P, ) -> SmallVec<[P; 1]> { - let mut foreign_item = configure!(self, foreign_item); - - if let Some(attr) = self.take_first_attr(&mut foreign_item) { - return self - .collect_attr( - attr, - Annotatable::ForeignItem(foreign_item), - AstFragmentKind::ForeignItems, - ) - .make_foreign_items(); - } - - match foreign_item.kind { - ast::ForeignItemKind::MacCall(..) => { - self.check_attributes(&foreign_item.attrs); - foreign_item.and_then(|item| match item.kind { - ast::ForeignItemKind::MacCall(mac) => self - .collect_bang(mac, item.span, AstFragmentKind::ForeignItems) + loop { + return match self.take_first_attr(&mut foreign_item) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() + } + sym::cfg_attr => { + foreign_item.attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + continue; + } + _ => self + .collect_attr( + (attr, pos, derives), + Annotatable::ForeignItem(foreign_item), + AstFragmentKind::ForeignItems, + ) .make_foreign_items(), - _ => unreachable!(), - }) - } - _ => noop_flat_map_foreign_item(foreign_item, self), + }, + None => match foreign_item.kind { + ast::ForeignItemKind::MacCall(..) => { + self.check_attributes(&foreign_item.attrs); + foreign_item.and_then(|item| match item.kind { + ast::ForeignItemKind::MacCall(mac) => self + .collect_bang(mac, item.span, AstFragmentKind::ForeignItems) + .make_foreign_items(), + _ => unreachable!(), + }) + } + _ => noop_flat_map_foreign_item(foreign_item, self), + }, + }; } } fn flat_map_generic_param( &mut self, - param: ast::GenericParam, + mut param: ast::GenericParam, ) -> SmallVec<[ast::GenericParam; 1]> { - let mut param = configure!(self, param); - - if let Some(attr) = self.take_first_attr(&mut param) { - return self - .collect_attr( - attr, - Annotatable::GenericParam(param), - AstFragmentKind::GenericParams, - ) - .make_generic_params(); + loop { + return match self.take_first_attr(&mut param) { + Some((attr, pos, derives)) => match attr.name_or_empty() { + sym::cfg => { + if self.cfg.cfg_true(&attr) { + continue; + } + Default::default() + } + sym::cfg_attr => { + param.visit_attrs(|attrs| { + attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr)); + }); + continue; + } + _ => self + .collect_attr( + (attr, pos, derives), + Annotatable::GenericParam(param), + AstFragmentKind::GenericParams, + ) + .make_generic_params(), + }, + None => noop_flat_map_generic_param(param, self), + }; } - - noop_flat_map_generic_param(param, self) } fn visit_attribute(&mut self, at: &mut ast::Attribute) { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index de9c1882c7d48..f452ea53b8a1e 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1252,7 +1252,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display())); if builder.is_fuse_ld_lld(compiler.host) { hostflags.push("-Clink-args=-fuse-ld=lld".to_string()); - hostflags.push("-Clink-arg=-Wl,--threads=1".to_string()); + // hostflags.push("-Clink-arg=-Wl,--threads=1".to_string()); } cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); @@ -1260,7 +1260,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display())); if builder.is_fuse_ld_lld(target) { targetflags.push("-Clink-args=-fuse-ld=lld".to_string()); - targetflags.push("-Clink-arg=-Wl,--threads=1".to_string()); + // targetflags.push("-Clink-arg=-Wl,--threads=1".to_string()); } cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); diff --git a/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.rs b/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.rs index 4c96d6e7ca17d..d909dd6c19e9c 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.rs @@ -1,13 +1,14 @@ // Check that `#[cfg_attr($PREDICATE,)]` triggers the `unused_attribute` lint. +// check-pass // compile-flags: --cfg TRUE #![deny(unused)] -#[cfg_attr(FALSE,)] //~ ERROR unused attribute +#[cfg_attr(FALSE,)] fn _f() {} -#[cfg_attr(TRUE,)] //~ ERROR unused attribute +#[cfg_attr(TRUE,)] fn _g() {} fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr b/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr deleted file mode 100644 index 67cb6530e3831..0000000000000 --- a/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error: unused attribute - --> $DIR/cfg-attr-empty-is-unused.rs:7:1 - | -LL | #[cfg_attr(FALSE,)] - | ^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/cfg-attr-empty-is-unused.rs:5:9 - | -LL | #![deny(unused)] - | ^^^^^^ - = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]` - -error: unused attribute - --> $DIR/cfg-attr-empty-is-unused.rs:10:1 - | -LL | #[cfg_attr(TRUE,)] - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs index 408eaffccf7d9..7f0648b381dbd 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -29,7 +29,6 @@ macro_rules! generate_s10 { ($expr: expr) => { #[cfg(feature = $expr)] //~^ ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")` - //~| ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")` struct S10; } } diff --git a/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index 8ae2ff16a2b4f..44063dd1d65d7 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -63,18 +63,7 @@ LL | generate_s10!(concat!("nonexistent")); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected unsuffixed literal or identifier, found `concat!("nonexistent")` - --> $DIR/cfg-attr-syntax-validation.rs:30:25 - | -LL | #[cfg(feature = $expr)] - | ^^^^^ -... -LL | generate_s10!(concat!("nonexistent")); - | -------------------------------------- in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 11 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0537, E0565. For more information about an error, try `rustc --explain E0537`. diff --git a/src/test/ui/macros/macro-attributes.rs b/src/test/ui/macros/macro-attributes.rs index d382e8b719713..267d2118732dd 100644 --- a/src/test/ui/macros/macro-attributes.rs +++ b/src/test/ui/macros/macro-attributes.rs @@ -3,7 +3,7 @@ macro_rules! compiles_fine { (#[$at:meta]) => { // test that the different types of attributes work - #[attribute] + #[rustfmt::attribute] /// Documentation! #[$at] @@ -15,9 +15,9 @@ macro_rules! compiles_fine { } // item -compiles_fine!(#[foo]); +compiles_fine!(#[doc = "foo"]); pub fn main() { // statement - compiles_fine!(#[bar]); + compiles_fine!(#[doc = "bar"]); } diff --git a/src/test/ui/proc-macro/cfg-eval-fail.rs b/src/test/ui/proc-macro/cfg-eval-fail.rs index 379491f3126b0..ca5034cbeca3e 100644 --- a/src/test/ui/proc-macro/cfg-eval-fail.rs +++ b/src/test/ui/proc-macro/cfg-eval-fail.rs @@ -5,5 +5,4 @@ fn main() { let _ = #[cfg_eval] #[cfg(FALSE)] 0; //~^ ERROR removing an expression is not supported in this position //~| ERROR removing an expression is not supported in this position - //~| ERROR removing an expression is not supported in this position } diff --git a/src/test/ui/proc-macro/cfg-eval-fail.stderr b/src/test/ui/proc-macro/cfg-eval-fail.stderr index 010ac006b0bee..69e92114ba518 100644 --- a/src/test/ui/proc-macro/cfg-eval-fail.stderr +++ b/src/test/ui/proc-macro/cfg-eval-fail.stderr @@ -10,11 +10,5 @@ error: removing an expression is not supported in this position LL | let _ = #[cfg_eval] #[cfg(FALSE)] 0; | ^^^^^^^^^^^^^ -error: removing an expression is not supported in this position - --> $DIR/cfg-eval-fail.rs:5:25 - | -LL | let _ = #[cfg_eval] #[cfg(FALSE)] 0; - | ^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/proc-macro/cfg-eval.rs b/src/test/ui/proc-macro/cfg-eval.rs index fa6d015e48eb8..2a1c4b43c7113 100644 --- a/src/test/ui/proc-macro/cfg-eval.rs +++ b/src/test/ui/proc-macro/cfg-eval.rs @@ -35,3 +35,7 @@ fn main() { let _ = #[cfg_eval] #[print_attr] #[cfg_attr(not(FALSE), rustc_dummy)] (#[cfg(FALSE)] 0, #[cfg(all(/*true*/))] 1,); } + +#[derive(Clone)] +#[cfg(FALSE)] +struct S3 {} diff --git a/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed b/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed index d592438009a48..ebb1abadeb90c 100644 --- a/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed +++ b/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed @@ -8,7 +8,8 @@ // The suggestion span should include the attribute. - +#[cfg(blandiloquence)] + //~ HELP remove it //~^ ERROR unused extern crate fn main() {} diff --git a/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs b/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs index a948baee53c4c..d0dcccba0a6ac 100644 --- a/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs +++ b/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs @@ -8,8 +8,8 @@ // The suggestion span should include the attribute. -#[cfg(blandiloquence)] //~ HELP remove it -extern crate edition_lint_paths; +#[cfg(blandiloquence)] +extern crate edition_lint_paths; //~ HELP remove it //~^ ERROR unused extern crate fn main() {} diff --git a/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr b/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr index 2ef97e7f20e9f..f6a85b7fdbe70 100644 --- a/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr +++ b/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr @@ -1,11 +1,8 @@ error: unused extern crate --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:12:1 | -LL | / #[cfg(blandiloquence)] -LL | | extern crate edition_lint_paths; - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | |________________________________| - | help: remove it +LL | extern crate edition_lint_paths; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it | note: the lint level is defined here --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:6:9