about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-06-26 02:18:04 +0000
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-06-26 02:18:43 +0000
commit8eddf0280014972e051856dfe949054acf53c043 (patch)
tree8d4523f2bd6a218c75b5a602fa30d5cd85d8184c /src
parent8748cd92d06328af657934f6728183c10f92eefe (diff)
parent5033eca65f1dd9585aafa9cddd9d4bfd71b820c1 (diff)
downloadrust-8eddf0280014972e051856dfe949054acf53c043.tar.gz
rust-8eddf0280014972e051856dfe949054acf53c043.zip
Rollup merge of #34339 - jseyfried:thin_vec, r=petrochenkov,Manishearth
Generalize and abstract `ThinAttributes` to `ThinVec<Attribute>`.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/fold.rs12
-rw-r--r--src/librustc/hir/intravisit.rs3
-rw-r--r--src/librustc/hir/lowering.rs156
-rw-r--r--src/librustc/hir/map/blocks.rs7
-rw-r--r--src/librustc/hir/map/mod.rs3
-rw-r--r--src/librustc/hir/mod.rs10
-rw-r--r--src/librustc/lint/context.rs9
-rw-r--r--src/librustc_const_eval/check_match.rs2
-rw-r--r--src/librustc_driver/pretty.rs2
-rw-r--r--src/libsyntax/ast.rs9
-rw-r--r--src/libsyntax/attr.rs81
-rw-r--r--src/libsyntax/ext/base.rs2
-rw-r--r--src/libsyntax/ext/build.rs6
-rw-r--r--src/libsyntax/ext/expand.rs8
-rw-r--r--src/libsyntax/ext/quote.rs6
-rw-r--r--src/libsyntax/fold.rs13
-rw-r--r--src/libsyntax/lib.rs3
-rw-r--r--src/libsyntax/parse/mod.rs13
-rw-r--r--src/libsyntax/parse/parser.rs157
-rw-r--r--src/libsyntax/print/pprust.rs11
-rw-r--r--src/libsyntax/test.rs4
-rw-r--r--src/libsyntax/util/thin_vec.rs59
-rw-r--r--src/libsyntax/visit.rs7
-rw-r--r--src/libsyntax_ext/asm.rs2
-rw-r--r--src/libsyntax_ext/concat_idents.rs2
-rw-r--r--src/libsyntax_ext/deriving/debug.rs2
-rw-r--r--src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs2
27 files changed, 274 insertions, 317 deletions
diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs
index 778709035bf..78fd2bbbe0d 100644
--- a/src/librustc/hir/fold.rs
+++ b/src/librustc/hir/fold.rs
@@ -14,7 +14,6 @@
 use hir::*;
 use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_, MetaItem};
 use syntax::ast::MetaItemKind;
-use syntax::attr::ThinAttributesExt;
 use hir;
 use syntax_pos::Span;
 use syntax::codemap::{respan, Spanned};
@@ -293,8 +292,11 @@ pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P<
     })
 }
 
-pub fn fold_attrs<T: Folder>(attrs: HirVec<Attribute>, fld: &mut T) -> HirVec<Attribute> {
-    attrs.move_flat_map(|x| fld.fold_attribute(x))
+pub fn fold_attrs<T, F>(attrs: T, fld: &mut F) -> T
+    where T: Into<Vec<Attribute>> + From<Vec<Attribute>>,
+          F: Folder,
+{
+    attrs.into().move_flat_map(|x| fld.fold_attribute(x)).into()
 }
 
 pub fn noop_fold_arm<T: Folder>(Arm { attrs, pats, guard, body }: Arm, fld: &mut T) -> Arm {
@@ -462,7 +464,7 @@ pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
             pat: fld.fold_pat(pat),
             init: init.map(|e| fld.fold_expr(e)),
             span: fld.new_span(span),
-            attrs: attrs.map_thin_attrs(|attrs| fold_attrs(attrs.into(), fld).into()),
+            attrs: fold_attrs(attrs, fld),
         }
     })
 }
@@ -1079,7 +1081,7 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &
             }
         },
         span: folder.new_span(span),
-        attrs: attrs.map_thin_attrs(|attrs| fold_attrs(attrs.into(), folder).into()),
+        attrs: fold_attrs(attrs, folder),
     }
 }
 
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 9bb53065ec4..2d5c4ebf8d8 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -27,7 +27,6 @@
 
 use syntax::abi::Abi;
 use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
-use syntax::attr::ThinAttributesExt;
 use syntax::codemap::Spanned;
 use syntax_pos::Span;
 use hir::*;
@@ -757,7 +756,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             walk_list!(visitor, visit_arm, arms);
         }
         ExprClosure(_, ref function_declaration, ref body, _fn_decl_span) => {
-            visitor.visit_fn(FnKind::Closure(expression.attrs.as_attr_slice()),
+            visitor.visit_fn(FnKind::Closure(&expression.attrs),
                              function_declaration,
                              body,
                              expression.span,
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 37c437b1922..a32631ac53d 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -50,7 +50,6 @@ use session::Session;
 use std::collections::BTreeMap;
 use std::iter;
 use syntax::ast::*;
-use syntax::attr::{ThinAttributes, ThinAttributesExt};
 use syntax::ptr::P;
 use syntax::codemap::{respan, Spanned};
 use syntax::parse::token;
@@ -951,16 +950,16 @@ impl<'a> LoweringContext<'a> {
 
                     let make_call = |this: &mut LoweringContext, p, args| {
                         let path = this.core_path(e.span, p);
-                        let path = this.expr_path(path, None);
-                        this.expr_call(e.span, path, args, None)
+                        let path = this.expr_path(path, ThinVec::new());
+                        this.expr_call(e.span, path, args)
                     };
 
                     let mk_stmt_let = |this: &mut LoweringContext, bind, expr| {
-                        this.stmt_let(e.span, false, bind, expr, None)
+                        this.stmt_let(e.span, false, bind, expr)
                     };
 
                     let mk_stmt_let_mut = |this: &mut LoweringContext, bind, expr| {
-                        this.stmt_let(e.span, true, bind, expr, None)
+                        this.stmt_let(e.span, true, bind, expr)
                     };
 
                     // let placer = <placer_expr> ;
@@ -969,21 +968,21 @@ impl<'a> LoweringContext<'a> {
                                                                  placer_expr,
                                                                  e.span,
                                                                  hir::PopUnstableBlock,
-                                                                 None);
+                                                                 ThinVec::new());
                         mk_stmt_let(self, placer_ident, placer_expr)
                     };
 
                     // let mut place = Placer::make_place(placer);
                     let (s2, place_binding) = {
-                        let placer = self.expr_ident(e.span, placer_ident, None, placer_binding);
+                        let placer = self.expr_ident(e.span, placer_ident, placer_binding);
                         let call = make_call(self, &make_place, hir_vec![placer]);
                         mk_stmt_let_mut(self, place_ident, call)
                     };
 
                     // let p_ptr = Place::pointer(&mut place);
                     let (s3, p_ptr_binding) = {
-                        let agent = self.expr_ident(e.span, place_ident, None, place_binding);
-                        let args = hir_vec![self.expr_mut_addr_of(e.span, agent, None)];
+                        let agent = self.expr_ident(e.span, place_ident, place_binding);
+                        let args = hir_vec![self.expr_mut_addr_of(e.span, agent)];
                         let call = make_call(self, &place_pointer, args);
                         mk_stmt_let(self, p_ptr_ident, call)
                     };
@@ -994,11 +993,12 @@ impl<'a> LoweringContext<'a> {
                                                                 value_expr,
                                                                 e.span,
                                                                 hir::PopUnstableBlock,
-                                                                None);
+                                                                ThinVec::new());
                         self.signal_block_expr(hir_vec![],
                                                value_expr,
                                                e.span,
-                                               hir::PopUnsafeBlock(hir::CompilerGenerated), None)
+                                               hir::PopUnsafeBlock(hir::CompilerGenerated),
+                                               ThinVec::new())
                     };
 
                     // push_unsafe!({
@@ -1006,19 +1006,20 @@ impl<'a> LoweringContext<'a> {
                     //     InPlace::finalize(place)
                     // })
                     let expr = {
-                        let ptr = self.expr_ident(e.span, p_ptr_ident, None, p_ptr_binding);
+                        let ptr = self.expr_ident(e.span, p_ptr_ident, p_ptr_binding);
                         let call_move_val_init =
                             hir::StmtSemi(
                                 make_call(self, &move_val_init, hir_vec![ptr, pop_unsafe_expr]),
                                 self.next_id());
                         let call_move_val_init = respan(e.span, call_move_val_init);
 
-                        let place = self.expr_ident(e.span, place_ident, None, place_binding);
+                        let place = self.expr_ident(e.span, place_ident, place_binding);
                         let call = make_call(self, &inplace_finalize, hir_vec![place]);
                         self.signal_block_expr(hir_vec![call_move_val_init],
                                                call,
                                                e.span,
-                                               hir::PushUnsafeBlock(hir::CompilerGenerated), None)
+                                               hir::PushUnsafeBlock(hir::CompilerGenerated),
+                                               ThinVec::new())
                     };
 
                     return self.signal_block_expr(hir_vec![s1, s2, s3],
@@ -1090,7 +1091,7 @@ impl<'a> LoweringContext<'a> {
                                     rules: hir::DefaultBlock,
                                     span: span,
                                 });
-                                self.expr_block(blk, None)
+                                self.expr_block(blk, ThinVec::new())
                             }
                             _ => self.lower_expr(els),
                         }
