]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_expand/src/expand.rs
New upstream version 1.50.0+dfsg1
[rustc.git] / compiler / rustc_expand / src / expand.rs
index 1b31bd6a30510dfe995e242ca743f8e9176e75c7..2da5bde028fc12925b98a88700ed5068bc2481a5 100644 (file)
@@ -209,6 +209,28 @@ impl AstFragmentKind {
         self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment")
     }
 
+    /// Fragment supports macro expansion and not just inert attributes, `cfg` and `cfg_attr`.
+    pub fn supports_macro_expansion(self) -> bool {
+        match self {
+            AstFragmentKind::OptExpr
+            | AstFragmentKind::Expr
+            | AstFragmentKind::Pat
+            | AstFragmentKind::Ty
+            | AstFragmentKind::Stmts
+            | AstFragmentKind::Items
+            | AstFragmentKind::TraitItems
+            | AstFragmentKind::ImplItems
+            | AstFragmentKind::ForeignItems => true,
+            AstFragmentKind::Arms
+            | AstFragmentKind::Fields
+            | AstFragmentKind::FieldPats
+            | AstFragmentKind::GenericParams
+            | AstFragmentKind::Params
+            | AstFragmentKind::StructFields
+            | AstFragmentKind::Variants => false,
+        }
+    }
+
     fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
         self,
         items: I,
@@ -404,6 +426,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     // Recursively expand all macro invocations in this AST fragment.
     pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment {
         let orig_expansion_data = self.cx.current_expansion.clone();
+        let orig_force_mode = self.cx.force_mode;
         self.cx.current_expansion.depth = 0;
 
         // Collect all macro invocations and replace them with placeholders.
@@ -432,6 +455,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
                 invocations = mem::take(&mut undetermined_invocations);
                 force = !mem::replace(&mut progress, false);
+                if force && self.monotonic {
+                    self.cx.sess.delay_span_bug(
+                        invocations.last().unwrap().0.span(),
+                        "expansion entered force mode without producing any errors",
+                    );
+                }
                 continue;
             };
 
@@ -460,18 +489,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
             let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data;
             self.cx.current_expansion = invoc.expansion_data.clone();
+            self.cx.force_mode = force;
 
             // FIXME(jseyfried): Refactor out the following logic
