about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast.rs12
-rw-r--r--compiler/rustc_ast/src/ast_traits.rs47
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs3
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs34
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs50
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/hash.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/standard_library_imports.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs8
-rw-r--r--compiler/rustc_data_structures/src/map_in_place.rs127
-rw-r--r--compiler/rustc_data_structures/src/thin_vec.rs45
-rw-r--r--compiler/rustc_driver/src/lib.rs2
-rw-r--r--compiler/rustc_expand/src/base.rs4
-rw-r--r--compiler/rustc_expand/src/build.rs6
-rw-r--r--compiler/rustc_expand/src/config.rs8
-rw-r--r--compiler/rustc_expand/src/expand.rs16
-rw-r--r--compiler/rustc_expand/src/module.rs8
-rw-r--r--compiler/rustc_expand/src/placeholders.rs2
-rw-r--r--compiler/rustc_parse/src/lib.rs4
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs8
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs17
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs2
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs24
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs14
-rw-r--r--compiler/rustc_parse/src/parser/item.rs57
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs8
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs16
42 files changed, 272 insertions, 308 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index d5180b46aaf..598bf771008 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -504,7 +504,7 @@ pub struct WhereEqPredicate {
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Crate {
-    pub attrs: Vec<Attribute>,
+    pub attrs: AttrVec,
     pub items: Vec<P<Item>>,
     pub spans: ModSpans,
     /// Must be equal to `CRATE_NODE_ID` after the crate root is expanded, but may hold
@@ -1268,7 +1268,7 @@ impl Expr {
                 id: DUMMY_NODE_ID,
                 kind: ExprKind::Err,
                 span: DUMMY_SP,
-                attrs: ThinVec::new(),
+                attrs: AttrVec::new(),
                 tokens: None,
             },
         )
@@ -2669,7 +2669,7 @@ impl VariantData {
 /// An item definition.
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Item<K = ItemKind> {
-    pub attrs: Vec<Attribute>,
+    pub attrs: AttrVec,
     pub id: NodeId,
     pub span: Span,
     pub vis: Visibility,
@@ -3036,19 +3036,19 @@ mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
     // These are in alphabetical order, which is easy to maintain.
-    static_assert_size!(AssocItem, 120);
+    static_assert_size!(AssocItem, 104);
     static_assert_size!(AssocItemKind, 32);
     static_assert_size!(Attribute, 32);
     static_assert_size!(Block, 48);
     static_assert_size!(Expr, 104);
     static_assert_size!(ExprKind, 72);
     static_assert_size!(Fn, 192);
-    static_assert_size!(ForeignItem, 112);
+    static_assert_size!(ForeignItem, 96);
     static_assert_size!(ForeignItemKind, 24);
     static_assert_size!(GenericBound, 88);
     static_assert_size!(Generics, 72);
     static_assert_size!(Impl, 200);
-    static_assert_size!(Item, 200);
+    static_assert_size!(Item, 184);
     static_assert_size!(ItemKind, 112);
     static_assert_size!(Lit, 48);
     static_assert_size!(LitKind, 24);
diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs
index 1fc5e480215..0947a71b824 100644
--- a/compiler/rustc_ast/src/ast_traits.rs
+++ b/compiler/rustc_ast/src/ast_traits.rs
@@ -270,7 +270,7 @@ pub trait HasAttrs {
     /// during token collection.
     const SUPPORTS_CUSTOM_INNER_ATTRS: bool;
     fn attrs(&self) -> &[Attribute];
-    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec));
 }
 
 macro_rules! impl_has_attrs {
@@ -283,8 +283,8 @@ macro_rules! impl_has_attrs {
                     &self.attrs
                 }
 
-                fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
-                    VecOrAttrVec::visit(&mut self.attrs, f)
+                fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
+                    f(&mut self.attrs)
                 }
             }
         )+
@@ -299,7 +299,7 @@ macro_rules! impl_has_attrs_none {
                 fn attrs(&self) -> &[Attribute] {
                     &[]
                 }
-                fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
+                fn visit_attrs(&mut self, _f: impl FnOnce(&mut AttrVec)) {}
             }
         )+
     };
@@ -330,7 +330,7 @@ impl<T: AstDeref<Target: HasAttrs>> HasAttrs for T {
     fn attrs(&self) -> &[Attribute] {
         self.ast_deref().attrs()
     }
-    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
         self.ast_deref_mut().visit_attrs(f)
     }
 }
@@ -340,7 +340,7 @@ impl<T: HasAttrs> HasAttrs for Option<T> {
     fn attrs(&self) -> &[Attribute] {
         self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
     }
-    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
         if let Some(inner) = self.as_mut() {
             inner.visit_attrs(f);
         }
@@ -362,13 +362,13 @@ impl HasAttrs for StmtKind {
         }
     }
 
-    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
         match self {
-            StmtKind::Local(local) => visit_attrvec(&mut local.attrs, f),
+            StmtKind::Local(local) => f(&mut local.attrs),
             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
             StmtKind::Item(item) => item.visit_attrs(f),
             StmtKind::Empty => {}
-            StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f),
+            StmtKind::MacCall(mac) => f(&mut mac.attrs),
         }
     }
 }
@@ -378,38 +378,11 @@ impl HasAttrs for Stmt {
     fn attrs(&self) -> &[Attribute] {
         self.kind.attrs()
     }
-    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
         self.kind.visit_attrs(f);
     }
 }
 
-/// Helper trait for the impls above. Abstracts over
-/// the two types of attribute fields that AST nodes
-/// may have (`Vec<Attribute>` or `AttrVec`).
-trait VecOrAttrVec {
-    fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
-}
-
-impl VecOrAttrVec for Vec<Attribute> {
-    fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
-        f(self)
-    }
-}
-
-impl VecOrAttrVec for AttrVec {
-    fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
-        visit_attrvec(self, f)
-    }
-}
-
-fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
-    crate::mut_visit::visit_clobber(attrs, |attrs| {
-        let mut vec = attrs.into();
-        f(&mut vec);
-        vec.into()
-    });
-}
-
 /// A newtype around an AST node that implements the traits above if the node implements them.
 pub struct AstNodeWrapper<Wrapped, Tag> {
     pub wrapped: Wrapped,
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 0d114f1366c..5b72ec2b601 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -12,7 +12,6 @@ use crate::tokenstream::{DelimSpan, Spacing, TokenTree};
 use crate::tokenstream::{LazyTokenStream, TokenStream};
 use crate::util::comments;
 
-use rustc_data_structures::thin_vec::ThinVec;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_span::source_map::BytePos;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -487,7 +486,7 @@ impl MetaItemKind {
                     id: ast::DUMMY_NODE_ID,
                     kind: ast::ExprKind::Lit(lit.clone()),
                     span: lit.span,
-                    attrs: ThinVec::new(),
+                    attrs: ast::AttrVec::new(),
                     tokens: None,
                 });
                 MacArgs::Eq(span, MacArgsEq::Ast(expr))
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 0520319e3be..458d1156ec2 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -14,7 +14,6 @@ use crate::tokenstream::*;
 
 use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::thin_vec::ThinVec;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
@@ -338,12 +337,7 @@ where
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-pub fn visit_attrs<T: MutVisitor>(attrs: &mut Vec<Attribute>, vis: &mut T) {
-    visit_vec(attrs, |attr| vis.visit_attribute(attr));
-}
-
-// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-pub fn visit_thin_attrs<T: MutVisitor>(attrs: &mut AttrVec, vis: &mut T) {
+pub fn visit_attrs<T: MutVisitor>(attrs: &mut AttrVec, vis: &mut T) {
     for attr in attrs.iter_mut() {
         vis.visit_attribute(attr);
     }
@@ -398,7 +392,7 @@ pub fn noop_flat_map_pat_field<T: MutVisitor>(
     vis.visit_ident(ident);
     vis.visit_pat(pat);
     vis.visit_span(span);
-    visit_thin_attrs(attrs, vis);
+    visit_attrs(attrs, vis);
     smallvec![fp]
 }
 
@@ -424,7 +418,7 @@ pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
 
 pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> {
     let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm;
-    visit_thin_attrs(attrs, vis);
+    visit_attrs(attrs, vis);
     vis.visit_id(id);
     vis.visit_pat(pat);
     visit_opt(guard, |guard| vis.visit_expr(guard));
@@ -507,7 +501,7 @@ pub fn noop_flat_map_variant<T: MutVisitor>(
     let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
     visitor.visit_ident(ident);
     visitor.visit_vis(vis);
-    visit_thin_attrs(attrs, visitor);
+    visit_attrs(attrs, visitor);
     visitor.visit_id(id);
     visitor.visit_variant_data(data);
     visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr));
@@ -589,7 +583,7 @@ pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
         }
     }
     vis.visit_span(span);
