about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs17
-rw-r--r--src/libsyntax/ast_util.rs24
-rw-r--r--src/libsyntax/attr.rs4
-rw-r--r--src/libsyntax/codemap.rs2
-rw-r--r--src/libsyntax/diagnostics/macros.rs31
-rw-r--r--src/libsyntax/diagnostics/plugin.rs16
-rw-r--r--src/libsyntax/ext/expand.rs63
-rw-r--r--src/libsyntax/ext/mtwt.rs4
-rw-r--r--src/libsyntax/ext/quote.rs122
-rw-r--r--src/libsyntax/fold.rs6
-rw-r--r--src/libsyntax/parse/parser.rs151
-rw-r--r--src/libsyntax/parse/token.rs2
-rw-r--r--src/libsyntax/print/pprust.rs42
13 files changed, 294 insertions, 190 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 98d858babb1..d4860766d47 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -31,6 +31,7 @@ pub use self::Lit_::*;
 pub use self::LitIntType::*;
 pub use self::LocalSource::*;
 pub use self::Mac_::*;
+pub use self::MacStmtStyle::*;
 pub use self::MatchSource::*;
 pub use self::MetaItem_::*;
 pub use self::Method_::*;
@@ -615,8 +616,20 @@ pub enum Stmt_ {
     /// Expr with trailing semi-colon (may have any type):
     StmtSemi(P<Expr>, NodeId),
 
-    /// bool: is there a trailing semi-colon?
-    StmtMac(Mac, bool),
+    StmtMac(Mac, MacStmtStyle),
+}
+
+#[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub enum MacStmtStyle {
+    /// The macro statement had a trailing semicolon, e.g. `foo! { ... };`
+    /// `foo!(...);`, `foo![...];`
+    MacStmtWithSemicolon,
+    /// The macro statement had braces; e.g. foo! { ... }
+    MacStmtWithBraces,
+    /// The macro statement had parentheses or brackets and no semicolon; e.g.
+    /// `foo!(...)`. All of these will end up being converted into macro
+    /// expressions.
+    MacStmtWithoutBraces,
 }
 
 /// Where a local declaration came from: either a true `let ... =
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 2e097d45515..aaa172633be 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -753,16 +753,20 @@ macro_rules! mf_method{
 
 
 impl PostExpansionMethod for Method {
-    mf_method!(pe_ident,ast::Ident,MethDecl(ident,_,_,_,_,_,_,_),ident)
-    mf_method!(pe_generics,&'a ast::Generics,
-               MethDecl(_,ref generics,_,_,_,_,_,_),generics)
-    mf_method!(pe_abi,Abi,MethDecl(_,_,abi,_,_,_,_,_),abi)
-    mf_method!(pe_explicit_self,&'a ast::ExplicitSelf,
-               MethDecl(_,_,_,ref explicit_self,_,_,_,_),explicit_self)
-    mf_method!(pe_unsafety,ast::Unsafety,MethDecl(_,_,_,_,unsafety,_,_,_),unsafety)
-    mf_method!(pe_fn_decl,&'a ast::FnDecl,MethDecl(_,_,_,_,_,ref decl,_,_),&**decl)
-    mf_method!(pe_body,&'a ast::Block,MethDecl(_,_,_,_,_,_,ref body,_),&**body)
-    mf_method!(pe_vis,ast::Visibility,MethDecl(_,_,_,_,_,_,_,vis),vis)
+    mf_method! { pe_ident,ast::Ident,MethDecl(ident,_,_,_,_,_,_,_),ident }
+    mf_method! {
+        pe_generics,&'a ast::Generics,
+        MethDecl(_,ref generics,_,_,_,_,_,_),generics
+    }
+    mf_method! { pe_abi,Abi,MethDecl(_,_,abi,_,_,_,_,_),abi }
+    mf_method! {
+        pe_explicit_self,&'a ast::ExplicitSelf,
+        MethDecl(_,_,_,ref explicit_self,_,_,_,_),explicit_self
+    }
+    mf_method! { pe_unsafety,ast::Unsafety,MethDecl(_,_,_,_,unsafety,_,_,_),unsafety }
+    mf_method! { pe_fn_decl,&'a ast::FnDecl,MethDecl(_,_,_,_,_,ref decl,_,_),&**decl }
+    mf_method! { pe_body,&'a ast::Block,MethDecl(_,_,_,_,_,_,ref body,_),&**body }
+    mf_method! { pe_vis,ast::Visibility,MethDecl(_,_,_,_,_,_,_,vis),vis }
 }
 
 #[cfg(test)]
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 8248eae4b8c..598da6a5df0 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -29,7 +29,7 @@ use std::cell::{RefCell, Cell};
 use std::collections::BitvSet;
 use std::collections::HashSet;
 
-thread_local!(static USED_ATTRS: RefCell<BitvSet> = RefCell::new(BitvSet::new()))
+thread_local! { static USED_ATTRS: RefCell<BitvSet> = RefCell::new(BitvSet::new()) }
 
 pub fn mark_used(attr: &Attribute) {
     let AttrId(id) = attr.node.id;
@@ -169,7 +169,7 @@ pub fn mk_word_item(name: InternedString) -> P<MetaItem> {
     P(dummy_spanned(MetaWord(name)))
 }
 
-thread_local!(static NEXT_ATTR_ID: Cell<uint> = Cell::new(0))
+thread_local! { static NEXT_ATTR_ID: Cell<uint> = Cell::new(0) }
 
 pub fn mk_attr_id() -> AttrId {
     let id = NEXT_ATTR_ID.with(|slot| {
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 592fdd7207c..17cafc2441f 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -329,7 +329,7 @@ impl FileMap {
         // the new charpos must be > the last one (or it's the first one).
         let mut lines = self.lines.borrow_mut();
         let line_len = lines.len();
-        assert!(line_len == 0 || ((*lines)[line_len - 1] < pos))
+        assert!(line_len == 0 || ((*lines)[line_len - 1] < pos));
         lines.push(pos);
     }
 
diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs
index b4bf793d4e1..3107508a96a 100644
--- a/src/libsyntax/diagnostics/macros.rs
+++ b/src/libsyntax/diagnostics/macros.rs
@@ -11,44 +11,45 @@
 #![macro_escape]
 
 #[macro_export]
-macro_rules! register_diagnostic(
-    ($code:tt, $description:tt) => (__register_diagnostic!($code, $description));
-    ($code:tt) => (__register_diagnostic!($code))
-)
+macro_rules! register_diagnostic {
+    ($code:tt, $description:tt) => (__register_diagnostic! { $code, $description });
+    ($code:tt) => (__register_diagnostic! { $code })
+}
 
 #[macro_export]
-macro_rules! span_err(
+macro_rules! span_err {
     ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
         __diagnostic_used!($code);
         $session.span_err_with_code($span, format!($($message)*).as_slice(), stringify!($code))
     })
-)
+}
 
 #[macro_export]
-macro_rules! span_warn(
+macro_rules! span_warn {
     ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
         __diagnostic_used!($code);
         $session.span_warn_with_code($span, format!($($message)*).as_slice(), stringify!($code))
     })
-)
+}
 
 #[macro_export]
-macro_rules! span_note(
+macro_rules! span_note {
     ($session:expr, $span:expr, $($message:tt)*) => ({
         ($session).span_note($span, format!($($message)*).as_slice())
     })
-)
+}
 
 #[macro_export]
-macro_rules! span_help(
+macro_rules! span_help {
     ($session:expr, $span:expr, $($message:tt)*) => ({
         ($session).span_help($span, format!($($message)*).as_slice())
     })
-)
+}
 
 #[macro_export]
-macro_rules! register_diagnostics(
+macro_rules! register_diagnostics {
     ($($code:tt),*) => (
-        $(register_diagnostic!($code))*
+        $(register_diagnostic! { $code })*
     )
-)
+}
+
diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs
index cb2a1f8acd8..bcce5538314 100644
--- a/src/libsyntax/diagnostics/plugin.rs
+++ b/src/libsyntax/diagnostics/plugin.rs
@@ -18,12 +18,16 @@ use ext::build::AstBuilder;
 use parse::token;
 use ptr::P;
 
-thread_local!(static REGISTERED_DIAGNOSTICS: RefCell<HashMap<Name, Option<Name>>> = {
-    RefCell::new(HashMap::new())
-})
-thread_local!(static USED_DIAGNOSTICS: RefCell<HashMap<Name, Span>> = {
-    RefCell::new(HashMap::new())
-})
+thread_local! {
+    static REGISTERED_DIAGNOSTICS: RefCell<HashMap<Name, Option<Name>>> = {
+        RefCell::new(HashMap::new())
+    }
+}
+thread_local! {
+    static USED_DIAGNOSTICS: RefCell<HashMap<Name, Span>> = {
+        RefCell::new(HashMap::new())
+    }
+}
 
 fn with_registered_diagnostics<T, F>(f: F) -> T where
     F: FnOnce(&mut HashMap<Name, Option<Name>>) -> T,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index e280e6e4491..20c8ff20b71 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -11,7 +11,8 @@ use self::Either::*;
 
 use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
 use ast::{Local, Ident, MacInvocTT};
-use ast::{ItemMac, Mrk, Stmt, StmtDecl, StmtMac, StmtExpr, StmtSemi};
+use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
+use ast::{StmtExpr, StmtSemi};
 use ast::TokenTree;
 use ast;
 use ext::mtwt;
@@ -354,7 +355,7 @@ fn expand_loop_block(loop_block: P<Block>,
 
 // eval $e with a new exts frame.
 // must be a macro so that $e isn't evaluated too early.
-macro_rules! with_exts_frame (
+macro_rules! with_exts_frame {
     ($extsboxexpr:expr,$macros_escape:expr,$e:expr) =>
     ({$extsboxexpr.push_frame();
       $extsboxexpr.info().macros_escape = $macros_escape;
@@ -362,7 +363,7 @@ macro_rules! with_exts_frame (
       $extsboxexpr.pop_frame();
       result
      })
-)
+}
 
 // When we enter a module, record it, for the sake of `module!`
 pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
@@ -636,8 +637,8 @@ pub fn expand_item_mac(it: P<ast::Item>, fld: &mut MacroExpander)
 // I don't understand why this returns a vector... it looks like we're
 // half done adding machinery to allow macros to expand into multiple statements.
 fn expand_stmt(s: Stmt, fld: &mut MacroExpander) -> SmallVector<P<Stmt>> {
-    let (mac, semi) = match s.node {
-        StmtMac(mac, semi) => (mac, semi),
+    let (mac, style) = match s.node {
+        StmtMac(mac, style) => (mac, style),
         _ => return expand_non_macro_stmt(s, fld)
     };
     let expanded_stmt = match expand_mac_invoc(mac, s.span,
@@ -653,7 +654,7 @@ fn expand_stmt(s: Stmt, fld: &mut MacroExpander) -> SmallVector<P<Stmt>> {
     let fully_expanded = fld.fold_stmt(expanded_stmt);
     fld.cx.bt_pop();
 
-    if semi {
+    if style == MacStmtWithSemicolon {
         fully_expanded.into_iter().map(|s| s.map(|Spanned {node, span}| {
             Spanned {
                 node: match node {
@@ -1324,7 +1325,7 @@ mod test {
     // make sure that macros can't escape fns
     #[should_fail]
     #[test] fn macros_cant_escape_fns_test () {
-        let src = "fn bogus() {macro_rules! z (() => (3+4))}\
+        let src = "fn bogus() {macro_rules! z (() => (3+4));}\
                    fn inty() -> int { z!() }".to_string();
         let sess = parse::new_parse_sess();
         let crate_ast = parse::parse_crate_from_source_str(
@@ -1338,7 +1339,7 @@ mod test {
     // make sure that macros can't escape modules
     #[should_fail]
     #[test] fn macros_cant_escape_mods_test () {
-        let src = "mod foo {macro_rules! z (() => (3+4))}\
+        let src = "mod foo {macro_rules! z (() => (3+4));}\
                    fn inty() -> int { z!() }".to_string();
         let sess = parse::new_parse_sess();
         let crate_ast = parse::parse_crate_from_source_str(
@@ -1350,7 +1351,7 @@ mod test {
 
     // macro_escape modules should allow macros to escape
     #[test] fn macros_can_escape_flattened_mods_test () {
-        let src = "#[macro_escape] mod foo {macro_rules! z (() => (3+4))}\
+        let src = "#[macro_escape] mod foo {macro_rules! z (() => (3+4));}\
                    fn inty() -> int { z!() }".to_string();
         let sess = parse::new_parse_sess();
         let crate_ast = parse::parse_crate_from_source_str(
@@ -1402,13 +1403,13 @@ mod test {
 
     #[test] fn macro_tokens_should_match(){
         expand_crate_str(
-            "macro_rules! m((a)=>(13)) fn main(){m!(a);}".to_string());
+            "macro_rules! m((a)=>(13)) ;fn main(){m!(a);}".to_string());
     }
 
     // should be able to use a bound identifier as a literal in a macro definition:
     #[test] fn self_macro_parsing(){
         expand_crate_str(
-            "macro_rules! foo ((zz) => (287u;))
+            "macro_rules! foo ((zz) => (287u;));
             fn f(zz : int) {foo!(zz);}".to_string()
             );
     }
@@ -1451,16 +1452,16 @@ mod test {
                 ("fn main () {let x: int = 13;x;}",
                  vec!(vec!(0)), false),
                 // the use of b after the + should be renamed, the other one not:
-                ("macro_rules! f (($x:ident) => (b + $x)) fn a() -> int { let b = 13; f!(b)}",
+                ("macro_rules! f (($x:ident) => (b + $x)); fn a() -> int { let b = 13; f!(b)}",
                  vec!(vec!(1)), false),
                 // the b before the plus should not be renamed (requires marks)
-                ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})) fn a() -> int { f!(b)}",
+                ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})); fn a() -> int { f!(b)}",
                  vec!(vec!(1)), false),
                 // the marks going in and out of letty should cancel, allowing that $x to
                 // capture the one following the semicolon.
                 // this was an awesome test case, and caught a *lot* of bugs.
-                ("macro_rules! letty(($x:ident) => (let $x = 15;))
-                  macro_rules! user(($x:ident) => ({letty!($x); $x}))
+                ("macro_rules! letty(($x:ident) => (let $x = 15;));
+                  macro_rules! user(($x:ident) => ({letty!($x); $x}));
                   fn main() -> int {user!(z)}",
                  vec!(vec!(0)), false)
                 );
@@ -1488,7 +1489,7 @@ mod test {
     #[test] fn issue_6994(){
         run_renaming_test(
             &("macro_rules! g (($x:ident) =>
-              ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}))
+              ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}));
               fn a(){g!(z)}",
               vec!(vec!(0)),false),
             0)
@@ -1498,7 +1499,7 @@ mod test {
     // fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}}
     #[test] fn issue_9384(){
         run_renaming_test(
-            &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}}))
+            &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}}));
               fn z() {match 8 {x => bad_macro!(x)}}",
               // NB: the third "binding" is the repeat of the second one.
               vec!(vec!(1,3),vec!(0,2),vec!(0,2)),
@@ -1511,8 +1512,8 @@ mod test {
     // fn main(){let g1_1 = 13; g1_1}}
     #[test] fn pat_expand_issue_15221(){
         run_renaming_test(
-            &("macro_rules! inner ( ($e:pat ) => ($e))
-              macro_rules! outer ( ($e:pat ) => (inner!($e)))
+            &("macro_rules! inner ( ($e:pat ) => ($e));
+              macro_rules! outer ( ($e:pat ) => (inner!($e)));
               fn main() { let outer!(g) = 13; g;}",
               vec!(vec!(0)),
               true),
@@ -1527,8 +1528,8 @@ mod test {
     // method expands to fn get_x(&self_0, x_1:int) {self_0 + self_2 + x_3 + x_1}
     #[test] fn method_arg_hygiene(){
         run_renaming_test(
-            &("macro_rules! inject_x (()=>(x))
-              macro_rules! inject_self (()=>(self))
+            &("macro_rules! inject_x (()=>(x));
+              macro_rules! inject_self (()=>(self));
               struct A;
               impl A{fn get_x(&self, x: int) {self + inject_self!() + inject_x!() + x;} }",
               vec!(vec!(0),vec!(3)),
@@ -1542,8 +1543,8 @@ mod test {
         run_renaming_test(
             &("struct A;
               macro_rules! add_method (($T:ty) =>
-              (impl $T {  fn thingy(&self) {self;} }))
-              add_method!(A)",
+              (impl $T {  fn thingy(&self) {self;} }));
+              add_method!(A);",
               vec!(vec!(0)),
               true),
             0)
@@ -1553,7 +1554,7 @@ mod test {
     // expands to fn q(x_1:int){fn g(x_2:int){x_2 + x_1};}
     #[test] fn issue_9383(){
         run_renaming_test(
-            &("macro_rules! bad_macro (($ex:expr) => (fn g(x:int){ x + $ex }))
+            &("macro_rules! bad_macro (($ex:expr) => (fn g(x:int){ x + $ex }));
               fn q(x:int) { bad_macro!(x); }",
               vec!(vec!(1),vec!(0)),true),
             0)
@@ -1563,7 +1564,7 @@ mod test {
     // expands to fn f(){(|x_1 : int| {(x_2 + x_1)})(3);}
     #[test] fn closure_arg_hygiene(){
         run_renaming_test(
-            &("macro_rules! inject_x (()=>(x))
+            &("macro_rules! inject_x (()=>(x));
             fn f(){(|x : int| {(inject_x!() + x)})(3);}",
               vec!(vec!(1)),
               true),
@@ -1573,9 +1574,9 @@ mod test {
     // macro_rules in method position. Sadly, unimplemented.
     #[test] fn macro_in_method_posn(){
         expand_crate_str(
-            "macro_rules! my_method (() => (fn thirteen(&self) -> int {13}))
+            "macro_rules! my_method (() => (fn thirteen(&self) -> int {13}));
             struct A;
-            impl A{ my_method!()}
+            impl A{ my_method!(); }
             fn f(){A.thirteen;}".to_string());
     }
 
@@ -1586,7 +1587,7 @@ mod test {
             &("macro_rules! item { ($i:item) => {$i}}
               struct Entries;
               macro_rules! iterator_impl {
-              () => { item!( impl Entries { fn size_hint(&self) { self;}})}}
+              () => { item!( impl Entries { fn size_hint(&self) { self;}});}}
               iterator_impl! { }",
               vec!(vec!(0)), true),
             0)
@@ -1666,9 +1667,9 @@ mod test {
     }
 
     #[test] fn fmt_in_macro_used_inside_module_macro() {
-        let crate_str = "macro_rules! fmt_wrap(($b:expr)=>($b.to_string()))
-macro_rules! foo_module (() => (mod generated { fn a() { let xx = 147; fmt_wrap!(xx);}}))
-foo_module!()
+        let crate_str = "macro_rules! fmt_wrap(($b:expr)=>($b.to_string()));
+macro_rules! foo_module (() => (mod generated { fn a() { let xx = 147; fmt_wrap!(xx);}}));
+foo_module!();
 ".to_string();
         let cr = expand_crate_str(crate_str);
         // find the xx binding
diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs
index a4e06aeaf63..33936e6213f 100644
--- a/src/libsyntax/ext/mtwt.rs
+++ b/src/libsyntax/ext/mtwt.rs
@@ -108,7 +108,7 @@ pub fn apply_renames(renames: &RenameList, ctxt: SyntaxContext) -> SyntaxContext
 pub fn with_sctable<T, F>(op: F) -> T where
     F: FnOnce(&SCTable) -> T,
 {
-    thread_local!(static SCTABLE_KEY: SCTable = new_sctable_internal())
+    thread_local!(static SCTABLE_KEY: SCTable = new_sctable_internal());
     SCTABLE_KEY.with(move |slot| op(slot))
 }
 
@@ -174,7 +174,7 @@ fn with_resolve_table_mut<T, F>(op: F) -> T where
 {
     thread_local!(static RESOLVE_TABLE_KEY: RefCell<ResolveTable> = {
         RefCell::new(HashMap::new())
-    })
+    });
 
     RESOLVE_TABLE_KEY.with(move |slot| op(&mut *slot.borrow_mut()))
 }
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index 45752499ad5..14e13feac98 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -100,7 +100,7 @@ pub mod rt {
         fn to_source_with_hygiene(&self) -> String;
     }
 
-    macro_rules! impl_to_source(
+    macro_rules! impl_to_source {
         (P<$t:ty>, $pp:ident) => (
             impl ToSource for P<$t> {
                 fn to_source(&self) -> String {
@@ -125,7 +125,7 @@ pub mod rt {
                 }
             }
         );
-    )
+    }
 
     fn slice_to_source<'a, T: ToSource>(sep: &'static str, xs: &'a [T]) -> String {
         xs.iter()
@@ -144,7 +144,7 @@ pub mod rt {
             .to_string()
     }
 
-    macro_rules! impl_to_source_slice(
+    macro_rules! impl_to_source_slice {
         ($t:ty, $sep:expr) => (
             impl ToSource for [$t] {
                 fn to_source(&self) -> String {
@@ -158,7 +158,7 @@ pub mod rt {
                 }
             }
         )
-    )
+    }
 
     impl ToSource for ast::Ident {
         fn to_source(&self) -> String {
@@ -172,18 +172,18 @@ pub mod rt {
         }
     }
 
-    impl_to_source!(ast::Ty, ty_to_string)
-    impl_to_source!(ast::Block, block_to_string)
-    impl_to_source!(ast::Arg, arg_to_string)
-    impl_to_source!(Generics, generics_to_string)
-    impl_to_source!(P<ast::Item>, item_to_string)
-    impl_to_source!(P<ast::Method>, method_to_string)
-    impl_to_source!(P<ast::Stmt>, stmt_to_string)
-    impl_to_source!(P<ast::Expr>, expr_to_string)
-    impl_to_source!(P<ast::Pat>, pat_to_string)
-    impl_to_source!(ast::Arm, arm_to_string)
-    impl_to_source_slice!(ast::Ty, ", ")
-    impl_to_source_slice!(P<ast::Item>, "\n\n")
+    impl_to_source! { ast::Ty, ty_to_string }
+    impl_to_source! { ast::Block, block_to_string }
+    impl_to_source! { ast::Arg, arg_to_string }
+    impl_to_source! { Generics, generics_to_string }
+    impl_to_source! { P<ast::Item>, item_to_string }
+    impl_to_source! { P<ast::Method>, method_to_string }
+    impl_to_source! { P<ast::Stmt>, stmt_to_string }
+    impl_to_source! { P<ast::Expr>, expr_to_string }
+    impl_to_source! { P<ast::Pat>, pat_to_string }
+    impl_to_source! { ast::Arm, arm_to_string }
+    impl_to_source_slice! { ast::Ty, ", " }
+    impl_to_source_slice! { P<ast::Item>, "\n\n" }
 
     impl ToSource for ast::Attribute_ {
         fn to_source(&self) -> String {
@@ -244,7 +244,7 @@ pub mod rt {
         }
     }
 
-    macro_rules! impl_to_source_int(
+    macro_rules! impl_to_source_int {
         (signed, $t:ty, $tag:ident) => (
             impl ToSource for $t {
                 fn to_source(&self) -> String {
@@ -272,23 +272,23 @@ pub mod rt {
                 }
             }
         );
-    )
+    }
 
-    impl_to_source_int!(signed, int, TyI)
-    impl_to_source_int!(signed, i8,  TyI8)
-    impl_to_source_int!(signed, i16, TyI16)
-    impl_to_source_int!(signed, i32, TyI32)
-    impl_to_source_int!(signed, i64, TyI64)
+    impl_to_source_int! { signed, int, TyI }
+    impl_to_source_int! { signed, i8,  TyI8 }
+    impl_to_source_int! { signed, i16, TyI16 }
+    impl_to_source_int! { signed, i32, TyI32 }
+    impl_to_source_int! { signed, i64, TyI64 }
 
-    impl_to_source_int!(unsigned, uint, TyU)
-    impl_to_source_int!(unsigned, u8,   TyU8)
-    impl_to_source_int!(unsigned, u16,  TyU16)
-    impl_to_source_int!(unsigned, u32,  TyU32)
-    impl_to_source_int!(unsigned, u64,  TyU64)
+    impl_to_source_int! { unsigned, uint, TyU }
+    impl_to_source_int! { unsigned, u8,   TyU8 }
+    impl_to_source_int! { unsigned, u16,  TyU16 }
+    impl_to_source_int! { unsigned, u32,  TyU32 }
+    impl_to_source_int! { unsigned, u64,  TyU64 }
 
     // Alas ... we write these out instead. All redundant.
 
-    macro_rules! impl_to_tokens(
+    macro_rules! impl_to_tokens {
         ($t:ty) => (
             impl ToTokens for $t {
                 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
@@ -296,9 +296,9 @@ pub mod rt {
                 }
             }
         )
-    )
+    }
 
-    macro_rules! impl_to_tokens_lifetime(
+    macro_rules! impl_to_tokens_lifetime {
         ($t:ty) => (
             impl<'a> ToTokens for $t {
                 fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
@@ -306,36 +306,36 @@ pub mod rt {
                 }
             }
         )
-    )
-
-    impl_to_tokens!(ast::Ident)
-    impl_to_tokens!(P<ast::Item>)
-    impl_to_tokens!(P<ast::Pat>)
-    impl_to_tokens!(ast::Arm)
-    impl_to_tokens!(P<ast::Method>)
-    impl_to_tokens_lifetime!(&'a [P<ast::Item>])
-    impl_to_tokens!(ast::Ty)
-    impl_to_tokens_lifetime!(&'a [ast::Ty])
-    impl_to_tokens!(Generics)
-    impl_to_tokens!(P<ast::Stmt>)
-    impl_to_tokens!(P<ast::Expr>)
-    impl_to_tokens!(ast::Block)
-    impl_to_tokens!(ast::Arg)
-    impl_to_tokens!(ast::Attribute_)
-    impl_to_tokens_lifetime!(&'a str)
-    impl_to_tokens!(())
-    impl_to_tokens!(char)
-    impl_to_tokens!(bool)
-    impl_to_tokens!(int)
-    impl_to_tokens!(i8)
-    impl_to_tokens!(i16)
-    impl_to_tokens!(i32)
-    impl_to_tokens!(i64)
-    impl_to_tokens!(uint)
-    impl_to_tokens!(u8)
-    impl_to_tokens!(u16)
-    impl_to_tokens!(u32)
-    impl_to_tokens!(u64)
+    }
+
+    impl_to_tokens! { ast::Ident }
+    impl_to_tokens! { P<ast::Item> }
+    impl_to_tokens! { P<ast::Pat> }
+    impl_to_tokens! { ast::Arm }
+    impl_to_tokens! { P<ast::Method> }
+    impl_to_tokens_lifetime! { &'a [P<ast::Item>] }
+    impl_to_tokens! { ast::Ty }
+    impl_to_tokens_lifetime! { &'a [ast::Ty] }
+    impl_to_tokens! { Generics }
+    impl_to_tokens! { P<ast::Stmt> }
+    impl_to_tokens! { P<ast::Expr> }
+    impl_to_tokens! { ast::Block }
+    impl_to_tokens! { ast::Arg }
+    impl_to_tokens! { ast::Attribute_ }
+    impl_to_tokens_lifetime! { &'a str }
+    impl_to_tokens! { () }
+    impl_to_tokens! { char }
+    impl_to_tokens! { bool }
+    impl_to_tokens! { int }
+    impl_to_tokens! { i8 }
+    impl_to_tokens! { i16 }
+    impl_to_tokens! { i32 }
+    impl_to_tokens! { i64 }
+    impl_to_tokens! { uint }
+    impl_to_tokens! { u8 }
+    impl_to_tokens! { u16 }
+    impl_to_tokens! { u32 }
+    impl_to_tokens! { u64 }
 
     pub trait ExtParseUtils {
         fn parse_item(&self, s: String) -> P<ast::Item>;
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 7d2acd08d94..10860ee5e01 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1485,7 +1485,7 @@ mod test {
     }
 
     // maybe add to expand.rs...
-    macro_rules! assert_pred (
+    macro_rules! assert_pred {
         ($pred:expr, $predname:expr, $a:expr , $b:expr) => (
             {
                 let pred_val = $pred;
@@ -1497,7 +1497,7 @@ mod test {
                 }
             }
         )
-    )
+    }
 
     // make sure idents get transformed everywhere
     #[test] fn ident_transformation () {
@@ -1523,6 +1523,6 @@ mod test {
             matches_codepattern,
             "matches_codepattern",
             pprust::to_string(|s| fake_print_crate(s, &folded_crate)),
-            "zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)))".to_string());
+            "zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)));".to_string());
     }
 }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 6e3cfe5854a..c234c172fd8 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -40,9 +40,10 @@ use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy};
 use ast::{LifetimeDef, Lit, Lit_};
 use ast::{LitBool, LitChar, LitByte, LitBinary};
 use ast::{LitStr, LitInt, Local, LocalLet};
+use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces};
 use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchNormal};
 use ast::{Method, MutTy, BiMul, Mutability};
-use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
+use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, NodeId, UnNot};
 use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct};
 use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle};
 use ast::{PolyTraitRef};
@@ -132,7 +133,7 @@ enum ItemOrViewItem {
 /// macro expansion). Placement of these is not as complex as I feared it would
 /// be. The important thing is to make sure that lookahead doesn't balk at
 /// `token::Interpolated` tokens.
-macro_rules! maybe_whole_expr (
+macro_rules! maybe_whole_expr {
     ($p:expr) => (
         {
             let found = match $p.token {
@@ -170,10 +171,10 @@ macro_rules! maybe_whole_expr (
             }
         }
     )
-)
+}
 
 /// As maybe_whole_expr, but for things other than expressions
-macro_rules! maybe_whole (
+macro_rules! maybe_whole {
     ($p:expr, $constructor:ident) => (
         {
             let found = match ($p).token {
@@ -252,7 +253,7 @@ macro_rules! maybe_whole (
             }
         }
     )
-)
+}
 
 
 fn maybe_append(mut lhs: Vec<Attribute>, rhs: Option<Vec<Attribute>>)
@@ -3708,21 +3709,32 @@ impl<'a> Parser<'a> {
             );
             let hi = self.span.hi;
 
+            let style = if delim == token::Brace {
+                MacStmtWithBraces
+            } else {
+                MacStmtWithoutBraces
+            };
+
             if id.name == token::special_idents::invalid.name {
-                if self.check(&token::Dot) {
-                    let span = self.span;
-                    let token_string = self.this_token_to_string();
-                    self.span_err(span,
-                                  format!("expected statement, found `{}`",
-                                          token_string).as_slice());
-                    let mac_span = mk_sp(lo, hi);
-                    self.span_help(mac_span, "try parenthesizing this macro invocation");
-                    self.abort_if_errors();
-                }
-                P(spanned(lo, hi, StmtMac(
-                    spanned(lo, hi, MacInvocTT(pth, tts, EMPTY_CTXT)), false)))
+                P(spanned(lo,
+                          hi,
+                          StmtMac(spanned(lo,
+                                          hi,
+                                          MacInvocTT(pth, tts, EMPTY_CTXT)),
+                                  style)))
             } else {
                 // if it has a special ident, it's definitely an item
+                //
+                // Require a semicolon or braces.
+                if style != MacStmtWithBraces {
+                    if !self.eat(&token::Semi) {
+                        let last_span = self.last_span;
+                        self.span_err(last_span,
+                                      "macros that expand to items must \
+                                       either be surrounded with braces or \
+                                       followed by a semicolon");
+                    }
+                }
                 P(spanned(lo, hi, StmtDecl(
                     P(spanned(lo, hi, DeclItem(
                         self.mk_item(
@@ -3731,7 +3743,6 @@ impl<'a> Parser<'a> {
                             Inherited, Vec::new(/*no attrs*/))))),
                     ast::DUMMY_NODE_ID)))
             }
-
         } else {
             let found_attrs = !item_attrs.is_empty();
             let item_err = Parser::expected_item_err(item_attrs.as_slice());
@@ -3851,43 +3862,46 @@ impl<'a> Parser<'a> {
                     attributes_box = Vec::new();
                     stmt.and_then(|Spanned {node, span}| match node {
                         StmtExpr(e, stmt_id) => {
-                            // expression without semicolon
-                            if classify::expr_requires_semi_to_be_stmt(&*e) {
-                                // Just check for errors and recover; do not eat semicolon yet.
-                                self.commit_stmt(&[], &[token::Semi,
-                                    token::CloseDelim(token::Brace)]);
-                            }
-
+                            self.handle_expression_like_statement(e,
+                                                                  stmt_id,
+                                                                  span,
+                                                                  &mut stmts,
+                                                                  &mut expr);
+                        }
+                        StmtMac(macro, MacStmtWithoutBraces) => {
+                            // statement macro without braces; might be an
+                            // expr depending on whether a semicolon follows
                             match self.token {
                                 token::Semi => {
-                                    self.bump();
-                                    let span_with_semi = Span {
-                                        lo: span.lo,
-                                        hi: self.last_span.hi,
-                                        expn_id: span.expn_id,
-                                    };
                                     stmts.push(P(Spanned {
-                                        node: StmtSemi(e, stmt_id),
-                                        span: span_with_semi,
+                                        node: StmtMac(macro,
+                                                      MacStmtWithSemicolon),
+                                        span: span,
                                     }));
-                                }
-                                token::CloseDelim(token::Brace) => {
-                                    expr = Some(e);
+                                    self.bump();
                                 }
                                 _ => {
-                                    stmts.push(P(Spanned {
-                                        node: StmtExpr(e, stmt_id),
-                                        span: span
-                                    }));
+                                    let e = self.mk_mac_expr(span.lo,
+                                                             span.hi,
+                                                             macro.node);
+                                    let e =
+                                        self.parse_dot_or_call_expr_with(e);
+                                    self.handle_expression_like_statement(
+                                        e,
+                                        ast::DUMMY_NODE_ID,
+                                        span,
+                                        &mut stmts,
+                                        &mut expr);
                                 }
                             }
                         }
-                        StmtMac(m, semi) => {
+                        StmtMac(m, style) => {
                             // statement macro; might be an expr
                             match self.token {
                                 token::Semi => {
                                     stmts.push(P(Spanned {
-                                        node: StmtMac(m, true),
+                                        node: StmtMac(m,
+                                                      MacStmtWithSemicolon),
                                         span: span,
                                     }));
                                     self.bump();
@@ -3902,7 +3916,7 @@ impl<'a> Parser<'a> {
                                 }
                                 _ => {
                                     stmts.push(P(Spanned {
-                                        node: StmtMac(m, semi),
+                                        node: StmtMac(m, style),
                                         span: span
                                     }));
                                 }
@@ -3941,6 +3955,43 @@ impl<'a> Parser<'a> {
         })
     }
 
+    fn handle_expression_like_statement(
+            &mut self,
+            e: P<Expr>,
+            stmt_id: NodeId,
+            span: Span,
+            stmts: &mut Vec<P<Stmt>>,
+            last_block_expr: &mut Option<P<Expr>>) {
+        // expression without semicolon
+        if classify::expr_requires_semi_to_be_stmt(&*e) {
+            // Just check for errors and recover; do not eat semicolon yet.
+            self.commit_stmt(&[],
+                             &[token::Semi, token::CloseDelim(token::Brace)]);
+        }
+
+        match self.token {
+            token::Semi => {
+                self.bump();
+                let span_with_semi = Span {
+                    lo: span.lo,
+                    hi: self.last_span.hi,
+                    expn_id: span.expn_id,
+                };
+                stmts.push(P(Spanned {
+                    node: StmtSemi(e, stmt_id),
+                    span: span_with_semi,
+                }));
+            }
+            token::CloseDelim(token::Brace) => *last_block_expr = Some(e),
+            _ => {
+                stmts.push(P(Spanned {
+                    node: StmtExpr(e, stmt_id),
+                    span: span
+                }));
+            }
+        }
+    }
+
     // Parses a sequence of bounds if a `:` is found,
     // otherwise returns empty list.
     fn parse_colon_then_ty_param_bounds(&mut self)
@@ -4591,6 +4642,9 @@ impl<'a> Parser<'a> {
                 let m: ast::Mac = codemap::Spanned { node: m_,
                                                  span: mk_sp(self.span.lo,
                                                              self.span.hi) };
+                if delim != token::Brace {
+                    self.expect(&token::Semi)
+                }
                 (ast::MethMac(m), self.span.hi, attrs)
             } else {
                 let unsafety = self.parse_unsafety();
@@ -5747,6 +5801,17 @@ impl<'a> Parser<'a> {
             let m: ast::Mac = codemap::Spanned { node: m,
                                              span: mk_sp(self.span.lo,
                                                          self.span.hi) };
+
+            if delim != token::Brace {
+                if !self.eat(&token::Semi) {
+                    let last_span = self.last_span;
+                    self.span_err(last_span,
+                                  "macros that expand to items must either \
+                                   be surrounded with braces or followed by \
+                                   a semicolon");
+                }
+            }
+
             let item_ = ItemMac(m);
             let last_span = self.last_span;
             let item = self.mk_item(lo,
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 1bdcd73d847..641239f1f8b 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -570,7 +570,7 @@ pub type IdentInterner = StrInterner;
 pub fn get_ident_interner() -> Rc<IdentInterner> {
     thread_local!(static KEY: Rc<::parse::token::IdentInterner> = {
         Rc::new(mk_fresh_ident_interner())
-    })
+    });
     KEY.with(|k| k.clone())
 }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index cbbfcfef72e..1dd61a5ce19 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -409,12 +409,12 @@ pub fn arg_to_string(arg: &ast::Arg) -> String {
 }
 
 pub fn mac_to_string(arg: &ast::Mac) -> String {
-    $to_string(|s| s.print_mac(arg))
+    $to_string(|s| s.print_mac(arg, ::parse::token::Paren))
 }
 
 } }
 
-thing_to_string_impls!(to_string)
+thing_to_string_impls! { to_string }
 
 // FIXME (Issue #16472): the whole `with_hygiene` mod should go away
 // after we revise the syntax::ext::quote::ToToken impls to go directly
@@ -437,7 +437,7 @@ pub mod with_hygiene {
         })
     }
 
-    thing_to_string_impls!(to_string_hyg)
+    thing_to_string_impls! { to_string_hyg }
 }
 
 pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> String {
@@ -992,6 +992,7 @@ impl<'a> State<'a> {
                 try!(self.popen());
                 try!(self.print_tts(tts.as_slice()));
                 try!(self.pclose());
+                try!(word(&mut self.s, ";"));
                 try!(self.end());
             }
         }
@@ -1258,6 +1259,7 @@ impl<'a> State<'a> {
                 try!(self.popen());
                 try!(self.print_tts(tts.as_slice()));
                 try!(self.pclose());
+                try!(word(&mut self.s, ";"));
                 self.end()
             }
         }
@@ -1330,11 +1332,16 @@ impl<'a> State<'a> {
                 try!(self.print_expr(&**expr));
                 try!(word(&mut self.s, ";"));
             }
-            ast::StmtMac(ref mac, semi) => {
+            ast::StmtMac(ref mac, style) => {
                 try!(self.space_if_not_bol());
-                try!(self.print_mac(mac));
-                if semi {
-                    try!(word(&mut self.s, ";"));
+                let delim = match style {
+                    ast::MacStmtWithBraces => token::Brace,
+                    _ => token::Paren
+                };
+                try!(self.print_mac(mac, delim));
+                match style {
+                    ast::MacStmtWithBraces => {}
+                    _ => try!(word(&mut self.s, ";")),
                 }
             }
         }
@@ -1461,15 +1468,24 @@ impl<'a> State<'a> {
         self.print_else(elseopt)
     }
 
-    pub fn print_mac(&mut self, m: &ast::Mac) -> IoResult<()> {
+    pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken)
+                     -> IoResult<()> {
         match m.node {
             // I think it's reasonable to hide the ctxt here:
             ast::MacInvocTT(ref pth, ref tts, _) => {
                 try!(self.print_path(pth, false));
                 try!(word(&mut self.s, "!"));
-                try!(self.popen());
+                match delim {
+                    token::Paren => try!(self.popen()),
+                    token::Bracket => try!(word(&mut self.s, "[")),
+                    token::Brace => try!(self.bopen()),
+                }
                 try!(self.print_tts(tts.as_slice()));
-                self.pclose()
+                match delim {
+                    token::Paren => self.pclose(),
+                    token::Bracket => word(&mut self.s, "]"),
+                    token::Brace => self.bclose(m.span),
+                }
             }
         }
     }
@@ -1817,7 +1833,7 @@ impl<'a> State<'a> {
                 }));
                 try!(self.pclose());
             }
-            ast::ExprMac(ref m) => try!(self.print_mac(m)),
+            ast::ExprMac(ref m) => try!(self.print_mac(m, token::Paren)),
             ast::ExprParen(ref e) => {
                 try!(self.popen());
                 try!(self.print_expr(&**e));
@@ -2098,7 +2114,7 @@ impl<'a> State<'a> {
                                    |s, p| s.print_pat(&**p)));
                 try!(word(&mut self.s, "]"));
             }
-            ast::PatMac(ref m) => try!(self.print_mac(m)),
+            ast::PatMac(ref m) => try!(self.print_mac(m, token::Paren)),
         }
         self.ann.post(self, NodePat(pat))
     }
@@ -2187,7 +2203,7 @@ impl<'a> State<'a> {
         try!(self.nbsp());
         try!(self.print_ident(name));
         try!(self.print_generics(generics));
-        try!(self.print_fn_args_and_ret(decl, opt_explicit_self))
+        try!(self.print_fn_args_and_ret(decl, opt_explicit_self));
         self.print_where_clause(generics)
     }