+            let fragment_kind = invoc.fragment_kind;
             let (expanded_fragment, new_invocations) = match res {
                 InvocationRes::Single(ext) => match self.expand_invoc(invoc, &ext.kind) {
                     ExpandResult::Ready(fragment) => self.collect_invocations(fragment, &[]),
-                    ExpandResult::Retry(invoc, explanation) => {
+                    ExpandResult::Retry(invoc) => {
                         if force {
-                            // We are stuck, stop retrying and produce a dummy fragment.
-                            let span = invoc.span();
-                            self.cx.span_err(span, &explanation);
-                            let fragment = invoc.fragment_kind.dummy(span);
-                            self.collect_invocations(fragment, &[])
+                            self.cx.span_bug(
+                                invoc.span(),
+                                "expansion entered force mode but is still stuck",
+                            );
                         } else {
                             // Cannot expand, will retry this invocation later.
                             undetermined_invocations
@@ -483,36 +513,45 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 InvocationRes::DeriveContainer(_exts) => {
                     // FIXME: Consider using the derive resolutions (`_exts`) immediately,
                     // instead of enqueuing the derives to be resolved again later.
-                    let (derives, item) = match invoc.kind {
+                    let (derives, mut item) = match invoc.kind {
                         InvocationKind::DeriveContainer { derives, item } => (derives, item),
                         _ => unreachable!(),
                     };
-                    if !item.derive_allowed() {
+                    let (item, derive_placeholders) = if !item.derive_allowed() {
                         self.error_derive_forbidden_on_non_adt(&derives, &item);
-                    }
+                        item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
+                        (item, Vec::new())
+                    } else {
+                        let mut item = StripUnconfigured {
+                            sess: self.cx.sess,
+                            features: self.cx.ecfg.features,
+                        }
+                        .fully_configure(item);
+                        item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
+
+                        invocations.reserve(derives.len());
+                        let derive_placeholders = derives
+                            .into_iter()
+                            .map(|path| {
+                                let expn_id = ExpnId::fresh(None);
+                                invocations.push((
+                                    Invocation {
+                                        kind: InvocationKind::Derive { path, item: item.clone() },
+                                        fragment_kind,
+                                        expansion_data: ExpansionData {
+                                            id: expn_id,
+                                            ..self.cx.current_expansion.clone()
+                                        },
+                                    },
+                                    None,
+                                ));
+                                NodeId::placeholder_from_expn_id(expn_id)
+                            })
+                            .collect::<Vec<_>>();
+                        (item, derive_placeholders)
+                    };
 
-                    let mut item = self.fully_configure(item);
-                    item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
-
-                    let mut derive_placeholders = Vec::with_capacity(derives.len());
-                    invocations.reserve(derives.len());
-                    for path in derives {
-                        let expn_id = ExpnId::fresh(None);
-                        derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id));
-                        invocations.push((
-                            Invocation {
-                                kind: InvocationKind::Derive { path, item: item.clone() },
-                                fragment_kind: invoc.fragment_kind,
-                                expansion_data: ExpansionData {
-                                    id: expn_id,
-                                    ..invoc.expansion_data.clone()
-                                },
-                            },
-                            None,
-                        ));
-                    }
-                    let fragment =
-                        invoc.fragment_kind.expect_from_annotatables(::std::iter::once(item));
+                    let fragment = fragment_kind.expect_from_annotatables(::std::iter::once(item));
                     self.collect_invocations(fragment, &derive_placeholders)
                 }
             };
@@ -526,6 +565,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
 
         self.cx.current_expansion = orig_expansion_data;
+        self.cx.force_mode = orig_force_mode;
 
         // Finally incorporate all the expanded macros into the input AST fragment.
         let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
@@ -601,48 +641,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         (fragment, invocations)
     }
 
-    fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
-        let mut cfg = StripUnconfigured { sess: &self.cx.sess, features: self.cx.ecfg.features };
-        // Since the item itself has already been configured by the InvocationCollector,
-        // we know that fold result vector will contain exactly one element
-        match item {
-            Annotatable::Item(item) => Annotatable::Item(cfg.flat_map_item(item).pop().unwrap()),
-            Annotatable::TraitItem(item) => {
-                Annotatable::TraitItem(cfg.flat_map_trait_item(item).pop().unwrap())
-            }
-            Annotatable::ImplItem(item) => {
-                Annotatable::ImplItem(cfg.flat_map_impl_item(item).pop().unwrap())
-            }
-            Annotatable::ForeignItem(item) => {
-                Annotatable::ForeignItem(cfg.flat_map_foreign_item(item).pop().unwrap())
-            }
-            Annotatable::Stmt(stmt) => {
-                Annotatable::Stmt(stmt.map(|stmt| cfg.flat_map_stmt(stmt).pop().unwrap()))
-            }
-            Annotatable::Expr(mut expr) => Annotatable::Expr({
-                cfg.visit_expr(&mut expr);
-                expr
-            }),
-            Annotatable::Arm(arm) => Annotatable::Arm(cfg.flat_map_arm(arm).pop().unwrap()),
-            Annotatable::Field(field) => {
-                Annotatable::Field(cfg.flat_map_field(field).pop().unwrap())
-            }
-            Annotatable::FieldPat(fp) => {
-                Annotatable::FieldPat(cfg.flat_map_field_pattern(fp).pop().unwrap())
-            }
-            Annotatable::GenericParam(param) => {
-                Annotatable::GenericParam(cfg.flat_map_generic_param(param).pop().unwrap())
-            }
-            Annotatable::Param(param) => {
-                Annotatable::Param(cfg.flat_map_param(param).pop().unwrap())
-            }
-            Annotatable::StructField(sf) => {
-                Annotatable::StructField(cfg.flat_map_struct_field(sf).pop().unwrap())
-            }
-            Annotatable::Variant(v) => Annotatable::Variant(cfg.flat_map_variant(v).pop().unwrap()),
-        }
-    }
-
     fn error_recursion_limit_reached(&mut self) {
         let expn_data = self.cx.current_expansion.id.expn_data();
         let suggested_limit = self.cx.ecfg.recursion_limit * 2;
@@ -735,20 +733,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         Ok(meta) => {
                             let items = match expander.expand(self.cx, span, &meta, item) {
                                 ExpandResult::Ready(items) => items,
-                                ExpandResult::Retry(item, explanation) => {
+                                ExpandResult::Retry(item) => {
                                     // Reassemble the original invocation for retrying.
-                                    return ExpandResult::Retry(
-                                        Invocation {
-                                            kind: InvocationKind::Attr {
-                                                attr,
-                                                item,
-                                                derives,
-                                                after_derive,
-                                            },
-                                            ..invoc
+                                    return ExpandResult::Retry(Invocation {
+                                        kind: InvocationKind::Attr {
+                                            attr,
+                                            item,
+                                            derives,
+                                            after_derive,
                                         },
-                                        explanation,
-                                    );
+                                        ..invoc
+                                    });
                                 }
                             };
                             fragment_kind.expect_from_annotatables(items)
@@ -772,24 +767,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             InvocationKind::Derive { path, item } => match ext {
                 SyntaxExtensionKind::Derive(expander)
                 | SyntaxExtensionKind::LegacyDerive(expander) => {
-                    if !item.derive_allowed() {
-                        return ExpandResult::Ready(fragment_kind.dummy(span));
-                    }
                     if let SyntaxExtensionKind::Derive(..) = ext {
                         self.gate_proc_macro_input(&item);
                     }
                     let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path };
                     let items = match expander.expand(self.cx, span, &meta, item) {
                         ExpandResult::Ready(items) => items,
-                        ExpandResult::Retry(item, explanation) => {
+                        ExpandResult::Retry(item) => {
                             // Reassemble the original invocation for retrying.
-                            return ExpandResult::Retry(
-                                Invocation {
-                                    kind: InvocationKind::Derive { path: meta.path, item },
-                                    ..invoc
-                                },
-                                explanation,
-                            );
+                            return ExpandResult::Retry(Invocation {
+                                kind: InvocationKind::Derive { path: meta.path, item },
+                                ..invoc
+                            });
                         }
                     };
                     fragment_kind.expect_from_annotatables(items)
@@ -806,7 +795,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             | Annotatable::TraitItem(_)
             | Annotatable::ImplItem(_)
             | Annotatable::ForeignItem(_) => return,
-            Annotatable::Stmt(_) => "statements",
+            Annotatable::Stmt(stmt) => {
+                // Attributes are stable on item statements,
+                // but unstable on all other kinds of statements
+                if stmt.is_item() {
+                    return;
+                }
+                "statements"
+            }
             Annotatable::Expr(_) => "expressions",
             Annotatable::Arm(..)
             | Annotatable::Field(..)
@@ -1034,11 +1030,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
 
     fn collect_attr(
         &mut self,
-        attr: Option<ast::Attribute>,
-        derives: Vec<Path>,
+        (attr, derives, after_derive): (Option<ast::Attribute>, Vec<Path>, bool),
         item: Annotatable,
         kind: AstFragmentKind,
-        after_derive: bool,
     ) -> AstFragment {
         self.collect(
             kind,
@@ -1054,7 +1048,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         attrs: &mut Vec<ast::Attribute>,
         after_derive: &mut bool,
     ) -> Option<ast::Attribute> {
-        let attr = attrs
+        attrs
             .iter()
             .position(|a| {
                 if a.has_name(sym::derive) {
@@ -1062,29 +1056,14 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                 }
                 !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a)
             })
-            .map(|i| attrs.remove(i));
-        if let Some(attr) = &attr {
-            if !self.cx.ecfg.custom_inner_attributes()
-                && attr.style == ast::AttrStyle::Inner
-                && !attr.has_name(sym::test)
-            {
-                feature_err(
-                    &self.cx.sess.parse_sess,
-                    sym::custom_inner_attributes,
-                    attr.span,
-                    "non-builtin inner attributes are unstable",
-                )
-                .emit();
-            }
-        }
-        attr
+            .map(|i| attrs.remove(i))
     }
 
     /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
-    fn classify_item(
+    fn take_first_attr(
         &mut self,
         item: &mut impl HasAttrs,
-    ) -> (Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool) {
+    ) -> Option<(Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)> {
         let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false);
 
         item.visit_attrs(|mut attrs| {
@@ -1092,23 +1071,23 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
             traits = collect_derives(&mut self.cx, &mut attrs);
         });
 
-        (attr, traits, after_derive)
+        if attr.is_some() || !traits.is_empty() { Some((attr, traits, after_derive)) } else { None }
     }
 
-    /// Alternative to `classify_item()` that ignores `#[derive]` so invocations fallthrough
+    /// Alternative to `take_first_attr()` that ignores `#[derive]` so invocations fallthrough
     /// to the unused-attributes lint (making it an error on statements and expressions
     /// is a breaking change)
-    fn classify_nonitem(
+    fn take_first_attr_no_derive(
         &mut self,
         nonitem: &mut impl HasAttrs,
-    ) -> (Option<ast::Attribute>, /* after_derive */ bool) {
+    ) -> Option<(Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)> {
         let (mut attr, mut after_derive) = (None, false);
 
         nonitem.visit_attrs(|mut attrs| {
             attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
         });
 
-        (attr, after_derive)
+        attr.map(|attr| (Some(attr), Vec::new(), after_derive))
     }
 
     fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
@@ -1152,23 +1131,16 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         visit_clobber(expr.deref_mut(), |mut expr| {
             self.cfg.configure_expr_kind(&mut expr.kind);
 
-            // ignore derives so they remain unused
-            let (attr, after_derive) = self.classify_nonitem(&mut expr);
-
-            if let Some(ref attr_value) = attr {
+            if let Some(attr) = self.take_first_attr_no_derive(&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_value);
+                if let Some(attr) = attr.0.as_ref() {
+                    self.cfg.maybe_emit_expr_attr_err(attr)
+                }
 
                 // AstFragmentKind::Expr requires the macro to emit an expression.
                 return self
-                    .collect_attr(
-                        attr,
-                        vec![],
-                        Annotatable::Expr(P(expr)),
-                        AstFragmentKind::Expr,
-                        after_derive,
-                    )
+                    .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::Expr)
                     .make_expr()
                     .into_inner();
             }
@@ -1186,16 +1158,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
         let mut arm = configure!(self, arm);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut arm);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut arm) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::Arm(arm),
-                    AstFragmentKind::Arms,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::Arm(arm), AstFragmentKind::Arms)
                 .make_arms();
         }
 
@@ -1205,16 +1170,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_field(&mut self, field: ast::Field) -> SmallVec<[ast::Field; 1]> {
         let mut field = configure!(self, field);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut field);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut field) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::Field(field),
-                    AstFragmentKind::Fields,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::Field(field), AstFragmentKind::Fields)
                 .make_fields();
         }
 
@@ -1224,16 +1182,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_field_pattern(&mut self, fp: ast::FieldPat) -> SmallVec<[ast::FieldPat; 1]> {
         let mut fp = configure!(self, fp);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut fp);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut fp) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::FieldPat(fp),
-                    AstFragmentKind::FieldPats,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::FieldPat(fp), AstFragmentKind::FieldPats)
                 .make_field_patterns();
         }
 