-    visit_thin_attrs(attrs, vis);
+    visit_attrs(attrs, vis);
     visit_lazy_tts(tokens, vis);
 }
 
@@ -640,7 +634,7 @@ pub fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) {
 pub fn noop_flat_map_param<T: MutVisitor>(mut param: Param, vis: &mut T) -> SmallVec<[Param; 1]> {
     let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param;
     vis.visit_id(id);
-    visit_thin_attrs(attrs, vis);
+    visit_attrs(attrs, vis);
     vis.visit_pat(pat);
     vis.visit_span(span);
     vis.visit_ty(ty);
@@ -882,7 +876,7 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>(
     if let Some(ref mut colon_span) = colon_span {
         vis.visit_span(colon_span);
     }
-    visit_thin_attrs(attrs, vis);
+    visit_attrs(attrs, vis);
     visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
     match kind {
         GenericParamKind::Lifetime => {}
@@ -978,7 +972,7 @@ pub fn noop_flat_map_field_def<T: MutVisitor>(
     visitor.visit_vis(vis);
     visitor.visit_id(id);
     visitor.visit_ty(ty);
-    visit_thin_attrs(attrs, visitor);
+    visit_attrs(attrs, visitor);
     smallvec![fd]
 }
 
@@ -991,7 +985,7 @@ pub fn noop_flat_map_expr_field<T: MutVisitor>(
     vis.visit_expr(expr);
     vis.visit_id(id);
     vis.visit_span(span);
-    visit_thin_attrs(attrs, vis);
+    visit_attrs(attrs, vis);
     smallvec![f]
 }
 
@@ -1432,7 +1426,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
     }
     vis.visit_id(id);
     vis.visit_span(span);
-    visit_thin_attrs(attrs, vis);
+    visit_attrs(attrs, vis);
     visit_lazy_tts(tokens, vis);
 }
 
@@ -1478,7 +1472,7 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
         StmtKind::MacCall(mut mac) => {
             let MacCallStmt { mac: mac_, style: _, attrs, tokens } = mac.deref_mut();
             vis.visit_mac_call(mac_);
-            visit_thin_attrs(attrs, vis);
+            visit_attrs(attrs, vis);
             visit_lazy_tts(tokens, vis);
             smallvec![StmtKind::MacCall(mac)]
         }
@@ -1513,12 +1507,6 @@ impl<T: DummyAstNode + 'static> DummyAstNode for P<T> {
     }
 }
 
-impl<T> DummyAstNode for ThinVec<T> {
-    fn dummy() -> Self {
-        Default::default()
-    }
-}
-
 impl DummyAstNode for Item {
     fn dummy() -> Self {
         Item {
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 32dbd2ff47d..bd61f4fa87a 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -6,7 +6,6 @@ use rustc_ast::attr;
 use rustc_ast::ptr::P as AstP;
 use rustc_ast::*;
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -448,12 +447,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond));
         let new_cond = self.manage_let_cond(lowered_cond);
         let then = self.lower_block_expr(body);
-        let expr_break = self.expr_break(span, ThinVec::new());
+        let expr_break = self.expr_break(span, AttrVec::new());
         let stmt_break = self.stmt_expr(span, expr_break);
         let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);
-        let else_expr = self.arena.alloc(self.expr_block(else_blk, ThinVec::new()));
+        let else_expr = self.arena.alloc(self.expr_block(else_blk, AttrVec::new()));
         let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr));
-        let if_expr = self.expr(span, if_kind, ThinVec::new());
+        let if_expr = self.expr(span, if_kind, AttrVec::new());
         let block = self.block_expr(self.arena.alloc(if_expr));
         let span = self.lower_span(span.with_hi(cond.span.hi()));
         let opt_label = self.lower_label(opt_label);
@@ -512,7 +511,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let constructor = self.arena.alloc(self.expr_lang_item_path(
             method_span,
             lang_item,
-            ThinVec::new(),
+            AttrVec::new(),
             None,
         ));
         self.expr_call(overall_span, constructor, std::slice::from_ref(expr))
@@ -635,7 +634,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let gen_future = self.expr_lang_item_path(
             unstable_span,
             hir::LangItem::FromGenerator,
-            ThinVec::new(),
+            AttrVec::new(),
             None,
         );
 
@@ -747,7 +746,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             let break_x = self.with_loop_scope(loop_node_id, move |this| {
                 let expr_break =
                     hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
-                this.arena.alloc(this.expr(gen_future_span, expr_break, ThinVec::new()))
+                this.arena.alloc(this.expr(gen_future_span, expr_break, AttrVec::new()))
             });
             self.arm(ready_pat, break_x)
         };
@@ -780,7 +779,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             let yield_expr = self.expr(
                 span,
                 hir::ExprKind::Yield(unit, hir::YieldSource::Await { expr: Some(expr_hir_id) }),
-                ThinVec::new(),
+                AttrVec::new(),
             );
             let yield_expr = self.arena.alloc(yield_expr);
 
@@ -987,7 +986,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     hir::AsyncGeneratorKind::Closure,
                     |this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
                 );
-                this.expr(fn_decl_span, async_body, ThinVec::new())
+                this.expr(fn_decl_span, async_body, AttrVec::new())
             });
             body_id
         });
@@ -1257,7 +1256,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let ident = self.expr_ident(lhs.span, ident, binding);
         let assign =
             hir::ExprKind::Assign(self.lower_expr(lhs), ident, self.lower_span(eq_sign_span));
-        let expr = self.expr(lhs.span, assign, ThinVec::new());
+        let expr = self.expr(lhs.span, assign, AttrVec::new());
         assignments.push(self.stmt_expr(lhs.span, expr));
         pat
     }
@@ -1299,7 +1298,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let fn_path =
             hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span), None);
         let fn_expr =
-            self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
+            self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), AttrVec::new()));
         hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
     }
 
@@ -1472,7 +1471,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // `None => break`
         let none_arm = {
             let break_expr =
-                self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, ThinVec::new()));
+                self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, AttrVec::new()));
             let pat = self.pat_none(for_span);
             self.arm(pat, break_expr)
         };
@@ -1481,7 +1480,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let some_arm = {
             let some_pat = self.pat_some(pat_span, pat);
             let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
-            let body_expr = self.arena.alloc(self.expr_block(body_block, ThinVec::new()));
+            let body_expr = self.arena.alloc(self.expr_block(body_block, AttrVec::new()));
             self.arm(some_pat, body_expr)
         };
 
@@ -1596,7 +1595,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             };
             attr::mk_attr_outer(allow)
         };
-        let attrs = vec![attr];
+        let attrs: AttrVec = vec![attr].into();
 
         // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
         let continue_arm = {
@@ -1606,7 +1605,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 span,
                 val_ident,
                 val_pat_nid,
-                ThinVec::from(attrs.clone()),
+                attrs.clone(),
             ));
             let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
             self.arm(continue_pat, val_expr)
@@ -1625,7 +1624,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 self.arena.alloc(residual_expr),
                 unstable_span,
             );
-            let thin_attrs = ThinVec::from(attrs);
             let ret_expr = if let Some(catch_node) = self.catch_scope {
                 let target_id = Ok(self.lower_node_id(catch_node));
                 self.arena.alloc(self.expr(
@@ -1634,13 +1632,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         hir::Destination { label: None, target_id },
                         Some(from_residual_expr),
                     ),
-                    thin_attrs,
+                    attrs,
                 ))
             } else {
                 self.arena.alloc(self.expr(
                     try_span,
                     hir::ExprKind::Ret(Some(from_residual_expr)),
-                    thin_attrs,
+                    attrs,
                 ))
             };
 
@@ -1728,7 +1726,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         arms: &'hir [hir::Arm<'hir>],
         source: hir::MatchSource,
     ) -> hir::Expr<'hir> {
-        self.expr(span, hir::ExprKind::Match(arg, arms, source), ThinVec::new())
+        self.expr(span, hir::ExprKind::Match(arg, arms, source), AttrVec::new())
     }
 
     fn expr_break(&mut self, span: Span, attrs: AttrVec) -> hir::Expr<'hir> {