@@ -1157,7 +1158,7 @@ impl<'a> LoweringContext<'a> {
                                                                           expr,
                                                                           e.span,
                                                                           hir::PopUnstableBlock,
-                                                                          None);
+                                                                          ThinVec::new());
                                 this.field(token::intern(s), signal_block, ast_expr.span)
                             }).collect();
                             let attrs = ast_expr.attrs.clone();
@@ -1169,7 +1170,7 @@ impl<'a> LoweringContext<'a> {
                                                hir_expr,
                                                ast_expr.span,
                                                hir::PushUnstableBlock,
-                                               None)
+                                               ThinVec::new())
                     }
 
                     use syntax::ast::RangeLimits::*;
@@ -1256,9 +1257,9 @@ impl<'a> LoweringContext<'a> {
                             ex.span = e.span;
                         }
                         // merge attributes into the inner expression.
-                        ex.attrs.update(|attrs| {
-                            attrs.prepend(e.attrs.clone())
-                        });
+                        let mut attrs = e.attrs.clone();
+                        attrs.extend::<Vec<_>>(ex.attrs.into());
+                        ex.attrs = attrs;
                         ex
                     });
                 }
@@ -1277,7 +1278,7 @@ impl<'a> LoweringContext<'a> {
                     // `<pat> => <body>`
                     let pat_arm = {
                         let body = self.lower_block(body);
-                        let body_expr = self.expr_block(body, None);
+                        let body_expr = self.expr_block(body, ThinVec::new());
                         let pat = self.lower_pat(pat);
                         self.arm(hir_vec![pat], body_expr)
                     };
@@ -1297,7 +1298,7 @@ impl<'a> LoweringContext<'a> {
                                                 attrs: hir_vec![],
                                                 pats: hir_vec![pat_under],
                                                 guard: Some(cond),
-                                                body: self.expr_block(then, None),
+                                                body: self.expr_block(then, ThinVec::new()),
                                             });
                                             else_opt.map(|else_opt| (else_opt, true))
                                         }
@@ -1328,7 +1329,7 @@ impl<'a> LoweringContext<'a> {
                     let else_arm = {
                         let pat_under = self.pat_wild(e.span);
                         let else_expr =
-                            else_opt.unwrap_or_else(|| self.expr_tuple(e.span, hir_vec![], None));
+                            else_opt.unwrap_or_else(|| self.expr_tuple(e.span, hir_vec![]));
                         self.arm(hir_vec![pat_under], else_expr)
                     };
 
@@ -1363,7 +1364,7 @@ impl<'a> LoweringContext<'a> {
                     // `<pat> => <body>`
                     let pat_arm = {
                         let body = self.lower_block(body);
-                        let body_expr = self.expr_block(body, None);
+                        let body_expr = self.expr_block(body, ThinVec::new());
                         let pat = self.lower_pat(pat);
                         self.arm(hir_vec![pat], body_expr)
                     };
@@ -1371,7 +1372,7 @@ impl<'a> LoweringContext<'a> {
                     // `_ => break`
                     let break_arm = {
                         let pat_under = self.pat_wild(e.span);
-                        let break_expr = self.expr_break(e.span, None);
+                        let break_expr = self.expr_break(e.span, ThinVec::new());
                         self.arm(hir_vec![pat_under], break_expr)
                     };
 
@@ -1382,7 +1383,7 @@ impl<'a> LoweringContext<'a> {
                                                hir::ExprMatch(sub_expr,
                                                               arms,
                                                               hir::MatchSource::WhileLetDesugar),
-                                               None);
+                                               ThinVec::new());
 
                     // `[opt_ident]: loop { ... }`
                     let loop_block = self.block_expr(match_expr);
@@ -1424,7 +1425,7 @@ impl<'a> LoweringContext<'a> {
                             id: self.next_id(),
                             node: hir::ExprBlock(body_block),
                             span: body_span,
-                            attrs: None,
+                            attrs: ThinVec::new(),
                         });
                         let pat = self.lower_pat(pat);
                         let some_pat = self.pat_some(e.span, pat);
@@ -1434,7 +1435,7 @@ impl<'a> LoweringContext<'a> {
 
                     // `::std::option::Option::None => break`
                     let break_arm = {
-                        let break_expr = self.expr_break(e.span, None);
+                        let break_expr = self.expr_break(e.span, ThinVec::new());
                         let pat = self.pat_none(e.span);
                         self.arm(hir_vec![pat], break_expr)
                     };
@@ -1450,25 +1451,26 @@ impl<'a> LoweringContext<'a> {
 
                             self.path_global(e.span, strs)
                         };
-                        let iter = self.expr_ident(e.span, iter, None, iter_pat.id);
-                        let ref_mut_iter = self.expr_mut_addr_of(e.span, iter, None);
-                        let next_path = self.expr_path(next_path, None);
-                        let next_expr = self.expr_call(e.span,
-                                                       next_path,
-                                                       hir_vec![ref_mut_iter],
-                                                       None);
+                        let iter = self.expr_ident(e.span, iter, iter_pat.id);
+                        let ref_mut_iter = self.expr_mut_addr_of(e.span, iter);
+                        let next_path = self.expr_path(next_path, ThinVec::new());
+                        let next_expr = self.expr_call(e.span, next_path, hir_vec![ref_mut_iter]);
                         let arms = hir_vec![pat_arm, break_arm];
 
                         self.expr(e.span,
                                   hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar),
-                                  None)
+                                  ThinVec::new())
                     };
 
                     // `[opt_ident]: loop { ... }`
                     let loop_block = self.block_expr(match_expr);
                     let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident));
-                    let loop_expr =
-                        P(hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: None });
+                    let loop_expr = P(hir::Expr {
+                        id: e.id,
+                        node: loop_expr,
+                        span: e.span,
+                        attrs: ThinVec::new(),
+                    });
 
                     // `mut iter => { ... }`
                     let iter_arm = self.arm(hir_vec![iter_pat], loop_expr);
@@ -1481,23 +1483,22 @@ impl<'a> LoweringContext<'a> {
                             self.path_global(e.span, strs)
                         };
 
-                        let into_iter = self.expr_path(into_iter_path, None);
-                        self.expr_call(e.span, into_iter, hir_vec![head], None)
+                        let into_iter = self.expr_path(into_iter_path, ThinVec::new());
+                        self.expr_call(e.span, into_iter, hir_vec![head])
                     };
 
                     let match_expr = self.expr_match(e.span,
                                                      into_iter_expr,
                                                      hir_vec![iter_arm],
-                                                     hir::MatchSource::ForLoopDesugar,
-                                                     None);
+                                                     hir::MatchSource::ForLoopDesugar);
 
                     // `{ let _result = ...; _result }`
                     // underscore prevents an unused_variables lint if the head diverges
                     let result_ident = self.str_to_ident("_result");
                     let (let_stmt, let_stmt_binding) =
-                        self.stmt_let(e.span, false, result_ident, match_expr, None);
+                        self.stmt_let(e.span, false, result_ident, match_expr);
 
-                    let result = self.expr_ident(e.span, result_ident, None, let_stmt_binding);
+                    let result = self.expr_ident(e.span, result_ident, let_stmt_binding);
                     let block = self.block_all(e.span, hir_vec![let_stmt], Some(result));
                     // add the attributes to the outer returned expr node
                     return self.expr_block(block, e.attrs.clone());
@@ -1524,7 +1525,7 @@ impl<'a> LoweringContext<'a> {
                     let ok_arm = {
                         let val_ident = self.str_to_ident("val");
                         let val_pat = self.pat_ident(e.span, val_ident);
-                        let val_expr = self.expr_ident(e.span, val_ident, None, val_pat.id);
+                        let val_expr = self.expr_ident(e.span, val_ident, val_pat.id);
                         let ok_pat = self.pat_ok(e.span, val_pat);
 
                         self.arm(hir_vec![ok_pat], val_expr)
@@ -1537,26 +1538,26 @@ impl<'a> LoweringContext<'a> {
                         let from_expr = {
                             let path = self.std_path(&["convert", "From", "from"]);
                             let path = self.path_global(e.span, path);
-                            let from = self.expr_path(path, None);
-                            let err_expr = self.expr_ident(e.span, err_ident, None, err_local.id);
+                            let from = self.expr_path(path, ThinVec::new());
+                            let err_expr = self.expr_ident(e.span, err_ident, err_local.id);
 
-                            self.expr_call(e.span, from, hir_vec![err_expr], None)
+                            self.expr_call(e.span, from, hir_vec![err_expr])
                         };
                         let err_expr = {
                             let path = self.std_path(&["result", "Result", "Err"]);
                             let path = self.path_global(e.span, path);
-                            let err_ctor = self.expr_path(path, None);
-                            self.expr_call(e.span, err_ctor, hir_vec![from_expr], None)
+                            let err_ctor = self.expr_path(path, ThinVec::new());
+                            self.expr_call(e.span, err_ctor, hir_vec![from_expr])
                         };
                         let err_pat = self.pat_err(e.span, err_local);
                         let ret_expr = self.expr(e.span,
-                                                 hir::Expr_::ExprRet(Some(err_expr)), None);
-
+                                                 hir::Expr_::ExprRet(Some(err_expr)),
+                                                 ThinVec::new());
                         self.arm(hir_vec![err_pat], ret_expr)
                     };
 
                     return self.expr_match(e.span, sub_expr, hir_vec![err_arm, ok_arm],
-                                           hir::MatchSource::TryDesugar, None);
+                                           hir::MatchSource::TryDesugar);
                 }
 
                 ExprKind::Mac(_) => panic!("Shouldn't exist here"),