@@ -1243,16 +1194,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
         let mut p = configure!(self, p);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut p);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut p) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::Param(p),
-                    AstFragmentKind::Params,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::Param(p), AstFragmentKind::Params)
                 .make_params();
         }
 
@@ -1262,16 +1206,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_struct_field(&mut self, sf: ast::StructField) -> SmallVec<[ast::StructField; 1]> {
         let mut sf = configure!(self, sf);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut sf);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut sf) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::StructField(sf),
-                    AstFragmentKind::StructFields,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::StructField(sf), AstFragmentKind::StructFields)
                 .make_struct_fields();
         }
 
@@ -1281,16 +1218,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
         let mut variant = configure!(self, variant);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut variant);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut variant) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::Variant(variant),
-                    AstFragmentKind::Variants,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::Variant(variant), AstFragmentKind::Variants)
                 .make_variants();
         }
 
@@ -1302,20 +1232,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         expr.filter_map(|mut expr| {
             self.cfg.configure_expr_kind(&mut expr.kind);
 
-            // Ignore derives so they remain unused.
-            let (attr, after_derive) = self.classify_nonitem(&mut expr);
-
-            if let Some(ref attr_value) = attr {
-                self.cfg.maybe_emit_expr_attr_err(attr_value);
+            if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
+                if let Some(attr) = attr.0.as_ref() {
+                    self.cfg.maybe_emit_expr_attr_err(attr)
+                }
 
                 return self
-                    .collect_attr(
-                        attr,
-                        vec![],
-                        Annotatable::Expr(P(expr)),
-                        AstFragmentKind::OptExpr,
-                        after_derive,
-                    )
+                    .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr)
                     .make_opt_expr()
                     .map(|expr| expr.into_inner());
             }
@@ -1354,31 +1277,23 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
 
         // we'll expand attributes on expressions separately
         if !stmt.is_expr() {
-            let (attr, derives, after_derive) = if stmt.is_item() {
-                // FIXME: Handle custom attributes on statements (#15701)
-                (None, vec![], false)
+            let attr = if stmt.is_item() {
+                self.take_first_attr(&mut stmt)
             } else {
-                // ignore derives on non-item statements so it falls through
-                // to the unused-attributes lint
-                let (attr, after_derive) = self.classify_nonitem(&mut stmt);
-                (attr, vec![], after_derive)
+                // Ignore derives on non-item statements for backwards compatibility.
+                // This will result in a unused attribute warning
+                self.take_first_attr_no_derive(&mut stmt)
             };
 
-            if attr.is_some() || !derives.is_empty() {
+            if let Some(attr) = attr {
                 return self
-                    .collect_attr(
-                        attr,
-                        derives,
-                        Annotatable::Stmt(P(stmt)),
-                        AstFragmentKind::Stmts,
-                        after_derive,
-                    )
+                    .collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts)
                     .make_stmts();
             }
         }
 
         if let StmtKind::MacCall(mac) = stmt.kind {
-            let MacCallStmt { mac, style, attrs } = mac.into_inner();
+            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();
@@ -1395,10 +1310,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         }
 
         // The placeholder expander gives ids to statements, so we avoid folding the id here.
-        let ast::Stmt { id, kind, span, tokens } = stmt;
+        let ast::Stmt { id, kind, span } = stmt;
         noop_flat_map_stmt_kind(kind, self)
             .into_iter()
-            .map(|kind| ast::Stmt { id, kind, span, tokens: tokens.clone() })
+            .map(|kind| ast::Stmt { id, kind, span })
             .collect()
     }
 
@@ -1412,16 +1327,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         let mut item = configure!(self, item);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut item);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut item) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::Item(item),
-                    AstFragmentKind::Items,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::Item(item), AstFragmentKind::Items)
                 .make_items();
         }
 