@@ -1745,12 +1743,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
         self.expr(
             span,
             hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e),
-            ThinVec::new(),
+            AttrVec::new(),
         )
     }
 
     fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
-        self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]), ThinVec::new()))
+        self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]), AttrVec::new()))
     }
 
     fn expr_call_mut(
@@ -1759,7 +1757,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         e: &'hir hir::Expr<'hir>,
         args: &'hir [hir::Expr<'hir>],
     ) -> hir::Expr<'hir> {
-        self.expr(span, hir::ExprKind::Call(e, args), ThinVec::new())
+        self.expr(span, hir::ExprKind::Call(e, args), AttrVec::new())
     }
 
     fn expr_call(
@@ -1779,7 +1777,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         hir_id: Option<hir::HirId>,
     ) -> hir::Expr<'hir> {
         let path =
-            self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new(), hir_id));
+            self.arena.alloc(self.expr_lang_item_path(span, lang_item, AttrVec::new(), hir_id));
         self.expr_call_mut(span, path, args)
     }
 
@@ -1822,7 +1820,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         ident: Ident,
         binding: hir::HirId,
     ) -> hir::Expr<'hir> {
-        self.expr_ident_with_attrs(sp, ident, binding, ThinVec::new())
+        self.expr_ident_with_attrs(sp, ident, binding, AttrVec::new())
     }
 
     fn expr_ident_with_attrs(
@@ -1860,13 +1858,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 }),
                 None,
             ),