@@ -1679,23 +1680,18 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn expr_break(&mut self, span: Span, attrs: ThinAttributes) -> P<hir::Expr> {
+    fn expr_break(&mut self, span: Span, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
         self.expr(span, hir::ExprBreak(None), attrs)
     }
 
-    fn expr_call(&mut self,
-                 span: Span,
-                 e: P<hir::Expr>,
-                 args: hir::HirVec<P<hir::Expr>>,
-                 attrs: ThinAttributes)
+    fn expr_call(&mut self, span: Span, e: P<hir::Expr>, args: hir::HirVec<P<hir::Expr>>)
                  -> P<hir::Expr> {
-        self.expr(span, hir::ExprCall(e, args), attrs)
+        self.expr(span, hir::ExprCall(e, args), ThinVec::new())
     }
 
-    fn expr_ident(&mut self, span: Span, id: Name, attrs: ThinAttributes, binding: NodeId)
-                  -> P<hir::Expr> {
+    fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> P<hir::Expr> {
         let expr_path = hir::ExprPath(None, self.path_ident(span, id));
-        let expr = self.expr(span, expr_path, attrs);
+        let expr = self.expr(span, expr_path, ThinVec::new());
 
         let def = self.resolver.definitions().map(|defs| {
             Def::Local(defs.local_def_id(binding), binding)
@@ -1705,12 +1701,11 @@ impl<'a> LoweringContext<'a> {
         expr
     }
 
-    fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>, attrs: ThinAttributes)
-                        -> P<hir::Expr> {
-        self.expr(span, hir::ExprAddrOf(hir::MutMutable, e), attrs)
+    fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> P<hir::Expr> {
+        self.expr(span, hir::ExprAddrOf(hir::MutMutable, e), ThinVec::new())
     }
 
-    fn expr_path(&mut self, path: hir::Path, attrs: ThinAttributes) -> P<hir::Expr> {
+    fn expr_path(&mut self, path: hir::Path, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
         let def = self.resolver.resolve_generated_global_path(&path, true);
         let expr = self.expr(path.span, hir::ExprPath(None, path), attrs);
         self.resolver.record_resolution(expr.id, def);
@@ -1721,19 +1716,17 @@ impl<'a> LoweringContext<'a> {
                   span: Span,
                   arg: P<hir::Expr>,
                   arms: hir::HirVec<hir::Arm>,
-                  source: hir::MatchSource,
-                  attrs: ThinAttributes)
+                  source: hir::MatchSource)
                   -> P<hir::Expr> {
-        self.expr(span, hir::ExprMatch(arg, arms, source), attrs)
+        self.expr(span, hir::ExprMatch(arg, arms, source), ThinVec::new())
     }
 
-    fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinAttributes) -> P<hir::Expr> {
+    fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
         self.expr(b.span, hir::ExprBlock(b), attrs)
     }
 
-    fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<P<hir::Expr>>, attrs: ThinAttributes)
-                  -> P<hir::Expr> {
-        self.expr(sp, hir::ExprTup(exprs), attrs)
+    fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<P<hir::Expr>>) -> P<hir::Expr> {
+        self.expr(sp, hir::ExprTup(exprs), ThinVec::new())
     }
 
     fn expr_struct(&mut self,
@@ -1741,14 +1734,14 @@ impl<'a> LoweringContext<'a> {
                    path: hir::Path,
                    fields: hir::HirVec<hir::Field>,
                    e: Option<P<hir::Expr>>,
-                   attrs: ThinAttributes) -> P<hir::Expr> {
+                   attrs: ThinVec<Attribute>) -> P<hir::Expr> {
         let def = self.resolver.resolve_generated_global_path(&path, false);
         let expr = self.expr(sp, hir::ExprStruct(path, fields, e), attrs);
         self.resolver.record_resolution(expr.id, def);
         expr
     }
 
-    fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinAttributes) -> P<hir::Expr> {
+    fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
         P(hir::Expr {
             id: self.next_id(),
             node: node,
@@ -1757,12 +1750,7 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    fn stmt_let(&mut self,
-                sp: Span,
-                mutbl: bool,
-                ident: Name,
-                ex: P<hir::Expr>,
-                attrs: ThinAttributes)
+    fn stmt_let(&mut self, sp: Span, mutbl: bool, ident: Name, ex: P<hir::Expr>)
                 -> (hir::Stmt, NodeId) {
         let pat = if mutbl {
             self.pat_ident_binding_mode(sp, ident, hir::BindByValue(hir::MutMutable))
@@ -1776,7 +1764,7 @@ impl<'a> LoweringContext<'a> {
             init: Some(ex),
             id: self.next_id(),
             span: sp,
-            attrs: attrs,
+            attrs: ThinVec::new(),
         });
         let decl = respan(sp, hir::DeclLocal(local));
         (respan(sp, hir::StmtDecl(P(decl), self.next_id())), pat_id)
@@ -1936,7 +1924,7 @@ impl<'a> LoweringContext<'a> {
                          expr: P<hir::Expr>,
                          span: Span,
                          rule: hir::BlockCheckMode,
-                         attrs: ThinAttributes)
+                         attrs: ThinVec<Attribute>)
                          -> P<hir::Expr> {
         let id = self.next_id();
         let block = P(hir::Block {
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index 5ff3cf05187..50e8c6e7ab8 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -27,7 +27,6 @@ use hir::map::{self, Node};
 use syntax::abi;
 use hir::{Block, FnDecl};
 use syntax::ast::{Attribute, Name, NodeId};
-use syntax::attr::ThinAttributesExt;
 use hir as ast;
 use syntax_pos::Span;
 use hir::intravisit::FnKind;
@@ -257,11 +256,7 @@ impl<'a> FnLikeNode<'a> {
             }
             map::NodeExpr(e) => match e.node {
                 ast::ExprClosure(_, ref decl, ref block, _fn_decl_span) =>
-                    closure(ClosureParts::new(&decl,
-                                              &block,
-                                              e.id,
-                                              e.span,
-                                              e.attrs.as_attr_slice())),
+                    closure(ClosureParts::new(&decl, &block, e.id, e.span, &e.attrs)),
                 _ => bug!("expr FnLikeNode that is not fn-like"),
             },
             _ => bug!("other FnLikeNode that is not fn-like"),
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 488177e60c7..f9fb8ac66b7 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -23,7 +23,6 @@ use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
 
 use syntax::abi::Abi;
 use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, };
-use syntax::attr::ThinAttributesExt;
 use syntax::codemap::Spanned;
 use syntax::visit;
 use syntax_pos::Span;
@@ -578,7 +577,7 @@ impl<'ast> Map<'ast> {
             Some(NodeTraitItem(ref ti)) => Some(&ti.attrs[..]),
             Some(NodeImplItem(ref ii)) => Some(&ii.attrs[..]),
             Some(NodeVariant(ref v)) => Some(&v.node.attrs[..]),
-            Some(NodeExpr(ref e)) => Some(e.attrs.as_attr_slice()),
+            Some(NodeExpr(ref e)) => Some(&*e.attrs),
             Some(NodeStmt(ref s)) => Some(s.node.attrs()),
             // unit/tuple structs take the attributes straight from
             // the struct definition.
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index c6338568c0e..a139dd152f0 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -41,10 +41,10 @@ use syntax::codemap::{self, respan, Spanned};
 use syntax::abi::Abi;
 use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
 use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
-use syntax::attr::{ThinAttributes, ThinAttributesExt};
 use syntax::parse::token::{keywords, InternedString};
 use syntax::ptr::P;
 use syntax::tokenstream::TokenTree;
+use syntax::util::ThinVec;
 
 use std::collections::BTreeMap;
 use std::fmt;
@@ -734,7 +734,7 @@ impl Stmt_ {
         match *self {
             StmtDecl(ref d, _) => d.node.attrs(),
             StmtExpr(ref e, _) |
-            StmtSemi(ref e, _) => e.attrs.as_attr_slice(),
+            StmtSemi(ref e, _) => &e.attrs,
         }
     }
 
@@ -758,7 +758,7 @@ pub struct Local {
     pub init: Option<P<Expr>>,
     pub id: NodeId,
     pub span: Span,
-    pub attrs: ThinAttributes,
+    pub attrs: ThinVec<Attribute>,
 }
 
 pub type Decl = Spanned<Decl_>;
@@ -774,7 +774,7 @@ pub enum Decl_ {
 impl Decl_ {
     pub fn attrs(&self) -> &[Attribute] {
         match *self {
-            DeclLocal(ref l) => l.attrs.as_attr_slice(),
+            DeclLocal(ref l) => &l.attrs,
             DeclItem(_) => &[]
         }
     }
@@ -819,7 +819,7 @@ pub struct Expr {
     pub id: NodeId,
     pub node: Expr_,
     pub span: Span,
-    pub attrs: ThinAttributes,
+    pub attrs: ThinVec<Attribute>,
 }
 
 impl fmt::Debug for Expr {
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 11241977b82..3e101e1934f 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -42,7 +42,6 @@ use std::mem;
 use syntax::attr::{self, AttrMetaMethods};
 use syntax::parse::token::InternedString;
 use syntax::ast;
-use syntax::attr::ThinAttributesExt;
 use syntax_pos::Span;
 use errors::DiagnosticBuilder;
 use hir;
@@ -767,7 +766,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
     }
 
     fn visit_expr(&mut self, e: &hir::Expr) {
-        self.with_lint_attrs(e.attrs.as_attr_slice(), |cx| {
+        self.with_lint_attrs(&e.attrs, |cx| {
             run_lints!(cx, check_expr, late_passes, e);
             hir_visit::walk_expr(cx, e);
         })
@@ -832,7 +831,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
     }
 
     fn visit_local(&mut self, l: &hir::Local) {
-        self.with_lint_attrs(l.attrs.as_attr_slice(), |cx| {
+        self.with_lint_attrs(&l.attrs, |cx| {
             run_lints!(cx, check_local, late_passes, l);
             hir_visit::walk_local(cx, l);
         })
@@ -928,7 +927,7 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> {
     }
 
     fn visit_expr(&mut self, e: &ast::Expr) {
-        self.with_lint_attrs(e.attrs.as_attr_slice(), |cx| {
+        self.with_lint_attrs(&e.attrs, |cx| {
             run_lints!(cx, check_expr, early_passes, e);
             ast_visit::walk_expr(cx, e);
         })
@@ -988,7 +987,7 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> {
     }
 
     fn visit_local(&mut self, l: &ast::Local) {
-        self.with_lint_attrs(l.attrs.as_attr_slice(), |cx| {
+        self.with_lint_attrs(&l.attrs, |cx| {
             run_lints!(cx, check_local, early_passes, l);
             ast_visit::walk_local(cx, l);
         })
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 173d1f513a5..c878edcd4b2 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -452,7 +452,7 @@ fn const_val_to_expr(value: &ConstVal) -> P<hir::Expr> {
         id: 0,
         node: hir::ExprLit(P(Spanned { node: node, span: DUMMY_SP })),
         span: DUMMY_SP,
-        attrs: None,
+        attrs: ast::ThinVec::new(),
     })
 }
 
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index f7905e53101..80eea76e107 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -672,7 +672,7 @@ impl fold::Folder for ReplaceBodyWithLoop {
                 node: ast::ExprKind::Loop(empty_block, None),
                 id: ast::DUMMY_NODE_ID,
                 span: syntax_pos::DUMMY_SP,
-                attrs: None,
+                attrs: ast::ThinVec::new(),
             });
 
             expr_to_block(b.rules, Some(loop_expr))
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 51f42a678ce..dcdc1e60a99 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -14,8 +14,8 @@ pub use self::TyParamBound::*;
 pub use self::UnsafeSource::*;
 pub use self::ViewPath_::*;
 pub use self::PathParameters::*;
+pub use util::ThinVec;
 
-use attr::ThinAttributes;
 use syntax_pos::{mk_sp, Span, DUMMY_SP, ExpnId};
 use codemap::{respan, Spanned};
 use abi::Abi;
@@ -835,10 +835,9 @@ pub enum StmtKind {
     /// Expr without trailing semi-colon (must have unit type).
     Expr(P<Expr>),
 
-    /// Expr with trailing semi-colon (may have any type).
     Semi(P<Expr>),
 
-    Mac(P<(Mac, MacStmtStyle, ThinAttributes)>),
+    Mac(P<(Mac, MacStmtStyle, ThinVec<Attribute>)>),
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
@@ -865,7 +864,7 @@ pub struct Local {
     pub init: Option<P<Expr>>,
     pub id: NodeId,
     pub span: Span,
-    pub attrs: ThinAttributes,
+    pub attrs: ThinVec<Attribute>,
 }
 
 /// An arm of a 'match'.
@@ -913,7 +912,7 @@ pub struct Expr {
     pub id: NodeId,
     pub node: ExprKind,
     pub span: Span,
-    pub attrs: ThinAttributes
+    pub attrs: ThinVec<Attribute>
 }
 
 impl fmt::Debug for Expr {
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 34d07291bf4..da2967e306f 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -25,6 +25,7 @@ use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
 use parse::token::InternedString;
 use parse::{ParseSess, token};
 use ptr::P;
+use util::ThinVec;
 
 use std::cell::{RefCell, Cell};
 use std::collections::HashSet;
@@ -802,80 +803,6 @@ impl IntType {
     }
 }
 
-/// A list of attributes, behind a optional box as
-/// a space optimization.
-pub type ThinAttributes = Option<Box<Vec<Attribute>>>;
-
-pub trait ThinAttributesExt {
-    fn map_thin_attrs<F>(self, f: F) -> Self
-        where F: FnOnce(Vec<Attribute>) -> Vec<Attribute>;
-    fn prepend(mut self, attrs: Self) -> Self;
-    fn append(mut self, attrs: Self) -> Self;
-    fn update<F>(&mut self, f: F)
-        where Self: Sized,
-              F: FnOnce(Self) -> Self;
-    fn as_attr_slice(&self) -> &[Attribute];
-    fn into_attr_vec(self) -> Vec<Attribute>;
-}
-
-impl ThinAttributesExt for ThinAttributes {
-    fn map_thin_attrs<F>(self, f: F) -> Self
-        where F: FnOnce(Vec<Attribute>) -> Vec<Attribute>
-    {
-        f(self.map(|b| *b).unwrap_or(Vec::new())).into_thin_attrs()
-    }
-
-    fn prepend(self, attrs: ThinAttributes) -> Self {
-        attrs.map_thin_attrs(|mut attrs| {
-            attrs.extend(self.into_attr_vec());
-            attrs
-        })
-    }
-
-    fn append(self, attrs: ThinAttributes) -> Self {
-        self.map_thin_attrs(|mut self_| {
-            self_.extend(attrs.into_attr_vec());
-            self_
-        })
-    }
-
-    fn update<F>(&mut self, f: F)
-        where Self: Sized,
-              F: FnOnce(ThinAttributes) -> ThinAttributes
-    {
-        let self_ = f(self.take());
-        *self = self_;
-    }
-
-    fn as_attr_slice(&self) -> &[Attribute] {
-        match *self {
-            Some(ref b) => b,
-            None => &[],
-        }
-    }
-
-    fn into_attr_vec(self) -> Vec<Attribute> {
-        match self {
-            Some(b) => *b,
-            None => Vec::new(),
-        }
-    }
-}
-
-pub trait AttributesExt {
-    fn into_thin_attrs(self) -> ThinAttributes;
-}
-
-impl AttributesExt for Vec<Attribute> {
-    fn into_thin_attrs(self) -> ThinAttributes {
-        if self.len() == 0 {
-            None
-        } else {
-            Some(Box::new(self))
-        }
-    }
-}
-
 pub trait HasAttrs: Sized {
     fn attrs(&self) -> &[ast::Attribute];
     fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self;
@@ -890,12 +817,12 @@ impl HasAttrs for Vec<Attribute> {
     }
 }
 
-impl HasAttrs for ThinAttributes {
+impl HasAttrs for ThinVec<Attribute> {
     fn attrs(&self) -> &[Attribute] {
-        self.as_attr_slice()
+        &self
     }
     fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
-        self.map_thin_attrs(f)
+        f(self.into()).into()
     }
 }
 
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 4a715aa1d5b..757b039fcac 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -380,7 +380,7 @@ impl DummyResult {
             id: ast::DUMMY_NODE_ID,
             node: ast::ExprKind::Lit(P(codemap::respan(sp, ast::LitKind::Bool(false)))),
             span: sp,
-            attrs: None,
+            attrs: ast::ThinVec::new(),
         })
     }
 
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 17655cc1254..f4ae23ed8be 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -530,7 +530,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
             init: Some(ex),
             id: ast::DUMMY_NODE_ID,
             span: sp,
-            attrs: None,
+            attrs: ast::ThinVec::new(),
         });
         ast::Stmt {
             id: ast::DUMMY_NODE_ID,
@@ -558,7 +558,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
             init: Some(ex),
             id: ast::DUMMY_NODE_ID,
             span: sp,
-            attrs: None,
+            attrs: ast::ThinVec::new(),
         });
         P(ast::Stmt {
             id: ast::DUMMY_NODE_ID,
@@ -601,7 +601,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
             id: ast::DUMMY_NODE_ID,
             node: node,
             span: span,
-            attrs: None,
+            attrs: ast::ThinVec::new(),
         })
     }
 
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index ff8d0f81bd0..32635f5cdd2 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -15,7 +15,7 @@ use ast;
 use attr::HasAttrs;
 use ext::mtwt;
 use attr;
-use attr::{AttrMetaMethods, ThinAttributesExt};
+use attr::AttrMetaMethods;
 use codemap::{Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use syntax_pos::{self, Span, ExpnId};
 use config::StripUnconfigured;
@@ -107,7 +107,7 @@ pub fn expand_expr(mut expr: ast::Expr, fld: &mut MacroExpander) -> P<ast::Expr>
         // expr_mac should really be expr_ext or something; it's the
         // entry-point for all syntax extensions.
         ast::ExprKind::Mac(mac) => {
-            return expand_mac_invoc(mac, None, expr.attrs.into_attr_vec(), expr.span, fld);
+            return expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, fld);
         }
 
         ast::ExprKind::While(cond, body, opt_ident) => {
@@ -444,7 +444,7 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector<Stmt> {
     };
 
     let mut fully_expanded: SmallVector<ast::Stmt> =
-        expand_mac_invoc(mac, None, attrs.into_attr_vec(), stmt.span, fld);
+        expand_mac_invoc(mac, None, attrs.into(), stmt.span, fld);
 
     // If this is a macro invocation with a semicolon, then apply that
     // semicolon to the final statement produced by expansion.
@@ -1006,7 +1006,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
         expr.and_then(|expr| match expr.node {
             ast::ExprKind::Mac(mac) =>
-                expand_mac_invoc(mac, None, expr.attrs.into_attr_vec(), expr.span, self),
+                expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, self),
             _ => Some(expand_expr(expr, self)),
         })
     }
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index 4ffcb295619..3dc7c92f016 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -251,7 +251,7 @@ pub mod rt {
                 id: ast::DUMMY_NODE_ID,
                 node: ast::ExprKind::Lit(P(self.clone())),
                 span: DUMMY_SP,
-                attrs: None,
+                attrs: ast::ThinVec::new(),
             }).to_tokens(cx)
         }
     }
@@ -282,7 +282,7 @@ pub mod rt {
                         id: ast::DUMMY_NODE_ID,
                         node: ast::ExprKind::Lit(P(dummy_spanned(lit))),
                         span: DUMMY_SP,
-                        attrs: None,
+                        attrs: ast::ThinVec::new(),
                     });
                     if *self >= 0 {
                         return lit.to_tokens(cx);
@@ -291,7 +291,7 @@ pub mod rt {
                         id: ast::DUMMY_NODE_ID,
                         node: ast::ExprKind::Unary(ast::UnOp::Neg, lit),
                         span: DUMMY_SP,
-                        attrs: None,
+                        attrs: ast::ThinVec::new(),
                     }).to_tokens(cx)
                 }
             }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 1dc7f45ddbe..b2b286c9b14 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -20,7 +20,6 @@
 
 use ast::*;
 use ast;
-use attr::{ThinAttributes, ThinAttributesExt};
 use syntax_pos::Span;
 use codemap::{Spanned, respan};
 use parse::token::{self, keywords};
@@ -332,8 +331,8 @@ pub fn fold_attrs<T: Folder>(attrs: Vec<Attribute>, fld: &mut T) -> Vec<Attribut
     attrs.move_flat_map(|x| fld.fold_attribute(x))
 }
 
-pub fn fold_thin_attrs<T: Folder>(attrs: ThinAttributes, fld: &mut T) -> ThinAttributes {
-    attrs.map_thin_attrs(|v| fold_attrs(v, fld))
+pub fn fold_thin_attrs<T: Folder>(attrs: ThinVec<Attribute>, fld: &mut T) -> ThinVec<Attribute> {
+    fold_attrs(attrs.into(), fld).into()
 }
 
 pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body}: Arm, fld: &mut T) -> Arm {
@@ -481,7 +480,7 @@ pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
         pat: fld.fold_pat(pat),
         init: init.map(|e| fld.fold_expr(e)),
         span: fld.new_span(span),
-        attrs: attrs.map_thin_attrs(|v| fold_attrs(v, fld)),
+        attrs: fold_attrs(attrs.into(), fld).into(),
     })
 }
 
@@ -1276,7 +1275,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
             ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)),
         },
         span: folder.new_span(span),
-        attrs: attrs.map_thin_attrs(|v| fold_attrs(v, folder)),
+        attrs: fold_attrs(attrs.into(), folder).into(),
     }
 }
 