@@ -1515,16 +1423,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
         let mut item = configure!(self, item);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut item);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut item) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::TraitItem(item),
-                    AstFragmentKind::TraitItems,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::TraitItem(item), AstFragmentKind::TraitItems)
                 .make_trait_items();
         }
 
@@ -1545,16 +1446,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
         let mut item = configure!(self, item);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut item);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut item) {
             return self
-                .collect_attr(
-                    attr,
-                    traits,
-                    Annotatable::ImplItem(item),
-                    AstFragmentKind::ImplItems,
-                    after_derive,
-                )
+                .collect_attr(attr, Annotatable::ImplItem(item), AstFragmentKind::ImplItems)
                 .make_impl_items();
         }
 
@@ -1595,16 +1489,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         &mut self,
         mut foreign_item: P<ast::ForeignItem>,
     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
-        let (attr, traits, after_derive) = self.classify_item(&mut foreign_item);
-
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut foreign_item) {
             return self
                 .collect_attr(
                     attr,
-                    traits,
                     Annotatable::ForeignItem(foreign_item),
                     AstFragmentKind::ForeignItems,
-                    after_derive,
                 )
                 .make_foreign_items();
         }
@@ -1639,15 +1529,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     ) -> SmallVec<[ast::GenericParam; 1]> {
         let mut param = configure!(self, param);
 
-        let (attr, traits, after_derive) = self.classify_item(&mut param);
-        if attr.is_some() || !traits.is_empty() {
+        if let Some(attr) = self.take_first_attr(&mut param) {
             return self
                 .collect_attr(
                     attr,
-                    traits,
                     Annotatable::GenericParam(param),
                     AstFragmentKind::GenericParams,
-                    after_derive,
                 )
                 .make_generic_params();
         }
@@ -1720,23 +1607,22 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                             items.push(ast::NestedMetaItem::MetaItem(item));
                         }
                         Err(e) => {
-                            let lit =
-                                it.meta_item().and_then(|item| item.name_value_literal()).unwrap();
+                            let lit_span = it.name_value_literal_span().unwrap();
 
                             if e.kind() == ErrorKind::InvalidData {
                                 self.cx
                                     .struct_span_err(
-                                        lit.span,
+                                        lit_span,
                                         &format!("{} wasn't a utf-8 file", filename.display()),
                                     )
-                                    .span_label(lit.span, "contains invalid utf-8")
+                                    .span_label(lit_span, "contains invalid utf-8")
                                     .emit();
                             } else {
                                 let mut err = self.cx.struct_span_err(
-                                    lit.span,
+                                    lit_span,
                                     &format!("couldn't read {}: {}", filename.display(), e),
                                 );
-                                err.span_label(lit.span, "couldn't read file");
+                                err.span_label(lit_span, "couldn't read file");
 
                                 err.emit();
                             }
@@ -1830,7 +1716,4 @@ impl<'feat> ExpansionConfig<'feat> {
     fn proc_macro_hygiene(&self) -> bool {
         self.features.map_or(false, |features| features.proc_macro_hygiene)
     }
-    fn custom_inner_attributes(&self) -> bool {
-        self.features.map_or(false, |features| features.custom_inner_attributes)
-    }
 }