-            ThinVec::new(),
+            AttrVec::new(),
         )
     }
 
     fn expr_block_empty(&mut self, span: Span) -> &'hir hir::Expr<'hir> {
         let blk = self.block_all(span, &[], None);
-        let expr = self.expr_block(blk, ThinVec::new());
+        let expr = self.expr_block(blk, AttrVec::new());
         self.arena.alloc(expr)
     }
 
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 1a0ea8f4160..a1051d990b1 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -852,7 +852,7 @@ pub(super) fn expand_global_asm<'cx>(
             if let Some(inline_asm) = expand_preparsed_asm(ecx, args) {
                 MacEager::items(smallvec![P(ast::Item {
                     ident: Ident::empty(),
-                    attrs: Vec::new(),
+                    attrs: ast::AttrVec::new(),
                     id: ast::DUMMY_NODE_ID,
                     kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
                     vis: ast::Visibility {
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index d30fd479015..d2ee4249989 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -119,7 +119,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
                 vec![self.cx.attribute(attr::mk_list_item(
                     Ident::new(sym::allow, self.span),
                     vec![attr::mk_nested_word_item(Ident::new(sym::unused_imports, self.span))],
-                ))],
+                ))]
+                .into(),
                 ItemKind::Use(UseTree {
                     prefix: self.cx.path(self.span, self.cx.std_path(&[sym::asserting])),
                     kind: UseTreeKind::Nested(vec![
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index ee4c5aea1a3..dd7989cf48c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -68,7 +68,7 @@ pub fn expand_deriving_clone(
     }
 
     let inline = cx.meta_word(span, sym::inline);
-    let attrs = vec![cx.attribute(inline)];
+    let attrs = vec![cx.attribute(inline)].into();
     let trait_def = TraitDef {
         span,
         path: path_std!(clone::Clone),
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index f99ee8cb2d5..9b6d3e5032f 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -20,7 +20,7 @@ pub fn expand_deriving_eq(
     let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span));
     let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]);
     let no_coverage = cx.meta_word(span, sym::no_coverage);
-    let attrs = vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)];
+    let attrs = vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)].into();
     let trait_def = TraitDef {
         span,
         path: path_std!(cmp::Eq),
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index 8aa16dfeb0f..0e17b951787 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -15,7 +15,7 @@ pub fn expand_deriving_ord(
     push: &mut dyn FnMut(Annotatable),
 ) {
     let inline = cx.meta_word(span, sym::inline);
-    let attrs = vec![cx.attribute(inline)];
+    let attrs = vec![cx.attribute(inline)].into();
     let trait_def = TraitDef {
         span,
         path: path_std!(cmp::Ord),
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index 6f86092ba49..ac1325b92a6 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -68,7 +68,7 @@ pub fn expand_deriving_partial_eq(
     // No need to generate `ne`, the default suffices, and not generating it is
     // faster.
     let inline = cx.meta_word(span, sym::inline);
-    let attrs = vec![cx.attribute(inline)];
+    let attrs = vec![cx.attribute(inline)].into();
     let methods = vec![MethodDef {
         name: sym::eq,
         generics: Bounds::empty(),
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 137c779f81b..7763e554017 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -19,7 +19,7 @@ pub fn expand_deriving_partial_ord(
         Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));
 
     let inline = cx.meta_word(span, sym::inline);
-    let attrs = vec![cx.attribute(inline)];
+    let attrs = vec![cx.attribute(inline)].into();
 
     let partial_cmp_def = MethodDef {
         name: sym::partial_cmp,
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index f82175af4f6..4af7fd81653 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -29,7 +29,7 @@ pub fn expand_deriving_debug(
             explicit_self: true,
             nonself_args: vec![(fmtr, sym::f)],
             ret_ty: Path(path_std!(fmt::Result)),
-            attributes: Vec::new(),
+            attributes: ast::AttrVec::new(),
             unify_fieldless_variants: false,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 show_substructure(a, b, c)
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index 47da0862b52..7174dbbe7ea 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -47,7 +47,7 @@ pub fn expand_deriving_rustc_decodable(
                 ],
                 PathKind::Std,
             )),
-            attributes: Vec::new(),
+            attributes: ast::AttrVec::new(),
             unify_fieldless_variants: false,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 decodable_substructure(a, b, c, krate)
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index a431832080c..f316f01ef66 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -2,9 +2,7 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 
 use rustc_ast as ast;
-use rustc_ast::walk_list;
-use rustc_ast::EnumDef;
-use rustc_ast::VariantData;
+use rustc_ast::{walk_list, EnumDef, VariantData};
 use rustc_errors::Applicability;
 use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
 use rustc_span::symbol::Ident;
@@ -22,7 +20,7 @@ pub fn expand_deriving_default(
     item.visit_with(&mut DetectNonVariantDefaultAttr { cx });
 
     let inline = cx.meta_word(span, sym::inline);
-    let attrs = vec![cx.attribute(inline)];
+    let attrs = vec![cx.attribute(inline)].into();
     let trait_def = TraitDef {
         span,
         path: Path::new(vec![kw::Default, sym::Default]),
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index d43c66a5fa6..b220e54238f 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -89,7 +89,7 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::pathvec_std;
 
-use rustc_ast::{ExprKind, MetaItem, Mutability};
+use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
@@ -131,7 +131,7 @@ pub fn expand_deriving_rustc_encodable(
                 ],
                 PathKind::Std,
             )),
-            attributes: Vec::new(),
+            attributes: AttrVec::new(),
             unify_fieldless_variants: false,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 encodable_substructure(a, b, c, krate)
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index a39b97d07ef..c1bbc601560 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -217,7 +217,7 @@ pub struct MethodDef<'a> {
     /// Returns type
     pub ret_ty: Ty,
 
-    pub attributes: Vec<ast::Attribute>,
+    pub attributes: ast::AttrVec,
 
     /// Can we combine fieldless variants for enums into a single match arm?
     /// If true, indicates that the trait operation uses the enum tag in some
@@ -562,7 +562,7 @@ impl<'a> TraitDef<'a> {
                     kind: ast::VisibilityKind::Inherited,
                     tokens: None,
                 },
-                attrs: Vec::new(),
+                attrs: ast::AttrVec::new(),
                 kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
                     defaultness: ast::Defaultness::Final,
                     generics: Generics::default(),
@@ -716,7 +716,7 @@ impl<'a> TraitDef<'a> {
         let self_type = cx.ty_path(path);
 
         let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived));
-        let attrs = vec![attr];
+        let attrs = vec![attr].into();
         let opt_trait_ref = Some(trait_ref);
 
         cx.item(
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index 9aa170bec14..f1f02e7ce77 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -2,7 +2,7 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::{path_std, pathvec_std};
 
-use rustc_ast::{MetaItem, Mutability};
+use rustc_ast::{AttrVec, MetaItem, Mutability};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -31,7 +31,7 @@ pub fn expand_deriving_hash(
             explicit_self: true,
             nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)],
             ret_ty: Unit,
-            attributes: vec![],
+            attributes: AttrVec::new(),
             unify_fieldless_variants: true,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 hash_substructure(a, b, c)
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index c1ca089da22..a65d0bad6de 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -164,7 +164,7 @@ fn inject_impl_of_structural_trait(
 
     // Keep the lint and stability attributes of the original item, to control
     // how the generated implementation is linted.
-    let mut attrs = Vec::new();
+    let mut attrs = ast::AttrVec::new();
     attrs.extend(
         item.attrs
             .iter()
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 36cfbba45da..2bad9bbce66 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -4,7 +4,7 @@ use rustc_ast::expand::allocator::{
     AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS,
 };
 use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
+use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
 use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -113,10 +113,10 @@ impl AllocFnFactory<'_, '_> {
         self.cx.expr_call(self.ty_span, method, args)
     }
 
-    fn attrs(&self) -> Vec<Attribute> {
+    fn attrs(&self) -> AttrVec {
         let special = sym::rustc_std_internal_symbol;
         let special = self.cx.meta_word(self.span, special);
-        vec![self.cx.attribute(special)]
+        vec![self.cx.attribute(special)].into()
     }
 
     fn arg_ty(
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 5cfda33491d..ebe1c3663e3 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -281,7 +281,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
     let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id());
 
     let proc_macro = Ident::new(sym::proc_macro, span);
-    let krate = cx.item(span, proc_macro, Vec::new(), ast::ItemKind::ExternCrate(None));
+    let krate = cx.item(span, proc_macro, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None));
 
     let bridge = Ident::new(sym::bridge, span);
     let client = Ident::new(sym::client, span);
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index 09ad5f9b3ea..90ea1e457ba 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -51,7 +51,7 @@ pub fn inject(
             cx.item(
                 span,
                 ident,
-                vec![cx.attribute(cx.meta_word(span, sym::macro_use))],
+                vec![cx.attribute(cx.meta_word(span, sym::macro_use))].into(),
                 ast::ItemKind::ExternCrate(None),
             ),
         );
@@ -78,7 +78,7 @@ pub fn inject(
     let use_item = cx.item(
         span,
         Ident::empty(),
-        vec![cx.attribute(cx.meta_word(span, sym::prelude_import))],
+        vec![cx.attribute(cx.meta_word(span, sym::prelude_import))].into(),
         ast::ItemKind::Use(ast::UseTree {
             prefix: cx.path(span, import_path),
             kind: ast::UseTreeKind::Glob,
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index e20375689f3..03c84f5ec2a 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -227,7 +227,8 @@ pub fn expand_test_or_bench(
             )),
             // #[rustc_test_marker]
             cx.attribute(cx.meta_word(attr_sp, sym::rustc_test_marker)),
-        ],
+        ]
+        .into(),
         // const $ident: test::TestDescAndFn =
         ast::ItemKind::Const(
             ast::Defaultness::Final,
@@ -334,7 +335,7 @@ pub fn expand_test_or_bench(
     });
 
     // extern crate test
-    let test_extern = cx.item(sp, test_id, vec![], ast::ItemKind::ExternCrate(None));
+    let test_extern = cx.item(sp, test_id, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None));
 
     tracing::debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
 
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 0ebe29df95f..093f0f10a38 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -298,8 +298,10 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
     let call_test_main = ecx.stmt_expr(call_test_main);
 
     // extern crate test
-    let test_extern_stmt =
-        ecx.stmt_item(sp, ecx.item(sp, test_id, vec![], ast::ItemKind::ExternCrate(None)));
+    let test_extern_stmt = ecx.stmt_item(
+        sp,
+        ecx.item(sp, test_id, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None)),
+    );
 
     // #[rustc_main]
     let main_meta = ecx.meta_word(sp, sym::rustc_main);
@@ -333,7 +335,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
 
     let main = P(ast::Item {
         ident: main_id,
-        attrs: vec![main_attr],
+        attrs: vec![main_attr].into(),
         id: ast::DUMMY_NODE_ID,
         kind: main,
         vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None },
diff --git a/compiler/rustc_data_structures/src/map_in_place.rs b/compiler/rustc_data_structures/src/map_in_place.rs
index 874de03d37a..d912211443a 100644
--- a/compiler/rustc_data_structures/src/map_in_place.rs
+++ b/compiler/rustc_data_structures/src/map_in_place.rs
@@ -1,3 +1,4 @@
+use crate::thin_vec::ThinVec;
 use smallvec::{Array, SmallVec};
 use std::ptr;
 
@@ -15,94 +16,64 @@ pub trait MapInPlace<T>: Sized {
         I: IntoIterator<Item = T>;
 }
 
-impl<T> MapInPlace<T> for Vec<T> {
-    fn flat_map_in_place<F, I>(&mut self, mut f: F)
-    where
-        F: FnMut(T) -> I,
-        I: IntoIterator<Item = T>,
-    {
-        let mut read_i = 0;
-        let mut write_i = 0;
-        unsafe {
-            let mut old_len = self.len();
-            self.set_len(0); // make sure we just leak elements in case of panic
+// The implementation of this method is syntactically identical for all the
+// different vector types.
+macro_rules! flat_map_in_place {
+    () => {
+        fn flat_map_in_place<F, I>(&mut self, mut f: F)
+        where
+            F: FnMut(T) -> I,
+            I: IntoIterator<Item = T>,
+        {
+            let mut read_i = 0;
+            let mut write_i = 0;
+            unsafe {
+                let mut old_len = self.len();
+                self.set_len(0); // make sure we just leak elements in case of panic
 
-            while read_i < old_len {
-                // move the read_i'th item out of the vector and map it
-                // to an iterator
-                let e = ptr::read(self.as_ptr().add(read_i));
-                let iter = f(e).into_iter();
-                read_i += 1;
+                while read_i < old_len {
+                    // move the read_i'th item out of the vector and map it
+                    // to an iterator
+                    let e = ptr::read(self.as_ptr().add(read_i));
+                    let iter = f(e).into_iter();
+                    read_i += 1;
 
-                for e in iter {
-                    if write_i < read_i {
-                        ptr::write(self.as_mut_ptr().add(write_i), e);
-                        write_i += 1;
-                    } else {
-                        // If this is reached we ran out of space
-                        // in the middle of the vector.
-                        // However, the vector is in a valid state here,
-                        // so we just do a somewhat inefficient insert.
-                        self.set_len(old_len);
-                        self.insert(write_i, e);
+                    for e in iter {
+                        if write_i < read_i {
+                            ptr::write(self.as_mut_ptr().add(write_i), e);
+                            write_i += 1;
+                        } else {
+                            // If this is reached we ran out of space
+                            // in the middle of the vector.
+                            // However, the vector is in a valid state here,
+                            // so we just do a somewhat inefficient insert.
+                            self.set_len(old_len);
+                            self.insert(write_i, e);
 
-                        old_len = self.len();
-                        self.set_len(0);
+                            old_len = self.len();
+                            self.set_len(0);
 
-                        read_i += 1;
-                        write_i += 1;
+                            read_i += 1;
+                            write_i += 1;
+                        }
                     }
                 }
-            }
 
-            // write_i tracks the number of actually written new items.
-            self.set_len(write_i);
+                // write_i tracks the number of actually written new items.
+                self.set_len(write_i);
+            }
         }
-    }
+    };
 }
 
-impl<T, A: Array<Item = T>> MapInPlace<T> for SmallVec<A> {
-    fn flat_map_in_place<F, I>(&mut self, mut f: F)
-    where
-        F: FnMut(T) -> I,
-        I: IntoIterator<Item = T>,
-    {
-        let mut read_i = 0;
-        let mut write_i = 0;
-        unsafe {
-            let mut old_len = self.len();
-            self.set_len(0); // make sure we just leak elements in case of panic
-
-            while read_i < old_len {
-                // move the read_i'th item out of the vector and map it
-                // to an iterator
-                let e = ptr::read(self.as_ptr().add(read_i));
-                let iter = f(e).into_iter();
-                read_i += 1;
-
-                for e in iter {
-                    if write_i < read_i {
-                        ptr::write(self.as_mut_ptr().add(write_i), e);
-                        write_i += 1;
-                    } else {
-                        // If this is reached we ran out of space
-                        // in the middle of the vector.
-                        // However, the vector is in a valid state here,
-                        // so we just do a somewhat inefficient insert.
-                        self.set_len(old_len);
-                        self.insert(write_i, e);
-
-                        old_len = self.len();
-                        self.set_len(0);
+impl<T> MapInPlace<T> for Vec<T> {
+    flat_map_in_place!();
+}
 
-                        read_i += 1;
-                        write_i += 1;
-                    }
-                }
-            }
+impl<T, A: Array<Item = T>> MapInPlace<T> for SmallVec<A> {
+    flat_map_in_place!();
+}
 
-            // write_i tracks the number of actually written new items.
-            self.set_len(write_i);
-        }
-    }
+impl<T> MapInPlace<T> for ThinVec<T> {
+    flat_map_in_place!();
 }
diff --git a/compiler/rustc_data_structures/src/thin_vec.rs b/compiler/rustc_data_structures/src/thin_vec.rs
index 716259142d1..fce42e709ab 100644
--- a/compiler/rustc_data_structures/src/thin_vec.rs
+++ b/compiler/rustc_data_structures/src/thin_vec.rs
@@ -27,6 +27,51 @@ impl<T> ThinVec<T> {
             ThinVec(None) => *self = vec![item].into(),
         }
     }
+
+    /// Note: if `set_len(0)` is called on a non-empty `ThinVec`, it will
+    /// remain in the `Some` form. This is required for some code sequences
+    /// (such as the one in `flat_map_in_place`) that call `set_len(0)` before
+    /// an operation that might panic, and then call `set_len(n)` again
+    /// afterwards.
+    pub unsafe fn set_len(&mut self, new_len: usize) {
+        match *self {
+            ThinVec(None) => {
+                // A prerequisite of `Vec::set_len` is that `new_len` must be
+                // less than or equal to capacity(). The same applies here.
+                if new_len != 0 {
+                    panic!("unsafe ThinVec::set_len({})", new_len);
+                }
+            }
+            ThinVec(Some(ref mut vec)) => vec.set_len(new_len),
+        }
+    }
+
+    pub fn insert(&mut self, index: usize, value: T) {
+        match *self {
+            ThinVec(None) => {
+                if index == 0 {
+                    *self = vec![value].into();
+                } else {
+                    panic!("invalid ThinVec::insert");
+                }
+            }
+            ThinVec(Some(ref mut vec)) => vec.insert(index, value),
+        }
+    }
+
+    pub fn remove(&mut self, index: usize) -> T {
+        match self {
+            ThinVec(None) => panic!("invalid ThinVec::remove"),
+            ThinVec(Some(vec)) => vec.remove(index),
+        }
+    }
+
+    pub fn as_slice(&self) -> &[T] {
+        match self {
+            ThinVec(None) => &[],
+            ThinVec(Some(vec)) => vec.as_slice(),
+        }
+    }
 }
 
 impl<T> From<Vec<T>> for ThinVec<T> {
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 94639bf8e1e..dac8df7dc55 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -1070,7 +1070,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     Some(matches)
 }
 
-fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<ast::Attribute>> {
+fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::AttrVec> {
     match input {
         Input::File(ifile) => rustc_parse::parse_crate_attrs_from_file(ifile, &sess.parse_sess),
         Input::Str { name, input } => rustc_parse::parse_crate_attrs_from_source_str(
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 852ea806b20..df56e032988 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -6,7 +6,7 @@ use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Nonterminal};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{AssocCtxt, Visitor};
-use rustc_ast::{self as ast, Attribute, HasAttrs, Item, NodeId, PatKind};
+use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
 use rustc_attr::{self as attr, Deprecation, Stability};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::{self, Lrc};
@@ -71,7 +71,7 @@ impl Annotatable {
         }
     }
 
-    pub fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+    pub fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
         match self {
             Annotatable::Item(item) => item.visit_attrs(f),
             Annotatable::TraitItem(trait_item) => trait_item.visit_attrs(f),
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 0440bca53b2..c4890b4a9c4 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -575,7 +575,7 @@ impl<'a> ExtCtxt<'a> {
         &self,
         span: Span,
         name: Ident,
-        attrs: Vec<ast::Attribute>,
+        attrs: ast::AttrVec,
         kind: ast::ItemKind,
     ) -> P<ast::Item> {
         // FIXME: Would be nice if our generated code didn't violate
@@ -603,7 +603,7 @@ impl<'a> ExtCtxt<'a> {
         mutbl: ast::Mutability,
         expr: P<ast::Expr>,
     ) -> P<ast::Item> {
-        self.item(span, name, Vec::new(), ast::ItemKind::Static(ty, mutbl, Some(expr)))
+        self.item(span, name, AttrVec::new(), ast::ItemKind::Static(ty, mutbl, Some(expr)))
     }
 
     pub fn item_const(
@@ -614,7 +614,7 @@ impl<'a> ExtCtxt<'a> {
         expr: P<ast::Expr>,
     ) -> P<ast::Item> {
         let def = ast::Defaultness::Final;
-        self.item(span, name, Vec::new(), ast::ItemKind::Const(def, ty, Some(expr)))
+        self.item(span, name, AttrVec::new(), ast::ItemKind::Const(def, ty, Some(expr)))
     }
 
     pub fn attribute(&self, mi: ast::MetaItem) -> ast::Attribute {
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 3e1acf4382d..48ee23d2c3d 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -215,7 +215,7 @@ pub fn features(
     let features = match strip_unconfigured.configure_krate_attrs(krate.attrs) {
         None => {
             // The entire crate is unconfigured.
-            krate.attrs = Vec::new();
+            krate.attrs = ast::AttrVec::new();
             krate.items = Vec::new();
             Features::default()
         }
@@ -265,7 +265,7 @@ impl<'a> StripUnconfigured<'a> {
         }
     }
 
-    fn configure_krate_attrs(&self, mut attrs: Vec<ast::Attribute>) -> Option<Vec<ast::Attribute>> {
+    fn configure_krate_attrs(&self, mut attrs: ast::AttrVec) -> Option<ast::AttrVec> {
         attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
         if self.in_cfg(&attrs) { Some(attrs) } else { None }
     }
@@ -292,9 +292,7 @@ impl<'a> StripUnconfigured<'a> {
             .iter()
             .flat_map(|(tree, spacing)| match tree.clone() {
                 AttrAnnotatedTokenTree::Attributes(mut data) => {
-                    let mut attrs: Vec<_> = std::mem::take(&mut data.attrs).into();
-                    attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
-                    data.attrs = attrs.into();
+                    data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
 
                     if self.in_cfg(&data.attrs) {
                         data.tokens = LazyTokenStream::new(
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index cc72dab84af..c2add852a06 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -11,7 +11,7 @@ use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AssocItemKind, AstNodeWrapper, AttrStyle, ExprKind, ForeignItemKind};
+use rustc_ast::{AssocItemKind, AstNodeWrapper, AttrStyle, AttrVec, ExprKind, ForeignItemKind};
 use rustc_ast::{HasAttrs, HasNodeId};
 use rustc_ast::{Inline, ItemKind, MacArgs, MacStmtStyle, MetaItemKind, ModKind};
 use rustc_ast::{NestedMetaItem, NodeId, PatKind, StmtKind, TyKind};
@@ -1001,7 +1001,7 @@ enum AddSemicolon {
 /// of functionality used by `InvocationCollector`.
 trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
     type OutputTy = SmallVec<[Self; 1]>;
-    type AttrsTy: Deref<Target = [ast::Attribute]> = Vec<ast::Attribute>;
+    type AttrsTy: Deref<Target = [ast::Attribute]> = ast::AttrVec;
     const KIND: AstFragmentKind;
     fn to_annotatable(self) -> Annotatable;
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy;
@@ -1333,7 +1333,7 @@ impl InvocationCollectorNode for ast::Stmt {
             }
             StmtKind::Item(item) => match item.into_inner() {
                 ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {
-                    (mac.args.need_semicolon(), mac, attrs.into())
+                    (mac.args.need_semicolon(), mac, attrs)
                 }
                 _ => unreachable!(),
             },
@@ -1390,7 +1390,7 @@ impl InvocationCollectorNode for P<ast::Ty> {
     fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
         let node = self.into_inner();
         match node.kind {
-            TyKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No),
+            TyKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No),
             _ => unreachable!(),
         }
     }
@@ -1414,7 +1414,7 @@ impl InvocationCollectorNode for P<ast::Pat> {
     fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
         let node = self.into_inner();
         match node.kind {
-            PatKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No),
+            PatKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No),
             _ => unreachable!(),
         }
     }
@@ -1646,7 +1646,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
 
     fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: ast::Attribute, pos: usize) {
         node.visit_attrs(|attrs| {
-            attrs.splice(pos..pos, self.cfg().expand_cfg_attr(attr, false));
+            // Repeated `insert` calls is inefficient, but the number of
+            // insertions is almost always 0 or 1 in practice.
+            for cfg in self.cfg().expand_cfg_attr(attr, false).into_iter().rev() {
+                attrs.insert(pos, cfg)
+            }
         });
     }
 
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index 0315d11634c..9002a24e42f 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -1,6 +1,6 @@
 use crate::base::ModuleData;
 use rustc_ast::ptr::P;
-use rustc_ast::{token, Attribute, Inline, Item, ModSpans};
+use rustc_ast::{token, AttrVec, Attribute, Inline, Item, ModSpans};
 use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_parse::new_parser_from_file;
 use rustc_parse::validate_attr;
@@ -48,7 +48,7 @@ pub(crate) fn parse_external_mod(
     span: Span, // The span to blame on errors.
     module: &ModuleData,
     mut dir_ownership: DirOwnership,
-    attrs: &mut Vec<Attribute>,
+    attrs: &mut AttrVec,
 ) -> ParsedExternalMod {
     // We bail on the first error, but that error does not cause a fatal error... (1)
     let result: Result<_, ModError<'_>> = try {
@@ -63,9 +63,9 @@ pub(crate) fn parse_external_mod(
 
         // Actually parse the external file as a module.
         let mut parser = new_parser_from_file(&sess.parse_sess, &mp.file_path, Some(span));
-        let (mut inner_attrs, items, inner_span) =
+        let (inner_attrs, items, inner_span) =
             parser.parse_mod(&token::Eof).map_err(|err| ModError::ParserError(err))?;
-        attrs.append(&mut inner_attrs);
+        attrs.extend(inner_attrs);
         (items, inner_span, mp.file_path)
     };
     // (1) ...instead, we return a dummy module.
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 48918541e72..3b0d5ddb97b 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -24,7 +24,7 @@ pub fn placeholder(
     }
 
     let ident = Ident::empty();
-    let attrs = Vec::new();
+    let attrs = ast::AttrVec::new();
     let vis = vis.unwrap_or(ast::Visibility {
         span: DUMMY_SP,
         kind: ast::VisibilityKind::Inherited,
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 5924eba9f8b..3691d82a835 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -62,7 +62,7 @@ pub fn parse_crate_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<'
 pub fn parse_crate_attrs_from_file<'a>(
     input: &Path,
     sess: &'a ParseSess,
-) -> PResult<'a, Vec<ast::Attribute>> {
+) -> PResult<'a, ast::AttrVec> {
     let mut parser = new_parser_from_file(sess, input, None);
     parser.parse_inner_attributes()
 }
@@ -79,7 +79,7 @@ pub fn parse_crate_attrs_from_source_str(
     name: FileName,
     source: String,
     sess: &ParseSess,
-) -> PResult<'_, Vec<ast::Attribute>> {
+) -> PResult<'_, ast::AttrVec> {
     new_parser_from_source_str(sess, name, source).parse_inner_attributes()
 }
 
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index acdbddf4099..72ab96b5ca6 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -34,7 +34,7 @@ enum OuterAttributeType {
 impl<'a> Parser<'a> {
     /// Parses attributes that appear before an item.
     pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> {
-        let mut outer_attrs: Vec<ast::Attribute> = Vec::new();
+        let mut outer_attrs = ast::AttrVec::new();
         let mut just_parsed_doc_comment = false;
         let start_pos = self.token_cursor.num_next_calls;
         loop {
@@ -106,7 +106,7 @@ impl<'a> Parser<'a> {
                 break;
             }
         }
-        Ok(AttrWrapper::new(outer_attrs.into(), start_pos))
+        Ok(AttrWrapper::new(outer_attrs, start_pos))
     }
 
     /// Matches `attribute = # ! [ meta_item ]`.
@@ -283,8 +283,8 @@ impl<'a> Parser<'a> {
     /// terminated by a semicolon.
     ///
     /// Matches `inner_attrs*`.
-    pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
-        let mut attrs: Vec<ast::Attribute> = vec![];
+    pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> {
+        let mut attrs = ast::AttrVec::new();
         loop {
             let start_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap();
             // Only try to parse if it is an inner attribute (has `!`).
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 6c750ff428f..ed54af9f53f 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -15,11 +15,11 @@ use std::ops::Range;
 /// for the attribute target. This allows us to perform cfg-expansion on
 /// a token stream before we invoke a derive proc-macro.
 ///
-/// This wrapper prevents direct access to the underlying `Vec<ast::Attribute>`.
+/// This wrapper prevents direct access to the underlying `ast::AttrVec>`.
 /// Parsing code can only get access to the underlying attributes
 /// by passing an `AttrWrapper` to `collect_tokens_trailing_tokens`.
 /// This makes it difficult to accidentally construct an AST node
-/// (which stores a `Vec<ast::Attribute>`) without first collecting tokens.
+/// (which stores an `ast::AttrVec`) without first collecting tokens.
 ///
 /// This struct has its own module, to ensure that the parser code
 /// cannot directly access the `attrs` field
@@ -49,9 +49,10 @@ impl AttrWrapper {
         self.attrs
     }
 
+    // Prepend `self.attrs` to `attrs`.
     // FIXME: require passing an NT to prevent misuse of this method
-    pub(crate) fn prepend_to_nt_inner(self, attrs: &mut Vec<Attribute>) {
-        let mut self_attrs: Vec<_> = self.attrs.into();
+    pub(crate) fn prepend_to_nt_inner(self, attrs: &mut AttrVec) {
+        let mut self_attrs = self.attrs.clone();
         std::mem::swap(attrs, &mut self_attrs);
         attrs.extend(self_attrs);
     }
@@ -196,7 +197,7 @@ impl<'a> Parser<'a> {
         &mut self,
         attrs: AttrWrapper,
         force_collect: ForceCollect,
-        f: impl FnOnce(&mut Self, Vec<ast::Attribute>) -> PResult<'a, (R, TrailingToken)>,
+        f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, (R, TrailingToken)>,
     ) -> PResult<'a, R> {
         // We only bail out when nothing could possibly observe the collected tokens:
         // 1. We cannot be force collecting tokens (since force-collecting requires tokens
@@ -212,7 +213,7 @@ impl<'a> Parser<'a> {
             // or `#[cfg_attr]` attributes.
             && !self.capture_cfg
         {
-            return Ok(f(self, attrs.attrs.into())?.0);
+            return Ok(f(self, attrs.attrs)?.0);
         }
 
         let start_token = (self.token.clone(), self.token_spacing);
@@ -222,7 +223,7 @@ impl<'a> Parser<'a> {
         let prev_capturing = std::mem::replace(&mut self.capture_state.capturing, Capturing::Yes);
         let replace_ranges_start = self.capture_state.replace_ranges.len();
 
-        let ret = f(self, attrs.attrs.into());
+        let ret = f(self, attrs.attrs);
 
         self.capture_state.capturing = prev_capturing;
 
@@ -352,7 +353,7 @@ impl<'a> Parser<'a> {
         // on the captured token stream.
         if self.capture_cfg
             && matches!(self.capture_state.capturing, Capturing::Yes)
-            && has_cfg_or_cfg_attr(&final_attrs)
+            && has_cfg_or_cfg_attr(final_attrs)
         {
             let attr_data = AttributesData { attrs: final_attrs.to_vec().into(), tokens };
 
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 7beec270e3b..d7facb29714 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2370,7 +2370,7 @@ impl<'a> Parser<'a> {
 
     fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option<GenericArg> {
         let snapshot = self.create_snapshot_for_diagnostic();
-        let param = match self.parse_const_param(vec![]) {
+        let param = match self.parse_const_param(AttrVec::new()) {
             Ok(param) => param,
             Err(err) => {
                 err.cancel();
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index df092f55bfa..9fb9199231f 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -950,15 +950,15 @@ impl<'a> Parser<'a> {
         &mut self,
         e0: P<Expr>,
         lo: Span,
-        mut attrs: Vec<ast::Attribute>,
+        mut attrs: ast::AttrVec,
     ) -> PResult<'a, P<Expr>> {
         // Stitch the list of outer attributes onto the return value.
         // A little bit ugly, but the best way given the current code
         // structure
         self.parse_dot_or_call_expr_with_(e0, lo).map(|expr| {
             expr.map(|mut expr| {
-                attrs.extend::<Vec<_>>(expr.attrs.into());
-                expr.attrs = attrs.into();
+                attrs.extend(expr.attrs);
+                expr.attrs = attrs;
                 expr
             })
         })
@@ -2224,7 +2224,7 @@ impl<'a> Parser<'a> {
 
             Ok((
                 Param {
-                    attrs: attrs.into(),
+                    attrs,
                     ty,
                     pat,
                     span: lo.to(this.prev_token.span),
@@ -2732,7 +2732,7 @@ impl<'a> Parser<'a> {
                     let span = body.span;
                     return Ok((
                         ast::Arm {
-                            attrs: attrs.into(),
+                            attrs,
                             pat,
                             guard,
                             body,
@@ -2810,7 +2810,7 @@ impl<'a> Parser<'a> {
 
             Ok((
                 ast::Arm {
-                    attrs: attrs.into(),
+                    attrs,
                     pat,
                     guard,
                     body: expr,
@@ -3123,7 +3123,7 @@ impl<'a> Parser<'a> {
                     span: lo.to(expr.span),
                     expr,
                     is_shorthand,
-                    attrs: attrs.into(),
+                    attrs,
                     id: DUMMY_NODE_ID,
                     is_placeholder: false,
                 },
@@ -3219,14 +3219,10 @@ impl<'a> Parser<'a> {
         await_expr
     }
 
-    pub(crate) fn mk_expr_with_attrs<A>(&self, span: Span, kind: ExprKind, attrs: A) -> P<Expr>
-    where
-        A: Into<AttrVec>,
-    {
-        P(Expr { kind, span, attrs: attrs.into(), id: DUMMY_NODE_ID, tokens: None })
+    pub(crate) fn mk_expr_with_attrs(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> {
+        P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
     }
 
-    // njn: rename
     pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> P<Expr> {
         P(Expr { kind, span, attrs: AttrVec::new(), id: DUMMY_NODE_ID, tokens: None })
     }
@@ -3248,7 +3244,7 @@ impl<'a> Parser<'a> {
     fn collect_tokens_for_expr(
         &mut self,
         attrs: AttrWrapper,
-        f: impl FnOnce(&mut Self, Vec<ast::Attribute>) -> PResult<'a, P<Expr>>,
+        f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, P<Expr>>,
     ) -> PResult<'a, P<Expr>> {
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let res = f(this, attrs)?;
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 5e5f2fd7d9f..4d0a8b05eb0 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -1,9 +1,7 @@
 use super::{ForceCollect, Parser, TrailingToken};
 
 use rustc_ast::token;
-use rustc_ast::{
-    self as ast, Attribute, GenericBounds, GenericParam, GenericParamKind, WhereClause,
-};
+use rustc_ast::{self as ast, AttrVec, GenericBounds, GenericParam, GenericParamKind, WhereClause};
 use rustc_errors::{Applicability, PResult};
 use rustc_span::symbol::kw;
 
@@ -26,7 +24,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Matches `typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?`.
-    fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, GenericParam> {
+    fn parse_ty_param(&mut self, preceding_attrs: AttrVec) -> PResult<'a, GenericParam> {
         let ident = self.parse_ident()?;
 
         // Parse optional colon and param bounds.
@@ -43,7 +41,7 @@ impl<'a> Parser<'a> {
         Ok(GenericParam {
             ident,
             id: ast::DUMMY_NODE_ID,
-            attrs: preceding_attrs.into(),
+            attrs: preceding_attrs,
             bounds,
             kind: GenericParamKind::Type { default },
             is_placeholder: false,
@@ -53,7 +51,7 @@ impl<'a> Parser<'a> {
 
     pub(crate) fn parse_const_param(
         &mut self,
-        preceding_attrs: Vec<Attribute>,
+        preceding_attrs: AttrVec,
     ) -> PResult<'a, GenericParam> {
         let const_span = self.token.span;
 
@@ -68,7 +66,7 @@ impl<'a> Parser<'a> {
         Ok(GenericParam {
             ident,
             id: ast::DUMMY_NODE_ID,
-            attrs: preceding_attrs.into(),
+            attrs: preceding_attrs,
             bounds: Vec::new(),
             kind: GenericParamKind::Const { ty, kw_span: const_span, default },
             is_placeholder: false,
@@ -109,7 +107,7 @@ impl<'a> Parser<'a> {
                         Some(ast::GenericParam {
                             ident: lifetime.ident,
                             id: lifetime.id,
-                            attrs: attrs.into(),
+                            attrs,
                             bounds,
                             kind: ast::GenericParamKind::Lifetime,
                             is_placeholder: false,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index cd3c982ce81..b743162a7e4 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -32,7 +32,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
-    fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
+    fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemInfo> {
         let unsafety = self.parse_unsafety();
         self.expect_keyword(kw::Mod)?;
         let id = self.parse_ident()?;
@@ -40,9 +40,9 @@ impl<'a> Parser<'a> {
             ModKind::Unloaded
         } else {
             self.expect(&token::OpenDelim(Delimiter::Brace))?;
-            let (mut inner_attrs, items, inner_span) =
+            let (inner_attrs, items, inner_span) =
                 self.parse_mod(&token::CloseDelim(Delimiter::Brace))?;
-            attrs.append(&mut inner_attrs);
+            attrs.extend(inner_attrs);
             ModKind::Loaded(items, Inline::Yes, inner_span)
         };
         Ok((id, ItemKind::Mod(unsafety, mod_kind)))
@@ -52,7 +52,7 @@ impl<'a> Parser<'a> {
     pub fn parse_mod(
         &mut self,
         term: &TokenKind,
-    ) -> PResult<'a, (Vec<Attribute>, Vec<P<Item>>, ModSpans)> {
+    ) -> PResult<'a, (AttrVec, Vec<P<Item>>, ModSpans)> {
         let lo = self.token.span;
         let attrs = self.parse_inner_attributes()?;
 
@@ -134,7 +134,7 @@ impl<'a> Parser<'a> {
 
     fn parse_item_common_(
         &mut self,
-        mut attrs: Vec<Attribute>,
+        mut attrs: AttrVec,
         mac_allowed: bool,
         attrs_allowed: bool,
         fn_parse_mode: FnParseMode,
@@ -198,7 +198,7 @@ impl<'a> Parser<'a> {
     /// Parses one of the items allowed by the flags.
     fn parse_item_kind(
         &mut self,
-        attrs: &mut Vec<Attribute>,
+        attrs: &mut AttrVec,
         macros_allowed: bool,
         lo: Span,
         vis: &Visibility,
@@ -534,7 +534,7 @@ impl<'a> Parser<'a> {
     /// ```
     fn parse_item_impl(
         &mut self,
-        attrs: &mut Vec<Attribute>,
+        attrs: &mut AttrVec,
         defaultness: Defaultness,
     ) -> PResult<'a, ItemInfo> {
         let unsafety = self.parse_unsafety();
@@ -661,12 +661,12 @@ impl<'a> Parser<'a> {
 
     fn parse_item_list<T>(
         &mut self,
-        attrs: &mut Vec<Attribute>,
+        attrs: &mut AttrVec,
         mut parse_item: impl FnMut(&mut Parser<'a>) -> PResult<'a, Option<Option<T>>>,
     ) -> PResult<'a, Vec<T>> {
         let open_brace_span = self.token.span;
         self.expect(&token::OpenDelim(Delimiter::Brace))?;
-        attrs.append(&mut self.parse_inner_attributes()?);
+        attrs.extend(self.parse_inner_attributes()?);
 
         let mut items = Vec::new();
         while !self.eat(&token::CloseDelim(Delimiter::Brace)) {
@@ -775,7 +775,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`.
-    fn parse_item_trait(&mut self, attrs: &mut Vec<Attribute>, lo: Span) -> PResult<'a, ItemInfo> {
+    fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> {
         let unsafety = self.parse_unsafety();
         // Parse optional `auto` prefix.
         let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No };
@@ -1061,7 +1061,7 @@ impl<'a> Parser<'a> {
     /// ```
     fn parse_item_foreign_mod(
         &mut self,
-        attrs: &mut Vec<Attribute>,
+        attrs: &mut AttrVec,
         mut unsafety: Unsafe,
     ) -> PResult<'a, ItemInfo> {
         let abi = self.parse_abi(); // ABI?
@@ -1179,7 +1179,7 @@ impl<'a> Parser<'a> {
     fn recover_const_impl(
         &mut self,
         const_span: Span,
-        attrs: &mut Vec<Attribute>,
+        attrs: &mut AttrVec,
         defaultness: Defaultness,
     ) -> PResult<'a, ItemInfo> {
         let impl_span = self.token.span;
@@ -1337,7 +1337,7 @@ impl<'a> Parser<'a> {
                     ident,
                     vis,
                     id: DUMMY_NODE_ID,
-                    attrs: variant_attrs.into(),
+                    attrs: variant_attrs,
                     data: struct_def,
                     disr_expr,
                     span: vlo.to(this.prev_token.span),
@@ -1494,7 +1494,7 @@ impl<'a> Parser<'a> {
                         ident: None,
                         id: DUMMY_NODE_ID,
                         ty,
-                        attrs: attrs.into(),
+                        attrs,
                         is_placeholder: false,
                     },
                     TrailingToken::MaybeComma,
@@ -1520,7 +1520,7 @@ impl<'a> Parser<'a> {
         adt_ty: &str,
         lo: Span,
         vis: Visibility,
-        attrs: Vec<Attribute>,
+        attrs: AttrVec,
     ) -> PResult<'a, FieldDef> {
         let mut seen_comma: bool = false;
         let a_var = self.parse_name_and_ty(adt_ty, lo, vis, attrs)?;
@@ -1650,7 +1650,7 @@ impl<'a> Parser<'a> {
         adt_ty: &str,
         lo: Span,
         vis: Visibility,
-        attrs: Vec<Attribute>,
+        attrs: AttrVec,
     ) -> PResult<'a, FieldDef> {
         let name = self.parse_field_ident(adt_ty, lo)?;
         self.expect_field_ty_separator()?;
@@ -1684,7 +1684,7 @@ impl<'a> Parser<'a> {
             vis,
             id: DUMMY_NODE_ID,
             ty,
-            attrs: attrs.into(),
+            attrs,
             is_placeholder: false,
         })
     }
@@ -1703,7 +1703,7 @@ impl<'a> Parser<'a> {
                 // We use `parse_fn` to get a span for the function
                 let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
                 if let Err(mut db) =
-                    self.parse_fn(&mut Vec::new(), fn_parse_mode, lo, &inherited_vis)
+                    self.parse_fn(&mut AttrVec::new(), fn_parse_mode, lo, &inherited_vis)
                 {
                     db.delay_as_bug();
                 }
@@ -1979,7 +1979,7 @@ impl<'a> Parser<'a> {
     /// Parse a function starting from the front matter (`const ...`) to the body `{ ... }` or `;`.
     fn parse_fn(
         &mut self,
-        attrs: &mut Vec<Attribute>,
+        attrs: &mut AttrVec,
         fn_parse_mode: FnParseMode,
         sig_lo: Span,
         vis: &Visibility,
@@ -2002,7 +2002,7 @@ impl<'a> Parser<'a> {
     /// or e.g. a block when the function is a provided one.
     fn parse_fn_body(
         &mut self,
-        attrs: &mut Vec<Attribute>,
+        attrs: &mut AttrVec,
         ident: &Ident,
         sig_hi: &mut Span,
         req_body: bool,
@@ -2017,7 +2017,7 @@ impl<'a> Parser<'a> {
             // Include the trailing semicolon in the span of the signature
             self.expect_semi()?;
             *sig_hi = self.prev_token.span;
-            (Vec::new(), None)
+            (AttrVec::new(), None)
         } else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() {
             self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))?
         } else if self.token.kind == token::Eq {
@@ -2034,7 +2034,7 @@ impl<'a> Parser<'a> {
                     Applicability::MachineApplicable,
                 )
                 .emit();
-            (Vec::new(), Some(self.mk_block_err(span)))
+            (AttrVec::new(), Some(self.mk_block_err(span)))
         } else {
             let expected = if req_body {
                 &[token::OpenDelim(Delimiter::Brace)][..]
@@ -2051,7 +2051,7 @@ impl<'a> Parser<'a> {
                     return Err(err);
                 }
             }
-            (Vec::new(), None)
+            (AttrVec::new(), None)
         };
         attrs.extend(inner_attrs);
         Ok(body)
@@ -2280,7 +2280,7 @@ impl<'a> Parser<'a> {
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
             if let Some(mut param) = this.parse_self_param()? {
-                param.attrs = attrs.into();
+                param.attrs = attrs;
                 let res = if first_param { Ok(param) } else { this.recover_bad_self_param(param) };
                 return Ok((res?, TrailingToken::None));
             }
@@ -2341,14 +2341,7 @@ impl<'a> Parser<'a> {
             let span = lo.to(this.prev_token.span);
 
             Ok((
-                Param {
-                    attrs: attrs.into(),
-                    id: ast::DUMMY_NODE_ID,
-                    is_placeholder: false,
-                    pat,
-                    span,
-                    ty,
-                },
+                Param { attrs, id: ast::DUMMY_NODE_ID, is_placeholder: false, pat, span, ty },
                 TrailingToken::None,
             ))
         })
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 42bf8898447..8b3200d45fc 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -4,8 +4,8 @@ use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter};
 use rustc_ast::{
-    self as ast, Attribute, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat, PatField,
-    PatKind, Path, QSelf, RangeEnd, RangeSyntax,
+    self as ast, AttrVec, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat, PatField, PatKind,
+    Path, QSelf, RangeEnd, RangeSyntax,
 };
 use rustc_ast_pretty::pprust;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
@@ -1093,7 +1093,7 @@ impl<'a> Parser<'a> {
             .emit();
     }
 
-    fn parse_pat_field(&mut self, lo: Span, attrs: Vec<Attribute>) -> PResult<'a, PatField> {
+    fn parse_pat_field(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, PatField> {
         // Check if a colon exists one ahead. This means we're parsing a fieldname.
         let hi;
         let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
@@ -1134,7 +1134,7 @@ impl<'a> Parser<'a> {
             ident: fieldname,
             pat: subpat,
             is_shorthand,
-            attrs: attrs.into(),
+            attrs,
             id: ast::DUMMY_NODE_ID,
             span: lo.to(hi),
             is_placeholder: false,
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 12b1a37e022..3d957406b19 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -130,7 +130,7 @@ impl<'a> Parser<'a> {
             let path = this.parse_path(PathStyle::Expr)?;
 
             if this.eat(&token::Not) {
-                let stmt_mac = this.parse_stmt_mac(lo, attrs.into(), path)?;
+                let stmt_mac = this.parse_stmt_mac(lo, attrs, path)?;
                 if this.token == token::Semi {
                     return Ok((stmt_mac, TrailingToken::Semi));
                 } else {
@@ -190,7 +190,7 @@ impl<'a> Parser<'a> {
             // Since none of the above applied, this is an expression statement macro.
             let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
             let e = self.maybe_recover_from_bad_qpath(e)?;
-            let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
+            let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
             let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
             StmtKind::Expr(e)
         };
@@ -229,7 +229,7 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, Stmt> {
         self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
             this.expect_keyword(kw::Let)?;
-            let local = this.parse_local(attrs.into())?;
+            let local = this.parse_local(attrs)?;
             let trailing = if capture_semi && this.token.kind == token::Semi {
                 TrailingToken::Semi
             } else {
@@ -241,7 +241,7 @@ impl<'a> Parser<'a> {
 
     fn recover_local_after_let(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
-            let local = this.parse_local(attrs.into())?;
+            let local = this.parse_local(attrs)?;
             // FIXME - maybe capture semicolon in recovery?
             Ok((
                 this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)),
@@ -509,9 +509,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a block. Inner attributes are allowed.
-    pub(super) fn parse_inner_attrs_and_block(
-        &mut self,
-    ) -> PResult<'a, (Vec<Attribute>, P<Block>)> {
+    pub(super) fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (AttrVec, P<Block>)> {
         self.parse_block_common(self.token.span, BlockCheckMode::Default)
     }
 
@@ -520,8 +518,8 @@ impl<'a> Parser<'a> {
         &mut self,
         lo: Span,
         blk_mode: BlockCheckMode,
-    ) -> PResult<'a, (Vec<Attribute>, P<Block>)> {
-        maybe_whole!(self, NtBlock, |x| (Vec::new(), x));
+    ) -> PResult<'a, (AttrVec, P<Block>)> {
+        maybe_whole!(self, NtBlock, |x| (AttrVec::new(), x));
 
         self.maybe_recover_unexpected_block_label();
         if !self.eat(&token::OpenDelim(Delimiter::Brace)) {