@@ -1329,9 +1328,7 @@ pub fn noop_fold_stmt<T: Folder>(Stmt {node, span, id}: Stmt, folder: &mut T)
         StmtKind::Mac(mac) => SmallVector::one(Stmt {
             id: id,
             node: StmtKind::Mac(mac.map(|(mac, semi, attrs)| {
-                let mac = folder.fold_mac(mac);
-                let attrs = attrs.map_thin_attrs(|attrs| fold_attrs(attrs, folder));
-                (mac, semi, attrs)
+                (folder.fold_mac(mac), semi, fold_attrs(attrs.into(), folder).into())
             })),
             span: span,
         })
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 9c1b8175a3e..652cf68db07 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -75,6 +75,9 @@ pub mod util {
     pub mod parser_testing;
     pub mod small_vector;
     pub mod move_map;
+
+    mod thin_vec;
+    pub use self::thin_vec::ThinVec;
 }
 
 pub mod diagnostics {
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 28555dc89bc..0c5a672dfbc 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -675,6 +675,7 @@ mod tests {
     use tokenstream::{self, TokenTree};
     use util::parser_testing::{string_to_tts, string_to_parser};
     use util::parser_testing::{string_to_expr, string_to_item, string_to_stmt};
+    use util::ThinVec;
 
     // produce a syntax_pos::span
     fn sp(a: u32, b: u32) -> Span {
@@ -696,7 +697,7 @@ mod tests {
                         ),
                     }),
                     span: sp(0, 1),
-                    attrs: None,
+                    attrs: ThinVec::new(),
                    }))
     }
 
@@ -719,7 +720,7 @@ mod tests {
                             )
                         }),
                     span: sp(0, 6),
-                    attrs: None,
+                    attrs: ThinVec::new(),
                    }))
     }
 
@@ -835,10 +836,10 @@ mod tests {
                             ),
                         }),
                         span:sp(7,8),
-                        attrs: None,
+                        attrs: ThinVec::new(),
                     }))),
                     span:sp(0,8),
-                    attrs: None,
+                    attrs: ThinVec::new(),
                    }))
     }
 
@@ -858,7 +859,7 @@ mod tests {
                                ),
                             }),
                            span: sp(0,1),
-                           attrs: None})),
+                           attrs: ThinVec::new()})),
                        id: ast::DUMMY_NODE_ID,
                        span: sp(0,1)}))
 
@@ -953,7 +954,7 @@ mod tests {
                                                         ),
                                                       }),
                                                 span: sp(17,18),
-                                                attrs: None,})),
+                                                attrs: ThinVec::new()})),
                                             id: ast::DUMMY_NODE_ID,
                                             span: sp(17,19)}),
                                         expr: None,
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c04d2c37157..83401011ed4 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -37,7 +37,6 @@ use ast::{TraitItem, TraitRef};
 use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds};
 use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
 use ast::{Visibility, WhereClause};
-use attr::{ThinAttributes, ThinAttributesExt, AttributesExt};
 use ast::{BinOpKind, UnOp};
 use ast;
 use codemap::{self, CodeMap, Spanned, spanned};
@@ -57,6 +56,7 @@ use print::pprust;
 use ptr::P;
 use parse::PResult;
 use tokenstream::{self, Delimited, SequenceRepetition, TokenTree};
+use util::ThinVec;
 
 use std::collections::HashSet;
 use std::mem;
@@ -122,7 +122,7 @@ macro_rules! maybe_whole_expr {
                         _ => unreachable!()
                     };
                     let span = $p.span;
-                    Some($p.mk_expr(span.lo, span.hi, ExprKind::Path(None, pt), None))
+                    Some($p.mk_expr(span.lo, span.hi, ExprKind::Path(None, pt), ThinVec::new()))
                 }
                 token::Interpolated(token::NtBlock(_)) => {
                     // FIXME: The following avoids an issue with lexical borrowck scopes,
@@ -132,7 +132,7 @@ macro_rules! maybe_whole_expr {
                         _ => unreachable!()
                     };
                     let span = $p.span;
-                    Some($p.mk_expr(span.lo, span.hi, ExprKind::Block(b), None))
+                    Some($p.mk_expr(span.lo, span.hi, ExprKind::Block(b), ThinVec::new()))
                 }
                 _ => None
             };
@@ -318,12 +318,12 @@ pub struct ModulePathError {
 
 pub enum LhsExpr {
     NotYetParsed,
-    AttributesParsed(ThinAttributes),
+    AttributesParsed(ThinVec<Attribute>),
     AlreadyParsed(P<Expr>),
 }
 
-impl From<Option<ThinAttributes>> for LhsExpr {
-    fn from(o: Option<ThinAttributes>) -> Self {
+impl From<Option<ThinVec<Attribute>>> for LhsExpr {
+    fn from(o: Option<ThinVec<Attribute>>) -> Self {
         if let Some(attrs) = o {
             LhsExpr::AttributesParsed(attrs)
         } else {
@@ -1703,12 +1703,12 @@ impl<'a> Parser<'a> {
         let lo = self.span.lo;
         let literal = P(self.parse_lit()?);
         let hi = self.last_span.hi;
-        let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), None);
+        let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), ThinVec::new());
 
         if minus_present {
             let minus_hi = self.last_span.hi;
             let unary = self.mk_unary(UnOp::Neg, expr);
-            Ok(self.mk_expr(minus_lo, minus_hi, unary, None))
+            Ok(self.mk_expr(minus_lo, minus_hi, unary, ThinVec::new()))
         } else {
             Ok(expr)
         }
@@ -2066,13 +2066,13 @@ impl<'a> Parser<'a> {
         })
     }
 
-    pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos,
-                   node: ExprKind, attrs: ThinAttributes) -> P<Expr> {
+    pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: ExprKind, attrs: ThinVec<Attribute>)
+                   -> P<Expr> {
         P(Expr {
             id: ast::DUMMY_NODE_ID,
             node: node,
             span: mk_sp(lo, hi),
-            attrs: attrs,
+            attrs: attrs.into(),
         })
     }
 
@@ -2129,7 +2129,7 @@ impl<'a> Parser<'a> {
     }
 
     pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos,
-                       m: Mac_, attrs: ThinAttributes) -> P<Expr> {
+                       m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> {
         P(Expr {
             id: ast::DUMMY_NODE_ID,
             node: ExprKind::Mac(codemap::Spanned {node: m, span: mk_sp(lo, hi)}),
@@ -2138,7 +2138,7 @@ impl<'a> Parser<'a> {
         })
     }
 
-    pub fn mk_lit_u32(&mut self, i: u32, attrs: ThinAttributes) -> P<Expr> {
+    pub fn mk_lit_u32(&mut self, i: u32, attrs: ThinVec<Attribute>) -> P<Expr> {
         let span = &self.span;
         let lv_lit = P(codemap::Spanned {
             node: LitKind::Int(i as u64, ast::LitIntType::Unsigned(UintTy::U32)),
@@ -2179,7 +2179,7 @@ impl<'a> Parser<'a> {
         //
         // Therefore, prevent sub-parser from parsing
         // attributes by giving them a empty "already parsed" list.
-        let mut attrs = None;
+        let mut attrs = ThinVec::new();
 
         let lo = self.span.lo;
         let mut hi = self.span.hi;
@@ -2191,9 +2191,7 @@ impl<'a> Parser<'a> {
             token::OpenDelim(token::Paren) => {
                 self.bump();
 
-                let attrs = self.parse_inner_attributes()?
-                    .into_thin_attrs()
-                    .prepend(attrs);
+                attrs.extend(self.parse_inner_attributes()?);
 
                 // (e) is parenthesized e
                 // (e,) is a tuple with only one field, e
@@ -2231,9 +2229,7 @@ impl<'a> Parser<'a> {
             token::OpenDelim(token::Bracket) => {
                 self.bump();
 
-                let inner_attrs = self.parse_inner_attributes()?
-                    .into_thin_attrs();
-                attrs.update(|attrs| attrs.append(inner_attrs));
+                attrs.extend(self.parse_inner_attributes()?);
 
                 if self.check(&token::CloseDelim(token::Bracket)) {
                     // Empty vector.
@@ -2390,9 +2386,7 @@ impl<'a> Parser<'a> {
                             let mut fields = Vec::new();
                             let mut base = None;
 
-                            let attrs = attrs.append(
-                                self.parse_inner_attributes()?
-                                    .into_thin_attrs());
+                            attrs.extend(self.parse_inner_attributes()?);
 
                             while self.token != token::CloseDelim(token::Brace) {
                                 if self.eat(&token::DotDot) {
@@ -2459,25 +2453,24 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_or_use_outer_attributes(&mut self,
-                                     already_parsed_attrs: Option<ThinAttributes>)
-                                     -> PResult<'a, ThinAttributes> {
+                                     already_parsed_attrs: Option<ThinVec<Attribute>>)
+                                     -> PResult<'a, ThinVec<Attribute>> {
         if let Some(attrs) = already_parsed_attrs {
             Ok(attrs)
         } else {
-            self.parse_outer_attributes().map(|a| a.into_thin_attrs())
+            self.parse_outer_attributes().map(|a| a.into())
         }
     }
 
     /// Parse a block or unsafe block
     pub fn parse_block_expr(&mut self, lo: BytePos, blk_mode: BlockCheckMode,
-                            attrs: ThinAttributes)
+                            outer_attrs: ThinVec<Attribute>)
                             -> PResult<'a, P<Expr>> {
 
-        let outer_attrs = attrs;
         self.expect(&token::OpenDelim(token::Brace))?;
 
-        let inner_attrs = self.parse_inner_attributes()?.into_thin_attrs();
-        let attrs = outer_attrs.append(inner_attrs);
+        let mut attrs = outer_attrs;
+        attrs.extend(self.parse_inner_attributes()?);
 
         let blk = self.parse_block_tail(lo, blk_mode)?;
         return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), attrs));
@@ -2485,7 +2478,7 @@ impl<'a> Parser<'a> {
 
     /// parse a.b or a(13) or a[4] or just a
     pub fn parse_dot_or_call_expr(&mut self,
-                                  already_parsed_attrs: Option<ThinAttributes>)
+                                  already_parsed_attrs: Option<ThinVec<Attribute>>)
                                   -> PResult<'a, P<Expr>> {
         let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?;
 
@@ -2497,7 +2490,7 @@ impl<'a> Parser<'a> {
     pub fn parse_dot_or_call_expr_with(&mut self,
                                        e0: P<Expr>,
                                        lo: BytePos,
-                                       attrs: ThinAttributes)
+                                       mut attrs: ThinVec<Attribute>)
                                        -> 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
@@ -2505,12 +2498,13 @@ impl<'a> Parser<'a> {
         self.parse_dot_or_call_expr_with_(e0, lo)
         .map(|expr|
             expr.map(|mut expr| {
-                expr.attrs.update(|a| a.prepend(attrs));
+                attrs.extend::<Vec<_>>(expr.attrs.into());
+                expr.attrs = attrs;
                 match expr.node {
                     ExprKind::If(..) | ExprKind::IfLet(..) => {
-                        if !expr.attrs.as_attr_slice().is_empty() {
+                        if !expr.attrs.is_empty() {
                             // Just point to the first attribute in there...
-                            let span = expr.attrs.as_attr_slice()[0].span;
+                            let span = expr.attrs[0].span;
 
                             self.span_err(span,
                                 "attributes are not yet allowed on `if` \
@@ -2558,7 +2552,7 @@ impl<'a> Parser<'a> {
                 es.insert(0, self_value);
                 let id = spanned(ident_span.lo, ident_span.hi, ident);
                 let nd = self.mk_method_call(id, tys, es);
-                self.mk_expr(lo, hi, nd, None)
+                self.mk_expr(lo, hi, nd, ThinVec::new())
             }
             // Field access.
             _ => {
@@ -2571,7 +2565,7 @@ impl<'a> Parser<'a> {
 
                 let id = spanned(ident_span.lo, ident_span.hi, ident);
                 let field = self.mk_field(self_value, id);
-                self.mk_expr(lo, ident_span.hi, field, None)
+                self.mk_expr(lo, ident_span.hi, field, ThinVec::new())
             }
         })
     }
@@ -2583,7 +2577,7 @@ impl<'a> Parser<'a> {
             // expr?
             while self.eat(&token::Question) {
                 let hi = self.last_span.hi;
-                e = self.mk_expr(lo, hi, ExprKind::Try(e), None);
+                e = self.mk_expr(lo, hi, ExprKind::Try(e), ThinVec::new());
             }
 
             // expr.f
@@ -2611,7 +2605,7 @@ impl<'a> Parser<'a> {
                         Some(n) => {
                             let id = spanned(dot, hi, n);
                             let field = self.mk_tup_field(e, id);
-                            e = self.mk_expr(lo, hi, field, None);
+                            e = self.mk_expr(lo, hi, field, ThinVec::new());
                         }
                         None => {
                             let last_span = self.last_span;
@@ -2663,7 +2657,7 @@ impl<'a> Parser<'a> {
                 hi = self.last_span.hi;
 
                 let nd = self.mk_call(e, es);
-                e = self.mk_expr(lo, hi, nd, None);
+                e = self.mk_expr(lo, hi, nd, ThinVec::new());
               }
 
               // expr[...]
@@ -2674,7 +2668,7 @@ impl<'a> Parser<'a> {
                 hi = self.span.hi;
                 self.commit_expr_expecting(&ix, token::CloseDelim(token::Bracket))?;
                 let index = self.mk_index(e, ix);
-                e = self.mk_expr(lo, hi, index, None)
+                e = self.mk_expr(lo, hi, index, ThinVec::new())
               }
               _ => return Ok(e)
             }
@@ -2905,7 +2899,7 @@ impl<'a> Parser<'a> {
 
     /// Parse a prefix-unary-operator expr
     pub fn parse_prefix_expr(&mut self,
-                             already_parsed_attrs: Option<ThinAttributes>)
+                             already_parsed_attrs: Option<ThinVec<Attribute>>)
                              -> PResult<'a, P<Expr>> {
         let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?;
         let lo = self.span.lo;
@@ -2950,8 +2944,7 @@ impl<'a> Parser<'a> {
                 let blk = self.parse_block()?;
                 let span = blk.span;
                 hi = span.hi;
-                let blk_expr = self.mk_expr(span.lo, span.hi, ExprKind::Block(blk),
-                                            None);
+                let blk_expr = self.mk_expr(span.lo, hi, ExprKind::Block(blk), ThinVec::new());
                 ExprKind::InPlace(place, blk_expr)
             }
             token::Ident(..) if self.token.is_keyword(keywords::Box) => {
@@ -2971,7 +2964,7 @@ impl<'a> Parser<'a> {
     /// This parses an expression accounting for associativity and precedence of the operators in
     /// the expression.
     pub fn parse_assoc_expr(&mut self,
-                            already_parsed_attrs: Option<ThinAttributes>)
+                            already_parsed_attrs: Option<ThinVec<Attribute>>)
                             -> PResult<'a, P<Expr>> {
         self.parse_assoc_expr_with(0, already_parsed_attrs.into())
     }
@@ -3024,13 +3017,13 @@ impl<'a> Parser<'a> {
             // Special cases:
             if op == AssocOp::As {
                 let rhs = self.parse_ty()?;
-                lhs = self.mk_expr(lhs_span.lo, rhs.span.hi,
-                                   ExprKind::Cast(lhs, rhs), None);
+                let (lo, hi) = (lhs_span.lo, rhs.span.hi);
+                lhs = self.mk_expr(lo, hi, ExprKind::Cast(lhs, rhs), ThinVec::new());
                 continue
             } else if op == AssocOp::Colon {
                 let rhs = self.parse_ty()?;
-                lhs = self.mk_expr(lhs_span.lo, rhs.span.hi,
-                                   ExprKind::Type(lhs, rhs), None);
+                let (lo, hi) = (lhs_span.lo, rhs.span.hi);
+                lhs = self.mk_expr(lo, hi, ExprKind::Type(lhs, rhs), ThinVec::new());
                 continue
             } else if op == AssocOp::DotDot || op == AssocOp::DotDotDot {
                 // If we didn’t have to handle `x..`/`x...`, it would be pretty easy to
@@ -3056,7 +3049,7 @@ impl<'a> Parser<'a> {
                 };
 
                 let r = try!(self.mk_range(Some(lhs), rhs, limits));
-                lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None);
+                lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, ThinVec::new());
                 break
             }
 
@@ -3083,6 +3076,7 @@ impl<'a> Parser<'a> {
                 }),
             }?;
 
+            let (lo, hi) = (lhs_span.lo, rhs.span.hi);
             lhs = match op {
                 AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide |
                 AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor |
@@ -3090,14 +3084,13 @@ impl<'a> Parser<'a> {
                 AssocOp::Equal | AssocOp::Less | AssocOp::LessEqual | AssocOp::NotEqual |
                 AssocOp::Greater | AssocOp::GreaterEqual => {
                     let ast_op = op.to_ast_binop().unwrap();
-                    let (lhs_span, rhs_span) = (lhs_span, rhs.span);
                     let binary = self.mk_binary(codemap::respan(cur_op_span, ast_op), lhs, rhs);
-                    self.mk_expr(lhs_span.lo, rhs_span.hi, binary, None)
+                    self.mk_expr(lo, hi, binary, ThinVec::new())
                 }
                 AssocOp::Assign =>
-                    self.mk_expr(lhs_span.lo, rhs.span.hi, ExprKind::Assign(lhs, rhs), None),
+                    self.mk_expr(lo, hi, ExprKind::Assign(lhs, rhs), ThinVec::new()),
                 AssocOp::Inplace =>
-                    self.mk_expr(lhs_span.lo, rhs.span.hi, ExprKind::InPlace(lhs, rhs), None),
+                    self.mk_expr(lo, hi, ExprKind::InPlace(lhs, rhs), ThinVec::new()),
                 AssocOp::AssignOp(k) => {
                     let aop = match k {
                         token::Plus =>    BinOpKind::Add,
@@ -3111,9 +3104,8 @@ impl<'a> Parser<'a> {
                         token::Shl =>     BinOpKind::Shl,
                         token::Shr =>     BinOpKind::Shr,
                     };
-                    let (lhs_span, rhs_span) = (lhs_span, rhs.span);
                     let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs);
-                    self.mk_expr(lhs_span.lo, rhs_span.hi, aopexpr, None)
+                    self.mk_expr(lo, hi, aopexpr, ThinVec::new())
                 }
                 AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotDot => {
                     self.bug("As, Colon, DotDot or DotDotDot branch reached")
@@ -3148,7 +3140,7 @@ impl<'a> Parser<'a> {
 
     /// Parse prefix-forms of range notation: `..expr`, `..`, `...expr`
     fn parse_prefix_range_expr(&mut self,
-                               already_parsed_attrs: Option<ThinAttributes>)
+                               already_parsed_attrs: Option<ThinVec<Attribute>>)
                                -> PResult<'a, P<Expr>> {
         debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot);
         let tok = self.token.clone();
@@ -3193,7 +3185,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse an 'if' or 'if let' expression ('if' token already eaten)
-    pub fn parse_if_expr(&mut self, attrs: ThinAttributes) -> PResult<'a, P<Expr>> {
+    pub fn parse_if_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         if self.check_keyword(keywords::Let) {
             return self.parse_if_let_expr(attrs);
         }
@@ -3211,7 +3203,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse an 'if let' expression ('if' token already eaten)
-    pub fn parse_if_let_expr(&mut self, attrs: ThinAttributes)
+    pub fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>)
                              -> PResult<'a, P<Expr>> {
         let lo = self.last_span.lo;
         self.expect_keyword(keywords::Let)?;
@@ -3232,7 +3224,7 @@ impl<'a> Parser<'a> {
     pub fn parse_lambda_expr(&mut self,
                              lo: BytePos,
                              capture_clause: CaptureBy,
-                             attrs: ThinAttributes)
+                             attrs: ThinVec<Attribute>)
                              -> PResult<'a, P<Expr>>
     {
         let decl = self.parse_fn_block_decl()?;
@@ -3267,24 +3259,24 @@ impl<'a> Parser<'a> {
     // `else` token already eaten
     pub fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
         if self.eat_keyword(keywords::If) {
-            return self.parse_if_expr(None);
+            return self.parse_if_expr(ThinVec::new());
         } else {
             let blk = self.parse_block()?;
-            return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), None));
+            return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), ThinVec::new()));
         }
     }
 
     /// Parse a 'for' .. 'in' expression ('for' token already eaten)
     pub fn parse_for_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
                           span_lo: BytePos,
-                          attrs: ThinAttributes) -> PResult<'a, P<Expr>> {
+                          mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         // Parse: `for <src_pat> in <src_expr> <src_loop_block>`
 
         let pat = self.parse_pat()?;
         self.expect_keyword(keywords::In)?;
         let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
-        let attrs = attrs.append(iattrs.into_thin_attrs());
+        attrs.extend(iattrs);
 
         let hi = self.last_span.hi;
 
@@ -3296,13 +3288,13 @@ impl<'a> Parser<'a> {
     /// Parse a 'while' or 'while let' expression ('while' token already eaten)
     pub fn parse_while_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
                             span_lo: BytePos,
-                            attrs: ThinAttributes) -> PResult<'a, P<Expr>> {
+                            mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         if self.token.is_keyword(keywords::Let) {
             return self.parse_while_let_expr(opt_ident, span_lo, attrs);
         }
         let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
-        let attrs = attrs.append(iattrs.into_thin_attrs());
+        attrs.extend(iattrs);
         let hi = body.span.hi;
         return Ok(self.mk_expr(span_lo, hi, ExprKind::While(cond, body, opt_ident),
                                attrs));
@@ -3311,13 +3303,13 @@ impl<'a> Parser<'a> {
     /// Parse a 'while let' expression ('while' token already eaten)
     pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
                                 span_lo: BytePos,
-                                attrs: ThinAttributes) -> PResult<'a, P<Expr>> {
+                                mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         self.expect_keyword(keywords::Let)?;
         let pat = self.parse_pat()?;
         self.expect(&token::Eq)?;
         let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
-        let attrs = attrs.append(iattrs.into_thin_attrs());
+        attrs.extend(iattrs);
         let hi = body.span.hi;
         return Ok(self.mk_expr(span_lo, hi, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs));
     }
@@ -3325,15 +3317,15 @@ impl<'a> Parser<'a> {
     // parse `loop {...}`, `loop` token already eaten
     pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
                            span_lo: BytePos,
-                           attrs: ThinAttributes) -> PResult<'a, P<Expr>> {
+                           mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
-        let attrs = attrs.append(iattrs.into_thin_attrs());
+        attrs.extend(iattrs);
         let hi = body.span.hi;
         Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs))
     }
 
     // `match` token already eaten
-    fn parse_match_expr(&mut self, attrs: ThinAttributes) -> PResult<'a, P<Expr>> {
+    fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         let match_span = self.last_span;
         let lo = self.last_span.lo;
         let discriminant = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL,
@@ -3345,8 +3337,8 @@ impl<'a> Parser<'a> {
             }
             return Err(e)
         }
-        let attrs = attrs.append(
-            self.parse_inner_attributes()?.into_thin_attrs());
+        attrs.extend(self.parse_inner_attributes()?);
+
         let mut arms: Vec<Arm> = Vec::new();
         while self.token != token::CloseDelim(token::Brace) {
             match self.parse_arm() {
@@ -3419,7 +3411,7 @@ impl<'a> Parser<'a> {
 
     /// Parse an expression, subject to the given restrictions
     pub fn parse_expr_res(&mut self, r: Restrictions,
-                          already_parsed_attrs: Option<ThinAttributes>)
+                          already_parsed_attrs: Option<ThinVec<Attribute>>)
                           -> PResult<'a, P<Expr>> {
         self.with_res(r, |this| this.parse_assoc_expr(already_parsed_attrs))
     }
@@ -3617,7 +3609,7 @@ impl<'a> Parser<'a> {
                 (None, self.parse_path(PathStyle::Expr)?)
             };
             let hi = self.last_span.hi;
-            Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), None))
+            Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new()))
         } else {
             self.parse_pat_literal_maybe_minus()
         }
@@ -3712,7 +3704,8 @@ impl<'a> Parser<'a> {
                       token::DotDotDot => {
                         // Parse range
                         let hi = self.last_span.hi;
-                        let begin = self.mk_expr(lo, hi, ExprKind::Path(qself, path), None);
+                        let begin =
+                              self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new());
                         self.bump();
                         let end = self.parse_pat_range_end()?;
                         pat = PatKind::Range(begin, end);
@@ -3807,7 +3800,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse a local variable declaration
-    fn parse_local(&mut self, attrs: ThinAttributes) -> PResult<'a, P<Local>> {
+    fn parse_local(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Local>> {
         let lo = self.span.lo;
         let pat = self.parse_pat()?;
 
@@ -3941,7 +3934,7 @@ impl<'a> Parser<'a> {
         Ok(Some(if self.eat_keyword(keywords::Let) {
             Stmt {
                 id: ast::DUMMY_NODE_ID,
-                node: StmtKind::Local(self.parse_local(attrs.into_thin_attrs())?),
+                node: StmtKind::Local(self.parse_local(attrs.into())?),
                 span: mk_sp(lo, self.last_span.hi),
             }
         } else if self.token.is_ident()
@@ -3997,7 +3990,7 @@ impl<'a> Parser<'a> {
                 let mac = spanned(lo, hi, Mac_ { path: pth, tts: tts });
                 Stmt {
                     id: ast::DUMMY_NODE_ID,
-                    node: StmtKind::Mac(P((mac, style, attrs.into_thin_attrs()))),
+                    node: StmtKind::Mac(P((mac, style, attrs.into()))),
                     span: mk_sp(lo, hi),
                 }
             } else {
@@ -4057,7 +4050,7 @@ impl<'a> Parser<'a> {
 
                     // Remainder are line-expr stmts.
                     let e = self.parse_expr_res(
-                        Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into_thin_attrs()))?;
+                        Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into()))?;
                     Stmt {
                         id: ast::DUMMY_NODE_ID,
                         span: mk_sp(lo, e.span.hi),
@@ -4150,7 +4143,7 @@ impl<'a> Parser<'a> {
     }
 
     fn handle_macro_in_block(&mut self,
-                             (mac, style, attrs): (ast::Mac, MacStmtStyle, ThinAttributes),
+                             (mac, style, attrs): (ast::Mac, MacStmtStyle, ThinVec<Attribute>),
                              span: Span,
                              stmts: &mut Vec<Stmt>,
                              last_block_expr: &mut Option<P<Expr>>)
@@ -4168,7 +4161,7 @@ impl<'a> Parser<'a> {
                     self.bump();
                 }
                 _ => {
-                    let e = self.mk_mac_expr(span.lo, span.hi, mac.node, None);
+                    let e = self.mk_mac_expr(span.lo, span.hi, mac.node, ThinVec::new());
                     let lo = e.span.lo;
                     let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
                     let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index a268a6e9605..d399f538004 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -14,7 +14,6 @@ use abi::{self, Abi};
 use ast::{self, BlockCheckMode, PatKind};
 use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
 use ast::Attribute;
-use attr::ThinAttributesExt;
 use util::parser::AssocOp;
 use attr;
 use attr::{AttrMetaMethods, AttributeMethods};
@@ -1607,7 +1606,7 @@ impl<'a> State<'a> {
         try!(self.maybe_print_comment(st.span.lo));
         match st.node {
             ast::StmtKind::Local(ref loc) => {
-                try!(self.print_outer_attributes(loc.attrs.as_attr_slice()));
+                try!(self.print_outer_attributes(&loc.attrs));
                 try!(self.space_if_not_bol());
                 try!(self.ibox(INDENT_UNIT));
                 try!(self.word_nbsp("let"));
@@ -1635,7 +1634,7 @@ impl<'a> State<'a> {
             ast::StmtKind::Mac(ref mac) => {
                 let (ref mac, style, ref attrs) = **mac;
                 try!(self.space_if_not_bol());
-                try!(self.print_outer_attributes(attrs.as_attr_slice()));
+                try!(self.print_outer_attributes(&attrs));
                 let delim = match style {
                     ast::MacStmtStyle::Braces => token::Brace,
                     _ => token::Paren
@@ -1975,7 +1974,7 @@ impl<'a> State<'a> {
                                   is_inline: bool) -> io::Result<()> {
         try!(self.maybe_print_comment(expr.span.lo));
 
-        let attrs = expr.attrs.as_attr_slice();
+        let attrs = &expr.attrs;
         if is_inline {
             try!(self.print_outer_attributes_inline(attrs));
         } else {
@@ -2119,9 +2118,7 @@ impl<'a> State<'a> {
                     let i_expr = body.expr.as_ref().unwrap();
                     match i_expr.node {
                         ast::ExprKind::Block(ref blk) => {
-                            try!(self.print_block_unclosed_with_attrs(
-                                &blk,
-                                i_expr.attrs.as_attr_slice()));
+                            try!(self.print_block_unclosed_with_attrs(&blk, &i_expr.attrs));
                         }
                         _ => {
                             // this is a bare expression
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index cc3fff09617..078103f834a 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -608,10 +608,10 @@ fn mk_test_descs(cx: &TestCtxt) -> P<ast::Expr> {
                     mk_test_desc_and_fn_rec(cx, test)
                 }).collect()),
                 span: DUMMY_SP,
-                attrs: None,
+                attrs: ast::ThinVec::new(),
             })),
         span: DUMMY_SP,
-        attrs: None,
+        attrs: ast::ThinVec::new(),
     })
 }
 
diff --git a/src/libsyntax/util/thin_vec.rs b/src/libsyntax/util/thin_vec.rs
new file mode 100644
index 00000000000..546686b46b8
--- /dev/null
+++ b/src/libsyntax/util/thin_vec.rs
@@ -0,0 +1,59 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/// A vector type optimized for cases where this size is usually 0 (c.f. `SmallVector`).
+/// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`,
+/// which uses only a single (null) pointer.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct ThinVec<T>(Option<Box<Vec<T>>>);
+
+impl<T> ThinVec<T> {
+    pub fn new() -> Self {
+        ThinVec(None)
+    }
+}
+
+impl<T> From<Vec<T>> for ThinVec<T> {
+    fn from(vec: Vec<T>) -> Self {
+        if vec.is_empty() {
+            ThinVec(None)
+        } else {
+            ThinVec(Some(Box::new(vec)))
+        }
+    }
+}
+
+impl<T> Into<Vec<T>> for ThinVec<T> {
+    fn into(self) -> Vec<T> {
+        match self {
+            ThinVec(None) => Vec::new(),
+            ThinVec(Some(vec)) => *vec,
+        }
+    }
+}
+
+impl<T> ::std::ops::Deref for ThinVec<T> {
+    type Target = [T];
+    fn deref(&self) -> &[T] {
+        match *self {
+            ThinVec(None) => &[],
+            ThinVec(Some(ref vec)) => vec,
+        }
+    }
+}
+
+impl<T> Extend<T> for ThinVec<T> {
+    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+        match *self {
+            ThinVec(Some(ref mut vec)) => vec.extend(iter),
+            ThinVec(None) => *self = iter.into_iter().collect::<Vec<_>>().into(),
+        }
+    }
+}
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index aca0c2bcf57..571965ef872 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -25,7 +25,6 @@
 
 use abi::Abi;
 use ast::*;
-use attr::ThinAttributesExt;
 use syntax_pos::Span;
 use codemap::Spanned;
 
@@ -184,7 +183,7 @@ pub fn walk_mod<V: Visitor>(visitor: &mut V, module: &Mod) {
 }
 
 pub fn walk_local<V: Visitor>(visitor: &mut V, local: &Local) {
-    for attr in local.attrs.as_attr_slice() {
+    for attr in local.attrs.iter() {
         visitor.visit_attribute(attr);
     }
     visitor.visit_pat(&local.pat);
@@ -604,7 +603,7 @@ pub fn walk_stmt<V: Visitor>(visitor: &mut V, statement: &Stmt) {
         StmtKind::Mac(ref mac) => {
             let (ref mac, _, ref attrs) = **mac;
             visitor.visit_mac(mac);
-            for attr in attrs.as_attr_slice() {
+            for attr in attrs.iter() {
                 visitor.visit_attribute(attr);
             }
         }
@@ -616,7 +615,7 @@ pub fn walk_mac<V: Visitor>(_: &mut V, _: &Mac) {
 }
 
 pub fn walk_expr<V: Visitor>(visitor: &mut V, expression: &Expr) {
-    for attr in expression.attrs.as_attr_slice() {
+    for attr in expression.attrs.iter() {
         visitor.visit_attribute(attr);
     }
     match expression.node {
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index e9e72c040fe..56a8c28ffed 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -261,6 +261,6 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::Token
             expn_id: expn_id,
         }),
         span: sp,
-        attrs: None,
+        attrs: ast::ThinVec::new(),
     }))
 }
diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs
index 2be32d33345..870413a7f61 100644
--- a/src/libsyntax_ext/concat_idents.rs
+++ b/src/libsyntax_ext/concat_idents.rs
@@ -71,7 +71,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree])
                 id: ast::DUMMY_NODE_ID,
                 node: ast::ExprKind::Path(None, self.path()),
                 span: self.span,
-                attrs: None,
+                attrs: ast::ThinVec::new(),
             }))
         }
 
diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs
index 527748149a7..dabe234eb9c 100644
--- a/src/libsyntax_ext/deriving/debug.rs
+++ b/src/libsyntax_ext/deriving/debug.rs
@@ -149,7 +149,7 @@ fn stmt_let_undescore(cx: &mut ExtCtxt,
         init: Some(expr),
         id: ast::DUMMY_NODE_ID,
         span: sp,
-        attrs: None,
+        attrs: ast::ThinVec::new(),
     });
     ast::Stmt {
         id: ast::DUMMY_NODE_ID,
diff --git a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs
index ed971faf8c6..64747002a65 100644
--- a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs
+++ b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs
@@ -86,7 +86,7 @@ fn check_expr_attrs(es: &str, expected: &[&str]) {
     let actual = &e.attrs;
     str_compare(es,
                 &expected.iter().map(|r| attr(r, &ps).unwrap()).collect::<Vec<_>>(),
-                actual.as_attr_slice(),
+                &actual,
                 pprust::attribute_to_string);
 }