Merge tag 0.10.8 into master

Conflicts:
    Cargo.toml
diff --git a/.travis.yml b/.travis.yml
index 4e9dea9..5378689 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,6 +11,15 @@
     - .git/modules
 
 matrix:
+  include:
+    - rust: stable
+      env: ROLE=build
+    - rust: beta
+      env: ROLE=build
+    - rust: 1.12.1
+      env: ROLE=build
+    - rust: 1.13.0
+      env: ROLE=build
   allow_failures:
     - env: ROLE=clippy
 
@@ -27,21 +36,24 @@
         build)
           cargo build --no-default-features &&
           cargo build &&
-          cargo build --features 'full expand' &&
-          cargo doc --features 'full expand'
+          cargo build --features full &&
+          cargo doc --features 'full visit'
           ;;
         test)
           git submodule update --init &&
-          cargo test --features 'full aster expand pretty visit' --release
+          cargo test --features 'full aster visit' --release
           ;;
         clippy)
-          cargo build --features 'full aster expand pretty visit clippy'
+          cargo build --features 'full aster visit clippy'
+          ;;
+        *)
+          exit 1
           ;;
       esac
 
 after_success:
   - |
-      if [ "$ROLE" = build ]; then
+      if [ "$ROLE" = build ] && [ "$TRAVIS_RUST_VERSION" = nightly ]; then
         travis-cargo doc-upload
       fi
 
diff --git a/Cargo.toml b/Cargo.toml
index 13b273d..379316d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "syn"
-version = "0.10.8" # don't forget to update version in readme for breaking changes
+version = "0.11.4" # don't forget to update version in readme for breaking changes
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 license = "MIT/Apache-2.0"
 description = "Nom parser for Rust source code"
@@ -11,22 +11,19 @@
 [features]
 default = ["parsing", "printing"]
 aster = []
-expand = ["full", "parsing", "printing"]
 full = []
 parsing = ["unicode-xid"]
-pretty = ["syntex_syntax"]
 printing = ["quote"]
 visit = []
 
 [dependencies]
 clippy = { version = "0.*", optional = true }
 quote = { version = "0.3.0", optional = true }
-syntex_syntax = { version = "0.50.0", optional = true }
 unicode-xid = { version = "0.0.4", optional = true }
 
 [dev-dependencies]
-syntex_pos = "0.50.0"
-syntex_syntax = "0.50.0"
+syntex_pos = "0.52.0"
+syntex_syntax = "0.52.0"
 tempdir = "0.3.5"
 time = "0.1.35"
 walkdir = "1.0.1"
diff --git a/README.md b/README.md
index 4c4364d..8b30fb5 100644
--- a/README.md
+++ b/README.md
@@ -10,14 +10,17 @@
 
 Designed for fast compile time.
 
-- Compile time for `syn` (from scratch including all dependencies): **4 seconds**
+- Compile time for `syn` (from scratch including all dependencies): **6 seconds**
 - Compile time for the `syntex`/`quasi`/`aster` stack: **60+ seconds**
 
+If you get stuck with Macros 1.1 I am happy to provide help even if the issue is
+not related to syn. Please file a ticket in this repo.
+
 ## Usage with Macros 1.1
 
 ```toml
 [dependencies]
-syn = "0.10"
+syn = "0.11"
 quote = "0.3"
 
 [lib]
@@ -25,8 +28,6 @@
 ```
 
 ```rust
-#![feature(proc_macro, proc_macro_lib)]
-
 extern crate proc_macro;
 use proc_macro::TokenStream;
 
@@ -39,8 +40,8 @@
 pub fn my_macro(input: TokenStream) -> TokenStream {
     let source = input.to_string();
 
-    // Parse the string representation to an AST
-    let ast = syn::parse_macro_input(&source).unwrap();
+    // Parse the string representation into a syntax tree
+    let ast = syn::parse_derive_input(&source).unwrap();
 
     // Build the output, possibly using quasi-quotation
     let expanded = quote! {
@@ -67,8 +68,6 @@
 and [`quote`](https://github.com/dtolnay/quote) looks like this:
 
 ```rust
-#![feature(proc_macro, proc_macro_lib)]
-
 extern crate proc_macro;
 use proc_macro::TokenStream;
 
@@ -81,8 +80,8 @@
 pub fn num_fields(input: TokenStream) -> TokenStream {
     let source = input.to_string();
 
-    // Parse the string representation to an AST
-    let ast = syn::parse_macro_input(&source).unwrap();
+    // Parse the string representation into a syntax tree
+    let ast = syn::parse_derive_input(&source).unwrap();
 
     // Build the output
     let expanded = expand_num_fields(&ast);
@@ -91,7 +90,7 @@
     expanded.parse().unwrap()
 }
 
-fn expand_num_fields(ast: &syn::MacroInput) -> quote::Tokens {
+fn expand_num_fields(ast: &syn::DeriveInput) -> quote::Tokens {
     let n = match ast.body {
         syn::Body::Struct(ref data) => data.fields().len(),
         syn::Body::Enum(_) => panic!("#[derive(NumFields)] can only be used with structs"),
@@ -114,6 +113,59 @@
 }
 ```
 
+## Testing
+
+Macros 1.1 has a restriction that your proc-macro crate must export nothing but
+`proc_macro_derive` functions, and also `proc_macro_derive` procedural macros
+cannot be used from the same crate in which they are defined. These restrictions
+may be lifted in the future but for now they make writing tests a bit trickier
+than for other types of code.
+
+In particular, you will not be able to write test functions like `#[test] fn
+it_works() { ... }` in line with your code. Instead, either put tests in a
+[`tests` directory](https://doc.rust-lang.org/book/testing.html#the-tests-directory)
+or in a separate crate entirely.
+
+Additionally, if your procedural macro implements a particular trait, that trait
+must be defined in a separate crate from the procedural macro.
+
+As a concrete example, suppose your procedural macro crate is called `my_derive`
+and it implements a trait called `my_crate::MyTrait`. Your unit tests for the
+procedural macro can go in `my_derive/tests/test.rs` or into a separate crate
+`my_tests/tests/test.rs`. Either way the test would look something like this:
+
+```rust
+#[macro_use]
+extern crate my_derive;
+
+extern crate my_crate;
+use my_crate::MyTrait;
+
+#[test]
+fn it_works() {
+    #[derive(MyTrait)]
+    struct S { /* ... */ }
+
+    /* test the thing */
+}
+```
+
+## Debugging
+
+When developing a procedural macro it can be helpful to look at what the
+generated code looks like. Use `cargo rustc -- -Zunstable-options
+--pretty=expanded` or the
+[`cargo expand`](https://github.com/dtolnay/cargo-expand) subcommand.
+
+To show the expanded code for some crate that uses your procedural macro, run
+`cargo expand` from that crate. To show the expanded code for one of your own
+test cases, run `cargo expand --test the_test_case` where the last argument is
+the name of the test file without the `.rs` extension.
+
+This write-up by Brandon W Maister discusses debugging in more detail:
+[Debugging Rust's new Custom Derive
+system](https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/).
+
 ## Optional features
 
 Syn puts a lot of functionality behind optional features in order to optimize
@@ -122,70 +174,14 @@
 
 Features | Compile time | Functionality
 --- | --- | ---
-*(none)* | 1 sec | The data structures representing the AST of Rust structs, enums, and types.
-parsing | 4 sec | Parsing Rust source code containing structs and enums into an AST.
-printing | 2 sec | Printing an AST of structs and enums as Rust source code.
-**parsing, printing** | **4 sec** | **This is the default.** Parsing and printing of Rust structs and enums. This is typically what you want for implementing Macros 1.1 custom derives.
-full | 2 sec | The data structures representing the full AST of all possible Rust code.
-full, parsing | 7 sec | Parsing any valid Rust source code to an AST.
-full, printing | 4 sec | Turning an AST into Rust source code.
-full, parsing, printing | 8 sec | Parsing and printing any Rust syntax.
-full, parsing, printing, expand | 9 sec | Expansion of custom derives in a file of Rust code. This is typically what you want for expanding custom derives on stable Rust using a build script.
-full, parsing, printing, expand, pretty | 60 sec | Expansion of custom derives with pretty-printed output. This is what you want when iterating on or debugging a custom derive, but the pretty printing should be disabled once you get everything working.
-
-## Custom derives on stable Rust
-
-Syn supports a way of expanding custom derives from a build script, similar to
-what [Serde is able to do with serde_codegen](https://serde.rs/codegen-stable.html).
-The advantage of using Syn for this purpose rather than Syntex is much faster
-compile time.
-
-Continuing with the `NumFields` example from above, it can be extended to
-support stable Rust like this. One or more custom derives are added to a
-[`Registry`](https://dtolnay.github.io/syn/syn/struct.Registry.html), which is
-then able to expand those derives in a source file at a particular path and
-write the expanded output to a different path. A custom derive is represented by
-the [`CustomDerive`](https://dtolnay.github.io/syn/syn/trait.CustomDerive.html)
-trait which takes a [`MacroInput`](https://dtolnay.github.io/syn/syn/struct.MacroInput.html)
-(either a struct or an enum) and [expands it](https://dtolnay.github.io/syn/syn/struct.Expanded.html)
-into zero or more new items and maybe a modified or unmodified instance of the
-original input.
-
-```rust
-pub fn expand_file<S, D>(src: S, dst: D) -> Result<(), String>
-    where S: AsRef<Path>,
-          D: AsRef<Path>
-{
-    let mut registry = syn::Registry::new();
-    registry.add_derive("NumFields", |input| {
-        let tokens = expand_num_fields(&input);
-        let items = syn::parse_items(&tokens.to_string()).unwrap();
-        Ok(syn::Expanded {
-            new_items: items,
-            original: Some(input),
-        })
-    });
-    registry.expand_file(src, dst)
-}
-```
-
-The codegen can be invoked from a build script as follows.
-
-```rust
-extern crate your_codegen;
-
-use std::env;
-use std::path::Path;
-
-fn main() {
-    let out_dir = env::var_os("OUT_DIR").unwrap();
-
-    let src = Path::new("src/codegen_types.in.rs");
-    let dst = Path::new(&out_dir).join("codegen_types.rs");
-
-    your_codegen::expand_file(&src, &dst).unwrap();
-}
-```
+*(none)* | 3 sec | The data structures representing the AST of Rust structs, enums, and types.
+parsing | 6 sec | Parsing Rust source code containing structs and enums into an AST.
+printing | 4 sec | Printing an AST of structs and enums as Rust source code.
+**parsing, printing** | **6 sec** | **This is the default.** Parsing and printing of Rust structs and enums. This is typically what you want for implementing Macros 1.1 custom derives.
+full | 4 sec | The data structures representing the full AST of all possible Rust code.
+full, parsing | 9 sec | Parsing any valid Rust source code to an AST.
+full, printing | 6 sec | Turning an AST into Rust source code.
+full, parsing, printing | 11 sec | Parsing and printing any Rust syntax.
 
 ## License
 
diff --git a/src/aster/ty.rs b/src/aster/ty.rs
index 96b6554..127b164 100644
--- a/src/aster/ty.rs
+++ b/src/aster/ty.rs
@@ -158,10 +158,6 @@
         TyBuilder::with_callback(TyIteratorBuilder(self))
     }
 
-    pub fn object_sum(self) -> TyBuilder<TyObjectSumBuilder<F>> {
-        TyBuilder::with_callback(TyObjectSumBuilder { builder: self })
-    }
-
     pub fn impl_trait(self) -> TyImplTraitTyBuilder<F> {
         TyImplTraitTyBuilder {
             builder: self,
@@ -389,90 +385,6 @@
 
 // ////////////////////////////////////////////////////////////////////////////
 
-pub struct TyObjectSumBuilder<F> {
-    builder: TyBuilder<F>,
-}
-
-impl<F> Invoke<Ty> for TyObjectSumBuilder<F>
-    where F: Invoke<Ty>
-{
-    type Result = TyObjectSumTyBuilder<F>;
-
-    fn invoke(self, ty: Ty) -> Self::Result {
-        TyObjectSumTyBuilder {
-            builder: self.builder,
-            ty: ty,
-            bounds: Vec::new(),
-        }
-    }
-}
-
-pub struct TyObjectSumTyBuilder<F> {
-    builder: TyBuilder<F>,
-    ty: Ty,
-    bounds: Vec<TyParamBound>,
-}
-
-impl<F> TyObjectSumTyBuilder<F>
-    where F: Invoke<Ty>
-{
-    pub fn with_bounds<I>(mut self, iter: I) -> Self
-        where I: Iterator<Item = TyParamBound>
-    {
-        self.bounds.extend(iter);
-        self
-    }
-
-    pub fn with_bound(mut self, bound: TyParamBound) -> Self {
-        self.bounds.push(bound);
-        self
-    }
-
-    pub fn bound(self) -> TyParamBoundBuilder<Self> {
-        TyParamBoundBuilder::with_callback(self)
-    }
-
-    pub fn with_generics(self, generics: Generics) -> Self {
-        self.with_lifetimes(generics.lifetimes
-            .into_iter()
-            .map(|def| def.lifetime))
-    }
-
-    pub fn with_lifetimes<I, L>(mut self, lifetimes: I) -> Self
-        where I: Iterator<Item = L>,
-              L: IntoLifetime
-    {
-        for lifetime in lifetimes {
-            self = self.lifetime(lifetime);
-        }
-
-        self
-    }
-
-    pub fn lifetime<L>(self, lifetime: L) -> Self
-        where L: IntoLifetime
-    {
-        self.bound().lifetime(lifetime)
-    }
-
-    pub fn build(self) -> F::Result {
-        let bounds = self.bounds;
-        self.builder.build(Ty::ObjectSum(Box::new(self.ty), bounds))
-    }
-}
-
-impl<F> Invoke<TyParamBound> for TyObjectSumTyBuilder<F>
-    where F: Invoke<Ty>
-{
-    type Result = Self;
-
-    fn invoke(self, bound: TyParamBound) -> Self {
-        self.with_bound(bound)
-    }
-}
-
-// ////////////////////////////////////////////////////////////////////////////
-
 pub struct TyImplTraitTyBuilder<F> {
     builder: TyBuilder<F>,
     bounds: Vec<TyParamBound>,
diff --git a/src/macro_input.rs b/src/derive.rs
similarity index 92%
rename from src/macro_input.rs
rename to src/derive.rs
index de99f27..20b710b 100644
--- a/src/macro_input.rs
+++ b/src/derive.rs
@@ -1,7 +1,7 @@
 use super::*;
 
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct MacroInput {
+pub struct DeriveInput {
     pub ident: Ident,
     pub vis: Visibility,
     pub attrs: Vec<Attribute>,
@@ -24,14 +24,14 @@
     use generics::parsing::generics;
     use ident::parsing::ident;
 
-    named!(pub macro_input -> MacroInput, do_parse!(
+    named!(pub derive_input -> DeriveInput, do_parse!(
         attrs: many0!(outer_attr) >>
         vis: visibility >>
         which: alt!(keyword!("struct") | keyword!("enum")) >>
         id: ident >>
         generics: generics >>
         item: switch!(value!(which),
-            "struct" => map!(struct_body, move |(wh, body)| MacroInput {
+            "struct" => map!(struct_body, move |(wh, body)| DeriveInput {
                 ident: id,
                 vis: vis,
                 attrs: attrs,
@@ -42,7 +42,7 @@
                 body: Body::Struct(body),
             })
             |
-            "enum" => map!(enum_body, move |(wh, body)| MacroInput {
+            "enum" => map!(enum_body, move |(wh, body)| DeriveInput {
                 ident: id,
                 vis: vis,
                 attrs: attrs,
@@ -64,7 +64,7 @@
     use data::VariantData;
     use quote::{Tokens, ToTokens};
 
-    impl ToTokens for MacroInput {
+    impl ToTokens for DeriveInput {
         fn to_tokens(&self, tokens: &mut Tokens) {
             for attr in self.attrs.outer() {
                 attr.to_tokens(tokens);
diff --git a/src/expr.rs b/src/expr.rs
index c8b574d..7b6602a 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -22,7 +22,7 @@
     /// First expr is the place; second expr is the value.
     InPlace(Box<Expr>, Box<Expr>),
     /// An array (`[a, b, c, d]`)
-    Vec(Vec<Expr>),
+    Array(Vec<Expr>),
     /// A function call
     ///
     /// The first field resolves to the function itself,
@@ -85,10 +85,10 @@
     Loop(Block, Option<Ident>),
     /// A `match` block.
     Match(Box<Expr>, Vec<Arm>),
-    /// A closure (for example, `move |a, b, c| {a + b + c}`)
-    Closure(CaptureBy, Box<FnDecl>, Block),
+    /// A closure (for example, `move |a, b, c| a + b + c`)
+    Closure(CaptureBy, Box<FnDecl>, Box<Expr>),
     /// A block (`{ ... }` or `unsafe { ... }`)
-    Block(BlockCheckMode, Block),
+    Block(Unsafety, Block),
 
     /// An assignment (`a = foo()`)
     Assign(Box<Expr>, Box<Expr>),
@@ -116,8 +116,8 @@
 
     /// A referencing operation (`&a` or `&mut a`)
     AddrOf(Mutability, Box<Expr>),
-    /// A `break`, with an optional label to break
-    Break(Option<Ident>),
+    /// A `break`, with an optional label to break, and an optional expression
+    Break(Option<Ident>, Option<Box<Expr>>),
     /// A `continue`, with an optional label
     Continue(Option<Ident>),
     /// A `return`, with an optional value to be returned
@@ -150,6 +150,7 @@
     pub ident: Ident,
     pub expr: Expr,
     pub is_shorthand: bool,
+    pub attrs: Vec<Attribute>,
 }
 
 /// A Block (`{ .. }`).
@@ -161,12 +162,6 @@
     pub stmts: Vec<Stmt>,
 }
 
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum BlockCheckMode {
-    Default,
-    Unsafe,
-}
-
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
 pub enum Stmt {
     /// A local (let) binding.
@@ -300,6 +295,7 @@
     /// The pattern the field is destructured to
     pub pat: Box<Pat>,
     pub is_shorthand: bool,
+    pub attrs: Vec<Attribute>,
 }
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
@@ -312,7 +308,7 @@
 pub mod parsing {
     use super::*;
     use {BinOp, Delimited, DelimToken, FnArg, FnDecl, FunctionRetTy, Ident, Lifetime, Mac,
-         TokenTree, Ty, UnOp};
+         TokenTree, Ty, UnOp, Unsafety};
     use attr::parsing::outer_attr;
     use generics::parsing::lifetime;
     use ident::parsing::{ident, wordlike};
@@ -321,7 +317,7 @@
     use mac::parsing::{mac, token_trees};
     use nom::IResult::{self, Error};
     use op::parsing::{assign_op, binop, unop};
-    use ty::parsing::{mutability, path, qpath, ty};
+    use ty::parsing::{mutability, path, qpath, ty, unsafety};
 
     // Struct literals are ambiguous in certain positions
     // https://github.com/rust-lang/rfcs/pull/92
@@ -355,7 +351,7 @@
                 |
                 expr_mac // must be before expr_path
                 |
-                expr_break // must be before expr_path
+                call!(expr_break, allow_struct) // must be before expr_path
                 |
                 expr_continue // must be before expr_path
                 |
@@ -365,7 +361,7 @@
                 |
                 expr_in_place
                 |
-                expr_vec
+                expr_array
                 |
                 expr_tup
                 |
@@ -474,17 +470,17 @@
         punct!("}") >>
         (ExprKind::InPlace(
             Box::new(place),
-            Box::new(ExprKind::Block(BlockCheckMode::Default, Block {
+            Box::new(ExprKind::Block(Unsafety::Normal, Block {
                 stmts: value,
             }).into()),
         ))
     ));
 
-    named!(expr_vec -> ExprKind, do_parse!(
+    named!(expr_array -> ExprKind, do_parse!(
         punct!("[") >>
         elems: terminated_list!(punct!(","), expr) >>
         punct!("]") >>
-        (ExprKind::Vec(elems))
+        (ExprKind::Array(elems))
     ));
 
     named!(and_call -> Vec<Expr>, do_parse!(
@@ -571,7 +567,7 @@
                     punct!("{") >>
                     else_block: within_block >>
                     punct!("}") >>
-                    (ExprKind::Block(BlockCheckMode::Default, Block {
+                    (ExprKind::Block(Unsafety::Normal, Block {
                         stmts: else_block,
                     }).into())
                 )
@@ -632,7 +628,7 @@
     ));
 
     fn arm_requires_comma(arm: &Arm) -> bool {
-        if let ExprKind::Block(BlockCheckMode::Default, _) = arm.body.node {
+        if let ExprKind::Block(Unsafety::Normal, _) = arm.body.node {
             false
         } else {
             true
@@ -645,7 +641,7 @@
         guard: option!(preceded!(keyword!("if"), expr)) >>
         punct!("=>") >>
         body: alt!(
-            map!(block, |blk| ExprKind::Block(BlockCheckMode::Default, blk).into())
+            map!(block, |blk| ExprKind::Block(Unsafety::Normal, blk).into())
             |
             expr
         ) >>
@@ -667,15 +663,10 @@
                 punct!("->") >>
                 ty: ty >>
                 body: block >>
-                ((FunctionRetTy::Ty(ty), body))
+                (FunctionRetTy::Ty(ty), ExprKind::Block(Unsafety::Normal, body).into())
             )
             |
-            map!(ambiguous_expr!(allow_struct), |e| (
-                FunctionRetTy::Default,
-                Block {
-                    stmts: vec![Stmt::Expr(Box::new(e))],
-                },
-            ))
+            map!(ambiguous_expr!(allow_struct), |e| (FunctionRetTy::Default, e))
         ) >>
         (ExprKind::Closure(
             capture,
@@ -684,7 +675,7 @@
                 output: ret_and_body.0,
                 variadic: false,
             }),
-            ret_and_body.1,
+            Box::new(ret_and_body.1),
         ))
     ));
 
@@ -720,10 +711,11 @@
         (ExprKind::Continue(lbl))
     ));
 
-    named!(expr_break -> ExprKind, do_parse!(
+    named_ambiguous_expr!(expr_break -> ExprKind, allow_struct, do_parse!(
         keyword!("break") >>
         lbl: option!(label) >>
-        (ExprKind::Break(lbl))
+        val: option!(call!(ambiguous_expr, allow_struct, false)) >>
+        (ExprKind::Break(lbl, val.map(Box::new)))
     ));
 
     named_ambiguous_expr!(expr_ret -> ExprKind, allow_struct, do_parse!(
@@ -756,6 +748,7 @@
                 ident: name,
                 expr: value,
                 is_shorthand: false,
+                attrs: Vec::new(),
             })
         )
         |
@@ -763,6 +756,7 @@
             ident: name.clone(),
             expr: ExprKind::Path(None, name.into()).into(),
             is_shorthand: true,
+            attrs: Vec::new(),
         })
     ));
 
@@ -776,7 +770,7 @@
     ));
 
     named!(expr_block -> ExprKind, do_parse!(
-        rules: block_check_mode >>
+        rules: unsafety >>
         b: block >>
         (ExprKind::Block(rules, Block {
             stmts: b.stmts,
@@ -834,12 +828,6 @@
         })
     ));
 
-    named!(block_check_mode -> BlockCheckMode, alt!(
-        keyword!("unsafe") => { |_| BlockCheckMode::Unsafe }
-        |
-        epsilon!() => { |_| BlockCheckMode::Default }
-    ));
-
     named!(pub within_block -> Vec<Stmt>, do_parse!(
         many0!(punct!(";")) >>
         mut standalone: many0!(terminated!(standalone_stmt, many0!(punct!(";")))) >>
@@ -865,7 +853,7 @@
 
     named!(stmt_mac -> Stmt, do_parse!(
         attrs: many0!(outer_attr) >>
-        name: ident >>
+        what: path >>
         punct!("!") >>
     // Only parse braces here; paren and bracket will get parsed as
     // expression statements
@@ -875,7 +863,7 @@
         semi: option!(punct!(";")) >>
         (Stmt::Mac(Box::new((
             Mac {
-                path: name.into(),
+                path: what,
                 tts: vec![TokenTree::Delimited(Delimited {
                     delim: DelimToken::Brace,
                     tts: tts,
@@ -1024,6 +1012,7 @@
                 ident: ident,
                 pat: Box::new(pat),
                 is_shorthand: false,
+                attrs: Vec::new(),
             })
         )
         |
@@ -1049,6 +1038,7 @@
                     ident: ident,
                     pat: Box::new(pat),
                     is_shorthand: true,
+                    attrs: Vec::new(),
                 }
             })
         )
@@ -1159,7 +1149,7 @@
 #[cfg(feature = "printing")]
 mod printing {
     use super::*;
-    use {FnArg, FunctionRetTy, Mutability, Ty};
+    use {FnArg, FunctionRetTy, Mutability, Ty, Unsafety};
     use attr::FilterAttrs;
     use quote::{Tokens, ToTokens};
 
@@ -1176,7 +1166,7 @@
                     place.to_tokens(tokens);
                     value.to_tokens(tokens);
                 }
-                ExprKind::Vec(ref tys) => {
+                ExprKind::Array(ref tys) => {
                     tokens.append("[");
                     tokens.append_separated(tys, ",");
                     tokens.append("]");
@@ -1297,7 +1287,7 @@
                     tokens.append_all(arms);
                     tokens.append("}");
                 }
-                ExprKind::Closure(capture, ref decl, ref body) => {
+                ExprKind::Closure(capture, ref decl, ref expr) => {
                     capture.to_tokens(tokens);
                     tokens.append("|");
                     for (i, input) in decl.inputs.iter().enumerate() {
@@ -1313,23 +1303,13 @@
                     }
                     tokens.append("|");
                     match decl.output {
-                        FunctionRetTy::Default => {
-                            if body.stmts.len() == 1 {
-                                if let Stmt::Expr(ref expr) = body.stmts[0] {
-                                    expr.to_tokens(tokens);
-                                } else {
-                                    body.to_tokens(tokens);
-                                }
-                            } else {
-                                body.to_tokens(tokens);
-                            }
-                        }
+                        FunctionRetTy::Default => { /* nothing */ }
                         FunctionRetTy::Ty(ref ty) => {
                             tokens.append("->");
                             ty.to_tokens(tokens);
-                            body.to_tokens(tokens);
                         }
                     }
+                    expr.to_tokens(tokens);
                 }
                 ExprKind::Block(rules, ref block) => {
                     rules.to_tokens(tokens);
@@ -1396,9 +1376,10 @@
                     mutability.to_tokens(tokens);
                     expr.to_tokens(tokens);
                 }
-                ExprKind::Break(ref opt_label) => {
+                ExprKind::Break(ref opt_label, ref opt_val) => {
                     tokens.append("break");
                     opt_label.to_tokens(tokens);
+                    opt_val.to_tokens(tokens);
                 }
                 ExprKind::Continue(ref opt_label) => {
                     tokens.append("continue");
@@ -1465,7 +1446,7 @@
             tokens.append("=>");
             self.body.to_tokens(tokens);
             match self.body.node {
-                ExprKind::Block(BlockCheckMode::Default, _) => {
+                ExprKind::Block(Unsafety::Normal, _) => {
                     // no comma
                 }
                 _ => tokens.append(","),
@@ -1646,17 +1627,6 @@
         }
     }
 
-    impl ToTokens for BlockCheckMode {
-        fn to_tokens(&self, tokens: &mut Tokens) {
-            match *self {
-                BlockCheckMode::Default => {
-                    // nothing
-                }
-                BlockCheckMode::Unsafe => tokens.append("unsafe"),
-            }
-        }
-    }
-
     impl ToTokens for Stmt {
         fn to_tokens(&self, tokens: &mut Tokens) {
             match *self {
diff --git a/src/generics.rs b/src/generics.rs
index d76051f..46d7c43 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -19,8 +19,13 @@
 #[derive(Debug)]
 pub struct TyGenerics<'a>(&'a Generics);
 
+#[cfg(feature = "printing")]
+/// Returned by `TyGenerics::as_turbofish`.
+#[derive(Debug)]
+pub struct Turbofish<'a>(&'a Generics);
+
+#[cfg(feature = "printing")]
 impl Generics {
-    #[cfg(feature = "printing")]
     /// Split a type's generics into the pieces required for impl'ing a trait
     /// for that type.
     ///
@@ -45,6 +50,14 @@
     }
 }
 
+#[cfg(feature = "printing")]
+impl<'a> TyGenerics<'a> {
+    /// Turn a type's generics like `<X, Y>` into a turbofish like `::<X, Y>`.
+    pub fn as_turbofish(&self) -> Turbofish {
+        Turbofish(self.0)
+    }
+}
+
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
 pub struct Lifetime {
     pub ident: Ident,
@@ -125,6 +138,8 @@
     BoundPredicate(WhereBoundPredicate),
     /// A lifetime predicate, e.g. `'a: 'b+'c`
     RegionPredicate(WhereRegionPredicate),
+    /// An equality predicate (unsupported)
+    EqPredicate(WhereEqPredicate),
 }
 
 /// A type bound.
@@ -149,6 +164,15 @@
     pub bounds: Vec<Lifetime>,
 }
 
+/// An equality predicate (unsupported).
+///
+/// E.g. `T=int`
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct WhereEqPredicate {
+    pub lhs_ty: Ty,
+    pub rhs_ty: Ty,
+}
+
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
@@ -349,6 +373,17 @@
         }
     }
 
+    impl<'a> ToTokens for Turbofish<'a> {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            let has_lifetimes = !self.0.lifetimes.is_empty();
+            let has_ty_params = !self.0.ty_params.is_empty();
+            if has_lifetimes || has_ty_params {
+                tokens.append("::");
+                TyGenerics(self.0).to_tokens(tokens);
+            }
+        }
+    }
+
     impl ToTokens for Lifetime {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.ident.to_tokens(tokens);
@@ -414,6 +449,9 @@
                 WherePredicate::RegionPredicate(ref predicate) => {
                     predicate.to_tokens(tokens);
                 }
+                WherePredicate::EqPredicate(ref predicate) => {
+                    predicate.to_tokens(tokens);
+                }
             }
         }
     }
@@ -443,4 +481,12 @@
             }
         }
     }
+
+    impl ToTokens for WhereEqPredicate {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.lhs_ty.to_tokens(tokens);
+            tokens.append("=");
+            self.rhs_ty.to_tokens(tokens);
+        }
+    }
 }
diff --git a/src/item.rs b/src/item.rs
index 00d537a..dc4157e 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -80,8 +80,8 @@
     Mac(Mac),
 }
 
-impl From<MacroInput> for Item {
-    fn from(input: MacroInput) -> Item {
+impl From<DeriveInput> for Item {
+    fn from(input: DeriveInput) -> Item {
         Item {
             ident: input.ident,
             vis: input.vis,
@@ -242,8 +242,8 @@
     use generics::parsing::{generics, lifetime, ty_param_bound, where_clause};
     use ident::parsing::ident;
     use mac::parsing::delimited;
-    use macro_input::{Body, MacroInput};
-    use macro_input::parsing::macro_input;
+    use derive::{Body, DeriveInput};
+    use derive::parsing::derive_input;
     use ty::parsing::{abi, mutability, path, ty, unsafety};
 
     named!(pub item -> Item, alt!(
@@ -280,7 +280,7 @@
 
     named!(item_mac -> Item, do_parse!(
         attrs: many0!(outer_attr) >>
-        path: ident >>
+        what: path >>
         punct!("!") >>
         name: option!(ident) >>
         body: delimited >>
@@ -293,7 +293,7 @@
             vis: Visibility::Inherited,
             attrs: attrs,
             node: ItemKind::Mac(Mac {
-                path: path.into(),
+                path: what,
                 tts: vec![TokenTree::Delimited(body)],
             }),
         })
@@ -639,8 +639,8 @@
     ));
 
     named!(item_struct_or_enum -> Item, map!(
-        macro_input,
-        |def: MacroInput| Item {
+        derive_input,
+        |def: DeriveInput| Item {
             ident: def.ident,
             vis: def.vis,
             attrs: def.attrs,
@@ -821,7 +821,7 @@
 
     named!(trait_item_mac -> TraitItem, do_parse!(
         attrs: many0!(outer_attr) >>
-        id: ident >>
+        what: path >>
         punct!("!") >>
         body: delimited >>
         cond!(match body.delim {
@@ -829,10 +829,10 @@
             DelimToken::Brace => false,
         }, punct!(";")) >>
         (TraitItem {
-            ident: id.clone(),
+            ident: Ident::new(""),
             attrs: attrs,
             node: TraitItemKind::Macro(Mac {
-                path: id.into(),
+                path: what,
                 tts: vec![TokenTree::Delimited(body)],
             }),
         })
@@ -976,7 +976,7 @@
 
     named!(impl_item_macro -> ImplItem, do_parse!(
         attrs: many0!(outer_attr) >>
-        id: ident >>
+        what: path >>
         punct!("!") >>
         body: delimited >>
         cond!(match body.delim {
@@ -984,12 +984,12 @@
             DelimToken::Brace => false,
         }, punct!(";")) >>
         (ImplItem {
-            ident: id.clone(),
+            ident: Ident::new(""),
             vis: Visibility::Inherited,
             defaultness: Defaultness::Final,
             attrs: attrs,
             node: ImplItemKind::Macro(Mac {
-                path: id.into(),
+                path: what,
                 tts: vec![TokenTree::Delimited(body)],
             }),
         })
diff --git a/src/lib.rs b/src/lib.rs
index 41b5ae0..fe80c6b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,12 +2,8 @@
 #![cfg_attr(feature = "clippy", plugin(clippy))]
 
 #[cfg(feature = "printing")]
-#[macro_use]
 extern crate quote;
 
-#[cfg(feature = "pretty")]
-extern crate syntex_syntax as syntax;
-
 #[cfg(feature = "parsing")]
 extern crate unicode_xid;
 
@@ -37,14 +33,15 @@
 #[cfg(feature = "full")]
 mod expr;
 #[cfg(feature = "full")]
-pub use expr::{Arm, BindingMode, Block, BlockCheckMode, CaptureBy, Expr, ExprKind, FieldPat,
-               FieldValue, Local, MacStmtStyle, Pat, RangeLimits, Stmt};
+pub use expr::{Arm, BindingMode, Block, CaptureBy, Expr, ExprKind, FieldPat, FieldValue,
+               Local, MacStmtStyle, Pat, RangeLimits, Stmt};
 
 mod generics;
 pub use generics::{Generics, Lifetime, LifetimeDef, TraitBoundModifier, TyParam, TyParamBound,
-                   WhereBoundPredicate, WhereClause, WherePredicate, WhereRegionPredicate};
+                   WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
+                   WhereRegionPredicate};
 #[cfg(feature = "printing")]
-pub use generics::{ImplGenerics, TyGenerics};
+pub use generics::{ImplGenerics, Turbofish, TyGenerics};
 
 mod ident;
 pub use ident::Ident;
@@ -64,22 +61,18 @@
 mod lit;
 pub use lit::{FloatTy, IntTy, Lit, StrStyle};
 
-#[cfg(feature = "full")]
 mod mac;
-#[cfg(feature = "full")]
 pub use mac::{BinOpToken, DelimToken, Delimited, Mac, Token, TokenTree};
 
-mod macro_input;
-pub use macro_input::{Body, MacroInput};
+mod derive;
+pub use derive::{Body, DeriveInput};
+// Deprecated.
+#[doc(hidden)]
+pub type MacroInput = DeriveInput;
 
 mod op;
 pub use op::{BinOp, UnOp};
 
-#[cfg(feature = "expand")]
-mod registry;
-#[cfg(feature = "expand")]
-pub use registry::{CustomDerive, Expanded, Registry};
-
 #[cfg(feature = "parsing")]
 mod space;
 
@@ -97,14 +90,14 @@
 #[cfg(feature = "parsing")]
 mod parsing {
     use super::*;
-    use {generics, ident, macro_input, space, ty};
+    use {derive, generics, ident, mac, space, ty};
     use nom::IResult;
 
     #[cfg(feature = "full")]
-    use {expr, item, krate, mac};
+    use {expr, item, krate};
 
-    pub fn parse_macro_input(input: &str) -> Result<MacroInput, String> {
-        unwrap("macro input", macro_input::parsing::macro_input, input)
+    pub fn parse_derive_input(input: &str) -> Result<DeriveInput, String> {
+        unwrap("derive input", derive::parsing::derive_input, input)
     }
 
     #[cfg(feature = "full")]
@@ -139,7 +132,6 @@
         unwrap("where clause", generics::parsing::where_clause, input)
     }
 
-    #[cfg(feature = "full")]
     pub fn parse_token_trees(input: &str) -> Result<Vec<TokenTree>, String> {
         unwrap("token trees", mac::parsing::token_trees, input)
     }
@@ -148,6 +140,16 @@
         unwrap("identifier", ident::parsing::ident, input)
     }
 
+    pub fn parse_ty_param_bound(input: &str) -> Result<TyParamBound, String> {
+        unwrap("type parameter bound", generics::parsing::ty_param_bound, input)
+    }
+
+    // Deprecated.
+    #[doc(hidden)]
+    pub fn parse_macro_input(input: &str) -> Result<MacroInput, String> {
+        parse_derive_input(input)
+    }
+
     fn unwrap<T>(name: &'static str,
                  f: fn(&str) -> IResult<&str, T>,
                  input: &str)
diff --git a/src/mac.rs b/src/mac.rs
index 642f7bc..dd1447a 100644
--- a/src/mac.rs
+++ b/src/mac.rs
@@ -114,16 +114,17 @@
     use super::*;
     use Lifetime;
     use generics::parsing::lifetime;
-    use ident::parsing::{ident, word};
+    use ident::parsing::word;
     use lit::parsing::lit;
     use space::{block_comment, whitespace};
+    use ty::parsing::path;
 
     named!(pub mac -> Mac, do_parse!(
-        name: ident >>
+        what: path >>
         punct!("!") >>
         body: delimited >>
         (Mac {
-            path: name.into(),
+            path: what,
             tts: vec![TokenTree::Delimited(body)],
         })
     ));
diff --git a/src/nom.rs b/src/nom.rs
index 599a4bc..d987173 100644
--- a/src/nom.rs
+++ b/src/nom.rs
@@ -232,22 +232,12 @@
     };
 }
 
-pub fn str_chars(s: &str) -> Vec<char> {
-    // Can't do `s.chars().collect()` because it triggers a compiler bug in 1.12.0
-    // https://github.com/dtolnay/syn/issues/20
-    let mut result = Vec::new();
-    for ch in s.chars() {
-        result.push(ch);
-    }
-    result
-}
-
 macro_rules! take_until {
     ($input:expr, $substr:expr) => {{
         if $substr.len() > $input.len() {
             $crate::nom::IResult::Error
         } else {
-            let substr_vec: Vec<char> = $crate::nom::str_chars($substr);
+            let substr_vec: Vec<char> = $substr.chars().collect();
             let mut window: Vec<char> = vec![];
             let mut offset = $input.len();
             let mut parsed = false;
diff --git a/src/registry.rs b/src/registry.rs
deleted file mode 100644
index 24e1c6b..0000000
--- a/src/registry.rs
+++ /dev/null
@@ -1,392 +0,0 @@
-use super::{Attribute, AttrStyle, Body, Crate, Ident, Item, ItemKind, MacroInput, MetaItem,
-            NestedMetaItem};
-use quote::Tokens;
-
-use std::collections::BTreeMap as Map;
-use std::fs::File;
-use std::io::{Read, Write};
-use std::path::Path;
-
-/// Implementation of a custom derive. Custom derives take a struct or enum and
-/// expand it into zero or more items, typically `impl` items.
-pub trait CustomDerive {
-    /// Expand the given struct or enum. If this custom derive modifies the
-    /// input item or preserves it unmodified, it must be returned back in the
-    /// `original` field of Expanded. The custom derive may discard the input
-    /// item by setting `original` to None.
-    fn expand(&self, input: MacroInput) -> Result<Expanded, String>;
-}
-
-/// Produced by expanding a custom derive.
-pub struct Expanded {
-    /// The items (typically `impl` items) constructed by the custom derive.
-    pub new_items: Vec<Item>,
-    /// The input to the custom derive, whether modified or unmodified. If the
-    /// custom derive discards the input item it may do so by setting `original`
-    /// to None.
-    pub original: Option<MacroInput>,
-}
-
-/// Registry of custom derives. Callers add custom derives to a registry, then
-/// use the registry to expand those derives in a source file.
-#[derive(Default)]
-pub struct Registry<'a> {
-    derives: Map<String, Box<CustomDerive + 'a>>,
-}
-
-impl<T> CustomDerive for T
-    where T: Fn(MacroInput) -> Result<Expanded, String>
-{
-    fn expand(&self, input: MacroInput) -> Result<Expanded, String> {
-        self(input)
-    }
-}
-
-impl<'a> Registry<'a> {
-    pub fn new() -> Self {
-        Default::default()
-    }
-
-    /// Register a custom derive. A `fn(MacroInput) -> Result<Expanded, String>`
-    /// may be used as a custom derive.
-    ///
-    /// ```ignore
-    /// registry.add_derive("Serialize", expand_serialize);
-    /// ```
-    pub fn add_derive<T>(&mut self, name: &str, derive: T)
-        where T: CustomDerive + 'a
-    {
-        self.derives.insert(name.into(), Box::new(derive));
-    }
-
-    /// Read Rust source code from the `src` file, expand the custom derives
-    /// that have been registered, and write the result to the `dst` file.
-    pub fn expand_file<S, D>(&self, src: S, dst: D) -> Result<(), String>
-        where S: AsRef<Path>,
-              D: AsRef<Path>
-    {
-        // Open the src file
-        let mut src = match File::open(src) {
-            Ok(open) => open,
-            Err(err) => return Err(err.to_string()),
-        };
-
-        // Read the contents of the src file to a String
-        let mut content = String::new();
-        if let Err(err) = src.read_to_string(&mut content) {
-            return Err(err.to_string());
-        }
-
-        // Parse the contents
-        let krate = try!(super::parse_crate(&content));
-
-        // Expand
-        let expanded = try!(expand_crate(self, krate));
-
-        // Print the expanded code to a String
-        let out = try!(pretty(quote!(#expanded)));
-
-        // Create or truncate the dst file, opening in write-only mode
-        let mut dst = match File::create(dst) {
-            Ok(create) => create,
-            Err(err) => return Err(err.to_string()),
-        };
-
-        // Write expanded code to the dst file
-        if let Err(err) = dst.write_all(out.as_bytes()) {
-            return Err(err.to_string());
-        }
-
-        Ok(())
-    }
-}
-
-fn expand_crate(reg: &Registry, krate: Crate) -> Result<Crate, String> {
-    let mut items = Vec::new();
-    for item in krate.items {
-        try!(expand_item(reg, item, Vec::new(), &mut items));
-    }
-    Ok(Crate { items: items, ..krate })
-}
-
-fn expand_item(reg: &Registry,
-               mut item: Item,
-               cfg: Vec<NestedMetaItem>,
-               out: &mut Vec<Item>)
-               -> Result<(), String> {
-    let (body, generics) = match item.node {
-        ItemKind::Enum(variants, generics) => (Body::Enum(variants), generics),
-        ItemKind::Struct(variant_data, generics) => (Body::Struct(variant_data), generics),
-        _ => {
-            // Custom derives cannot apply to this item, preserve it unmodified
-            item.attrs.extend(combine_cfgs(cfg));
-            out.push(item);
-            return Ok(());
-        }
-    };
-    let macro_input = MacroInput {
-        ident: item.ident,
-        vis: item.vis,
-        attrs: item.attrs,
-        generics: generics,
-        body: body,
-    };
-    expand_macro_input(reg, macro_input, cfg, out)
-}
-
-fn expand_macro_input(reg: &Registry,
-                      mut input: MacroInput,
-                      inherited_cfg: Vec<NestedMetaItem>,
-                      out: &mut Vec<Item>)
-                      -> Result<(), String> {
-    let mut derives = Vec::new();
-    let mut all_cfg = inherited_cfg;
-
-    // Find custom derives on this item, removing them from the input
-    input.attrs = input.attrs
-        .into_iter()
-        .flat_map(|attr| {
-            let (new_derives, cfg, attr) = parse_attr(reg, attr);
-            derives.extend(new_derives);
-            all_cfg.extend(cfg);
-            attr
-        })
-        .collect();
-
-    // Expand each custom derive
-    for derive in derives {
-        let expanded = try!(reg.derives[derive.name.as_ref()].expand(input));
-
-        for new_item in expanded.new_items {
-            let mut extended_cfg = all_cfg.clone();
-            extended_cfg.extend(derive.cfg.clone());
-            try!(expand_item(reg, new_item, extended_cfg, out));
-        }
-
-        input = match expanded.original {
-            Some(input) => input,
-            None => return Ok(()),
-        };
-    }
-
-    input.attrs.extend(combine_cfgs(all_cfg));
-    out.push(input.into());
-    Ok(())
-}
-
-struct Derive {
-    name: Ident,
-    /// If the custom derive was behind a cfg_attr
-    cfg: Option<NestedMetaItem>,
-}
-
-/// Pull custom derives and cfgs out of the given Attribute.
-fn parse_attr(reg: &Registry,
-              attr: Attribute)
-              -> (Vec<Derive>, Vec<NestedMetaItem>, Option<Attribute>) {
-    if attr.style != AttrStyle::Outer || attr.is_sugared_doc {
-        return (Vec::new(), Vec::new(), Some(attr));
-    }
-
-    let (name, nested) = match attr.value {
-        MetaItem::List(name, nested) => (name, nested),
-        _ => return (Vec::new(), Vec::new(), Some(attr)),
-    };
-
-    match name.as_ref() {
-        "derive" => {
-            let (derives, attr) = parse_derive_attr(reg, nested);
-            let derives = derives.into_iter()
-                .map(|d| {
-                    Derive {
-                        name: d,
-                        cfg: None,
-                    }
-                })
-                .collect();
-            (derives, Vec::new(), attr)
-        }
-        "cfg_attr" => {
-            let (derives, attr) = parse_cfg_attr(reg, nested);
-            (derives, Vec::new(), attr)
-        }
-        "cfg" => (Vec::new(), nested, None),
-        _ => {
-            // Rebuild the original attribute because it was destructured above
-            let attr = Attribute {
-                style: AttrStyle::Outer,
-                value: MetaItem::List(name, nested),
-                is_sugared_doc: false,
-            };
-            (Vec::new(), Vec::new(), Some(attr))
-        }
-    }
-}
-
-/// Assuming the given nested meta-items came from a #[derive(...)] attribute,
-/// pull out the ones that are custom derives.
-fn parse_derive_attr(reg: &Registry,
-                     nested: Vec<NestedMetaItem>)
-                     -> (Vec<Ident>, Option<Attribute>) {
-    let mut derives = Vec::new();
-
-    let remaining: Vec<_> = nested.into_iter()
-        .flat_map(|meta| {
-            let word = match meta {
-                NestedMetaItem::MetaItem(MetaItem::Word(word)) => word,
-                _ => return Some(meta),
-            };
-            if reg.derives.contains_key(word.as_ref()) {
-                derives.push(word);
-                None
-            } else {
-                Some(NestedMetaItem::MetaItem(MetaItem::Word(word)))
-            }
-        })
-        .collect();
-
-    let attr = if remaining.is_empty() {
-        // Elide an empty #[derive()]
-        None
-    } else {
-        Some(Attribute {
-            style: AttrStyle::Outer,
-            value: MetaItem::List("derive".into(), remaining),
-            is_sugared_doc: false,
-        })
-    };
-
-    (derives, attr)
-}
-
-/// Assuming the given nested meta-items came from a #[cfg_attr(...)] attribute,
-/// pull out any custom derives contained within.
-fn parse_cfg_attr(reg: &Registry, nested: Vec<NestedMetaItem>) -> (Vec<Derive>, Option<Attribute>) {
-    if nested.len() != 2 {
-        let attr = Attribute {
-            style: AttrStyle::Outer,
-            value: MetaItem::List("cfg_attr".into(), nested),
-            is_sugared_doc: false,
-        };
-        return (Vec::new(), Some(attr));
-    }
-
-    let mut iter = nested.into_iter();
-    let cfg = iter.next().unwrap();
-    let arg = iter.next().unwrap();
-
-    let (name, nested) = match arg {
-        NestedMetaItem::MetaItem(MetaItem::List(name, nested)) => (name, nested),
-        _ => {
-            let attr = Attribute {
-                style: AttrStyle::Outer,
-                value: MetaItem::List("cfg_attr".into(), vec![cfg, arg]),
-                is_sugared_doc: false,
-            };
-            return (Vec::new(), Some(attr));
-        }
-    };
-
-    if name == "derive" {
-        let (derives, attr) = parse_derive_attr(reg, nested);
-        let derives = derives.into_iter()
-            .map(|d| {
-                Derive {
-                    name: d,
-                    cfg: Some(cfg.clone()),
-                }
-            })
-            .collect();
-        let attr = attr.map(|attr| {
-            Attribute {
-                style: AttrStyle::Outer,
-                value: MetaItem::List("cfg_attr".into(),
-                                      vec![cfg, NestedMetaItem::MetaItem(attr.value)]),
-                is_sugared_doc: false,
-            }
-        });
-        (derives, attr)
-    } else {
-        let attr = Attribute {
-            style: AttrStyle::Outer,
-            value:
-                MetaItem::List("cfg_attr".into(),
-                               vec![cfg, NestedMetaItem::MetaItem(MetaItem::List(name, nested))]),
-            is_sugared_doc: false,
-        };
-        (Vec::new(), Some(attr))
-    }
-}
-
-/// Combine a list of cfg expressions into an attribute like `#[cfg(a)]` or
-/// `#[cfg(all(a, b, c))]`, or nothing if there are no cfg expressions.
-fn combine_cfgs(cfg: Vec<NestedMetaItem>) -> Option<Attribute> {
-    // Flatten `all` cfgs so we don't nest `all` inside of `all`.
-    let cfg: Vec<_> = cfg.into_iter()
-        .flat_map(|cfg| {
-            let (name, nested) = match cfg {
-                NestedMetaItem::MetaItem(MetaItem::List(name, nested)) => (name, nested),
-                _ => return vec![cfg],
-            };
-            if name == "all" {
-                nested
-            } else {
-                vec![NestedMetaItem::MetaItem(MetaItem::List(name, nested))]
-            }
-        })
-        .collect();
-
-    let value = match cfg.len() {
-        0 => return None,
-        1 => cfg,
-        _ => vec![NestedMetaItem::MetaItem(MetaItem::List("all".into(), cfg))],
-    };
-
-    Some(Attribute {
-        style: AttrStyle::Outer,
-        value: MetaItem::List("cfg".into(), value),
-        is_sugared_doc: false,
-    })
-}
-
-#[cfg(not(feature = "pretty"))]
-fn pretty(tokens: Tokens) -> Result<String, String> {
-    Ok(tokens.to_string())
-}
-
-#[cfg(feature = "pretty")]
-fn pretty(tokens: Tokens) -> Result<String, String> {
-    use syntax::parse::{self, ParseSess};
-    use syntax::print::pprust;
-
-    let name = "syn".to_string();
-    let source = tokens.to_string();
-    let sess = ParseSess::new();
-    let krate = match parse::parse_crate_from_source_str(name, source, &sess) {
-        Ok(krate) => krate,
-        Err(mut err) => {
-            err.emit();
-            return Err("pretty printer failed to parse expanded code".into());
-        }
-    };
-
-    if sess.span_diagnostic.has_errors() {
-        return Err("pretty printer failed to parse expanded code".into());
-    }
-
-    let mut reader = &tokens.to_string().into_bytes()[..];
-    let mut writer = Vec::new();
-    let ann = pprust::NoAnn;
-
-    try!(pprust::print_crate(
-        sess.codemap(),
-        &sess.span_diagnostic,
-        &krate,
-        "".to_string(),
-        &mut reader,
-        Box::new(&mut writer),
-        &ann,
-        false).map_err(|err| err.to_string()));
-
-    String::from_utf8(writer).map_err(|err| err.to_string())
-}
diff --git a/src/ty.rs b/src/ty.rs
index e10901c..4031fc3 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -22,17 +22,19 @@
     ///
     /// Type parameters are stored in the Path itself
     Path(Option<QSelf>, Path),
-    /// Something like `A+B`. Note that `B` must always be a path.
-    ObjectSum(Box<Ty>, Vec<TyParamBound>),
-    /// A type like `for<'a> Foo<&'a Bar>`
-    PolyTraitRef(Vec<TyParamBound>),
-    /// An `impl TraitA+TraitB` type.
+    /// A trait object type `Bound1 + Bound2 + Bound3`
+    /// where `Bound` is a trait or a lifetime.
+    TraitObject(Vec<TyParamBound>),
+    /// An `impl Bound1 + Bound2 + Bound3` type
+    /// where `Bound` is a trait or a lifetime.
     ImplTrait(Vec<TyParamBound>),
     /// No-op; kept solely so that we can pretty-print faithfully
     Paren(Box<Ty>),
     /// TyKind::Infer means the type should be inferred instead of it having been
     /// specified. This can appear anywhere in a type.
     Infer,
+    /// A macro in the type position.
+    Mac(Mac),
 }
 
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
@@ -55,7 +57,10 @@
 /// E.g. `std::cmp::PartialEq`
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
 pub struct Path {
+    /// A `::foo` path, is relative to the crate root rather than current
+    /// module (like paths in an import).
     pub global: bool,
+    /// The segments in the path: the things separated by `::`.
     pub segments: Vec<PathSegment>,
 }
 
@@ -75,7 +80,13 @@
 /// E.g. `std`, `String` or `Box<T>`
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
 pub struct PathSegment {
+    /// The identifier portion of this path segment.
     pub ident: Ident,
+    /// Type/lifetime parameters attached to this path. They come in
+    /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
+    /// this is more than just simple syntactic sugar; the use of
+    /// parens affects the region binding rules, so we preserve the
+    /// distinction.
     pub parameters: PathParameters,
 }
 
@@ -220,6 +231,7 @@
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
+    use {TyParamBound, TraitBoundModifier};
     #[cfg(feature = "full")]
     use ConstExpr;
     use constant::parsing::const_expr;
@@ -228,11 +240,14 @@
     use generics::parsing::{lifetime, lifetime_def, ty_param_bound, bound_lifetimes};
     use ident::parsing::ident;
     use lit::parsing::quoted_string;
+    use mac::parsing::mac;
     use std::str;
 
     named!(pub ty -> Ty, alt!(
         ty_paren // must be before ty_tup
         |
+        ty_mac // must be before ty_path
+        |
         ty_path // must be before ty_poly_trait_ref
         |
         ty_vec
@@ -254,6 +269,8 @@
         ty_impl_trait
     ));
 
+    named!(ty_mac -> Ty, map!(mac, Ty::Mac));
+
     named!(ty_vec -> Ty, do_parse!(
         punct!("[") >>
         elem: ty >>
@@ -363,11 +380,18 @@
             if let Some(Some(parenthesized)) = parenthesized {
                 path.segments.last_mut().unwrap().parameters = parenthesized;
             }
-            let path = Ty::Path(qself, path);
             if bounds.is_empty() {
-                path
+                Ty::Path(qself, path)
             } else {
-                Ty::ObjectSum(Box::new(path), bounds)
+                let path = TyParamBound::Trait(
+                    PolyTraitRef {
+                        bound_lifetimes: Vec::new(),
+                        trait_ref: path,
+                    },
+                    TraitBoundModifier::None,
+                );
+                let bounds = Some(path).into_iter().chain(bounds).collect();
+                Ty::TraitObject(bounds)
             }
         })
     ));
@@ -423,7 +447,7 @@
 
     named!(ty_poly_trait_ref -> Ty, map!(
         separated_nonempty_list!(punct!("+"), ty_param_bound),
-        Ty::PolyTraitRef
+        Ty::TraitObject
     ));
 
     named!(ty_impl_trait -> Ty, do_parse!(
@@ -626,14 +650,7 @@
                         segment.to_tokens(tokens);
                     }
                 }
-                Ty::ObjectSum(ref ty, ref bounds) => {
-                    ty.to_tokens(tokens);
-                    for bound in bounds {
-                        tokens.append("+");
-                        bound.to_tokens(tokens);
-                    }
-                }
-                Ty::PolyTraitRef(ref bounds) => {
+                Ty::TraitObject(ref bounds) => {
                     tokens.append_separated(bounds, "+");
                 }
                 Ty::ImplTrait(ref bounds) => {
@@ -648,6 +665,7 @@
                 Ty::Infer => {
                     tokens.append("_");
                 }
+                Ty::Mac(ref mac) => mac.to_tokens(tokens),
             }
         }
     }
diff --git a/src/visit.rs b/src/visit.rs
index e23f3f0..a5d4f41 100644
--- a/src/visit.rs
+++ b/src/visit.rs
@@ -28,8 +28,8 @@
 /// new default implementation gets introduced.)
 pub trait Visitor: Sized {
     fn visit_ident(&mut self, _ident: &Ident) {}
-    fn visit_macro_input(&mut self, macro_input: &MacroInput) {
-        walk_macro_input(self, macro_input)
+    fn visit_derive_input(&mut self, derive_input: &DeriveInput) {
+        walk_derive_input(self, derive_input)
     }
     fn visit_ty(&mut self, ty: &Ty) {
         walk_ty(self, ty)
@@ -76,20 +76,67 @@
         walk_const_expr(self, expr)
     }
     fn visit_lit(&mut self, _lit: &Lit) {}
+
+    fn visit_mac(&mut self, mac: &Mac) {
+        walk_mac(self, mac);
+    }
+
+    #[cfg(feature = "full")]
+    fn visit_crate(&mut self, _crate: &Crate) {
+        walk_crate(self, _crate);
+    }
+    #[cfg(feature = "full")]
+    fn visit_item(&mut self, item: &Item) {
+        walk_item(self, item);
+    }
+    #[cfg(feature = "full")]
+    fn visit_expr(&mut self, expr: &Expr) {
+        walk_expr(self, expr);
+    }
+    #[cfg(feature = "full")]
+    fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
+        walk_foreign_item(self, foreign_item);
+    }
+    #[cfg(feature = "full")]
+    fn visit_pat(&mut self, pat: &Pat) {
+        walk_pat(self, pat);
+    }
+    #[cfg(feature = "full")]
+    fn visit_fn_decl(&mut self, fn_decl: &FnDecl) {
+        walk_fn_decl(self, fn_decl);
+    }
+    #[cfg(feature = "full")]
+    fn visit_trait_item(&mut self, trait_item: &TraitItem) {
+        walk_trait_item(self, trait_item);
+    }
+    #[cfg(feature = "full")]
+    fn visit_impl_item(&mut self, impl_item: &ImplItem) {
+        walk_impl_item(self, impl_item);
+    }
+    #[cfg(feature = "full")]
+    fn visit_method_sig(&mut self, method_sig: &MethodSig) {
+        walk_method_sig(self, method_sig);
+    }
+    #[cfg(feature = "full")]
+    fn visit_stmt(&mut self, stmt: &Stmt) {
+        walk_stmt(self, stmt);
+    }
+    #[cfg(feature = "full")]
+    fn visit_local(&mut self, local: &Local) {
+        walk_local(self, local);
+    }
+    #[cfg(feature = "full")]
+    fn visit_view_path(&mut self, view_path: &ViewPath) {
+        walk_view_path(self, view_path);
+    }
 }
 
-#[macro_export]
 macro_rules! walk_list {
-    ($visitor: expr, $method: ident, $list: expr) => {
+    ($visitor:expr, $method:ident, $list:expr $(, $extra_args:expr)*) => {
         for elem in $list {
-            $visitor.$method(elem)
+            $visitor.$method(elem $(, $extra_args)*)
         }
     };
-    ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => {
-        for elem in $list {
-            $visitor.$method(elem, $($extra_args,)*)
-        }
-    }
 }
 
 pub fn walk_opt_ident<V: Visitor>(visitor: &mut V, opt_ident: &Option<Ident>) {
@@ -110,18 +157,18 @@
     visitor.visit_path(&trait_ref.trait_ref);
 }
 
-pub fn walk_macro_input<V: Visitor>(visitor: &mut V, macro_input: &MacroInput) {
-    visitor.visit_ident(&macro_input.ident);
-    visitor.visit_generics(&macro_input.generics);
-    match macro_input.body {
+pub fn walk_derive_input<V: Visitor>(visitor: &mut V, derive_input: &DeriveInput) {
+    visitor.visit_ident(&derive_input.ident);
+    visitor.visit_generics(&derive_input.generics);
+    match derive_input.body {
         Body::Enum(ref variants) => {
-            walk_list!(visitor, visit_variant, variants, &macro_input.generics);
+            walk_list!(visitor, visit_variant, variants, &derive_input.generics);
         }
         Body::Struct(ref variant_data) => {
-            visitor.visit_variant_data(variant_data, &macro_input.ident, &macro_input.generics);
+            visitor.visit_variant_data(variant_data, &derive_input.ident, &derive_input.generics);
         }
     }
-    walk_list!(visitor, visit_attribute, &macro_input.attrs);
+    walk_list!(visitor, visit_attribute, &derive_input.attrs);
 }
 
 pub fn walk_variant<V>(visitor: &mut V, variant: &Variant, generics: &Generics)
@@ -159,18 +206,17 @@
             }
             visitor.visit_path(path);
         }
-        Ty::ObjectSum(ref inner, ref bounds) => {
-            visitor.visit_ty(inner);
-            walk_list!(visitor, visit_ty_param_bound, bounds);
-        }
         Ty::Array(ref inner, ref len) => {
             visitor.visit_ty(inner);
             visitor.visit_const_expr(len);
         }
-        Ty::PolyTraitRef(ref bounds) |
+        Ty::TraitObject(ref bounds) |
         Ty::ImplTrait(ref bounds) => {
             walk_list!(visitor, visit_ty_param_bound, bounds);
         }
+        Ty::Mac(ref mac) => {
+            visitor.visit_mac(mac);
+        }
     }
 }
 
@@ -240,6 +286,12 @@
                 visitor.visit_lifetime(lifetime);
                 walk_list!(visitor, visit_lifetime, bounds);
             }
+            WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty,
+                                                           ref rhs_ty,
+                                                           .. }) => {
+                visitor.visit_ty(lhs_ty);
+                visitor.visit_ty(rhs_ty);
+            }
         }
     }
 }
@@ -290,6 +342,461 @@
         ConstExpr::Paren(ref expr) => {
             visitor.visit_const_expr(expr);
         }
-        ConstExpr::Other(_) => {}
+        ConstExpr::Other(ref other) => {
+            #[cfg(feature = "full")]
+            fn walk_other<V: Visitor>(visitor: &mut V, other: &Expr) {
+                visitor.visit_expr(other);
+            }
+            #[cfg(not(feature = "full"))]
+            fn walk_other<V: Visitor>(_: &mut V, _: &super::constant::Other) {}
+            walk_other(visitor, other);
+        }
+    }
+}
+
+pub fn walk_mac<V: Visitor>(visitor: &mut V, mac: &Mac) {
+    visitor.visit_path(&mac.path);
+}
+
+#[cfg(feature = "full")]
+pub fn walk_crate<V: Visitor>(visitor: &mut V, _crate: &Crate) {
+    walk_list!(visitor, visit_attribute, &_crate.attrs);
+    walk_list!(visitor, visit_item, &_crate.items);
+}
+
+#[cfg(feature = "full")]
+pub fn walk_item<V: Visitor>(visitor: &mut V, item: &Item) {
+    visitor.visit_ident(&item.ident);
+    walk_list!(visitor, visit_attribute, &item.attrs);
+    match item.node {
+        ItemKind::ExternCrate(ref ident) => {
+            walk_opt_ident(visitor, ident);
+        }
+        ItemKind::Use(ref view_path) => {
+            visitor.visit_view_path(view_path);
+        }
+        ItemKind::Static(ref ty, _, ref expr) => {
+            visitor.visit_ty(ty);
+            visitor.visit_expr(expr);
+        }
+        ItemKind::Const(ref ty, ref expr) => {
+            visitor.visit_ty(ty);
+            visitor.visit_expr(expr);
+        }
+        ItemKind::Fn(ref decl, _, _, _, ref generics, ref body) => {
+            visitor.visit_fn_decl(decl);
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_stmt, &body.stmts);
+        }
+        ItemKind::Mod(ref maybe_items) => {
+            if let Some(ref items) = *maybe_items {
+                walk_list!(visitor, visit_item, items);
+            }
+        }
+        ItemKind::ForeignMod(ref foreign_mod) => {
+            walk_list!(visitor, visit_foreign_item, &foreign_mod.items);
+        }
+        ItemKind::Ty(ref ty, ref generics) => {
+            visitor.visit_ty(ty);
+            visitor.visit_generics(generics);
+        }
+        ItemKind::Enum(ref variant, ref generics) => {
+            walk_list!(visitor, visit_variant, variant, generics);
+        }
+        ItemKind::Struct(ref variant_data, ref generics) => {
+            visitor.visit_variant_data(variant_data, &item.ident, generics);
+        }
+        ItemKind::Union(ref variant_data, ref generics) => {
+            visitor.visit_variant_data(variant_data, &item.ident, generics);
+        }
+        ItemKind::Trait(_, ref generics, ref bounds, ref trait_items) => {
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_trait_item, trait_items);
+        }
+        ItemKind::DefaultImpl(_, ref path) => {
+            visitor.visit_path(path);
+        }
+        ItemKind::Impl(_, _, ref generics, ref maybe_path, ref ty, ref impl_items) => {
+            visitor.visit_generics(generics);
+            if let Some(ref path) = *maybe_path {
+                visitor.visit_path(path);
+            }
+            visitor.visit_ty(ty);
+            walk_list!(visitor, visit_impl_item, impl_items);
+        }
+        ItemKind::Mac(ref mac) => {
+            visitor.visit_mac(mac)
+        }
+    }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr) {
+    walk_list!(visitor, visit_attribute, &expr.attrs);
+    match expr.node {
+        ExprKind::Box(ref expr) => {
+            visitor.visit_expr(expr);
+        }
+        ExprKind::InPlace(ref place, ref value) => {
+            visitor.visit_expr(place);
+            visitor.visit_expr(value);
+        }
+        ExprKind::Array(ref exprs) => {
+            walk_list!(visitor, visit_expr, exprs);
+        }
+        ExprKind::Call(ref callee, ref args) => {
+            visitor.visit_expr(callee);
+            walk_list!(visitor, visit_expr, args);
+        }
+        ExprKind::MethodCall(ref name, ref ty_args, ref args) => {
+            visitor.visit_ident(name);
+            walk_list!(visitor, visit_ty, ty_args);
+            walk_list!(visitor, visit_expr, args);
+        }
+        ExprKind::Tup(ref exprs) => {
+            walk_list!(visitor, visit_expr, exprs);
+        }
+        ExprKind::Binary(_, ref lhs, ref rhs) => {
+            visitor.visit_expr(lhs);
+            visitor.visit_expr(rhs);
+        }
+        ExprKind::Unary(_, ref operand) => {
+            visitor.visit_expr(operand);
+        }
+        ExprKind::Lit(ref lit) => {
+            visitor.visit_lit(lit);
+        }
+        ExprKind::Cast(ref expr, ref ty) => {
+            visitor.visit_expr(expr);
+            visitor.visit_ty(ty);
+        }
+        ExprKind::Type(ref expr, ref ty) => {
+            visitor.visit_expr(expr);
+            visitor.visit_ty(ty);
+        }
+        ExprKind::If(ref cond, ref cons, ref maybe_alt) => {
+            visitor.visit_expr(cond);
+            walk_list!(visitor, visit_stmt, &cons.stmts);
+            if let Some(ref alt) = *maybe_alt {
+                visitor.visit_expr(alt);
+            }
+        }
+        ExprKind::IfLet(ref pat, ref cond, ref cons, ref maybe_alt) => {
+            visitor.visit_pat(pat);
+            visitor.visit_expr(cond);
+            walk_list!(visitor, visit_stmt, &cons.stmts);
+            if let Some(ref alt) = *maybe_alt {
+                visitor.visit_expr(alt);
+            }
+        }
+        ExprKind::While(ref cond, ref body, ref label) => {
+            visitor.visit_expr(cond);
+            walk_list!(visitor, visit_stmt, &body.stmts);
+            walk_opt_ident(visitor, label);
+        }
+        ExprKind::WhileLet(ref pat, ref cond, ref body, ref label) => {
+            visitor.visit_pat(pat);
+            visitor.visit_expr(cond);
+            walk_list!(visitor, visit_stmt, &body.stmts);
+            walk_opt_ident(visitor, label);
+        }
+        ExprKind::ForLoop(ref pat, ref expr, ref body, ref label) => {
+            visitor.visit_pat(pat);
+            visitor.visit_expr(expr);
+            walk_list!(visitor, visit_stmt, &body.stmts);
+            walk_opt_ident(visitor, label);
+        }
+        ExprKind::Loop(ref body, ref label) => {
+            walk_list!(visitor, visit_stmt, &body.stmts);
+            walk_opt_ident(visitor, label);
+        }
+        ExprKind::Match(ref expr, ref arms) => {
+            visitor.visit_expr(expr);
+            for &Arm{ref attrs, ref pats, ref guard, ref body} in arms {
+                walk_list!(visitor, visit_attribute, attrs);
+                walk_list!(visitor, visit_pat, pats);
+                if let Some(ref guard) = *guard {
+                    visitor.visit_expr(guard);
+                }
+                visitor.visit_expr(body);
+            }
+        }
+        ExprKind::Closure(_, ref decl, ref expr) => {
+            visitor.visit_fn_decl(decl);
+            visitor.visit_expr(expr);
+        }
+        ExprKind::Block(_, ref block) => {
+            walk_list!(visitor, visit_stmt, &block.stmts);
+        }
+        ExprKind::Assign(ref lhs, ref rhs) => {
+            visitor.visit_expr(lhs);
+            visitor.visit_expr(rhs);
+        }
+        ExprKind::AssignOp(_, ref lhs, ref rhs) => {
+            visitor.visit_expr(lhs);
+            visitor.visit_expr(rhs);
+        }
+        ExprKind::Field(ref obj, ref field) => {
+            visitor.visit_expr(obj);
+            visitor.visit_ident(field);
+        }
+        ExprKind::TupField(ref obj, _) => {
+            visitor.visit_expr(obj);
+        }
+        ExprKind::Index(ref obj, ref idx) => {
+            visitor.visit_expr(obj);
+            visitor.visit_expr(idx);
+        }
+        ExprKind::Range(ref maybe_start, ref maybe_end, _) => {
+            if let Some(ref start) = *maybe_start {
+                visitor.visit_expr(start);
+            }
+            if let Some(ref end) = *maybe_end {
+                visitor.visit_expr(end);
+            }
+        }
+        ExprKind::Path(ref maybe_qself, ref path) => {
+            if let Some(ref qself) = *maybe_qself {
+                visitor.visit_ty(&qself.ty);
+            }
+            visitor.visit_path(path);
+        }
+        ExprKind::AddrOf(_, ref expr) => {
+            visitor.visit_expr(expr);
+        }
+        ExprKind::Break(ref maybe_label, ref maybe_expr) => {
+            walk_opt_ident(visitor, maybe_label);
+            if let Some(ref expr) = *maybe_expr {
+                visitor.visit_expr(expr);
+            }
+        }
+        ExprKind::Continue(ref maybe_label) => {
+            walk_opt_ident(visitor, maybe_label);
+        }
+        ExprKind::Ret(ref maybe_expr) => {
+            if let Some(ref expr) = *maybe_expr {
+                visitor.visit_expr(expr);
+            }
+        }
+        ExprKind::Mac(ref mac) => {
+            visitor.visit_mac(mac);
+        }
+        ExprKind::Struct(ref path, ref fields, ref maybe_base) => {
+            visitor.visit_path(path);
+            for &FieldValue{ref ident, ref expr, ..} in fields {
+                visitor.visit_ident(ident);
+                visitor.visit_expr(expr);
+            }
+            if let Some(ref base) = *maybe_base {
+                visitor.visit_expr(base);
+            }
+        }
+        ExprKind::Repeat(ref value, ref times) => {
+            visitor.visit_expr(value);
+            visitor.visit_expr(times);
+        }
+        ExprKind::Paren(ref expr) => {
+            visitor.visit_expr(expr);
+        }
+        ExprKind::Try(ref expr) => {
+            visitor.visit_expr(expr);
+        }
+    }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_foreign_item<V: Visitor>(visitor: &mut V, foreign_item: &ForeignItem) {
+    visitor.visit_ident(&foreign_item.ident);
+    walk_list!(visitor, visit_attribute, &foreign_item.attrs);
+    match foreign_item.node {
+        ForeignItemKind::Fn(ref decl, ref generics) => {
+            visitor.visit_fn_decl(decl);
+            visitor.visit_generics(generics);
+        }
+        ForeignItemKind::Static(ref ty, _) => {
+            visitor.visit_ty(ty);
+        }
+    }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_pat<V: Visitor>(visitor: &mut V, pat: &Pat) {
+    match *pat {
+        Pat::Wild => {}
+        Pat::Ident(_, ref ident, ref maybe_pat) => {
+            visitor.visit_ident(ident);
+            if let Some(ref pat) = *maybe_pat {
+                visitor.visit_pat(pat);
+            }
+        }
+        Pat::Struct(ref path, ref field_pats, _) => {
+            visitor.visit_path(path);
+            for &FieldPat{ref ident, ref pat, ..} in field_pats {
+                visitor.visit_ident(ident);
+                visitor.visit_pat(pat);
+            }
+        }
+        Pat::TupleStruct(ref path, ref pats, _) => {
+            visitor.visit_path(path);
+            walk_list!(visitor, visit_pat, pats);
+        }
+        Pat::Path(ref maybe_qself, ref path) => {
+            if let Some(ref qself) = *maybe_qself {
+                visitor.visit_ty(&qself.ty);
+            }
+            visitor.visit_path(path);
+        }
+        Pat::Tuple(ref pats, _) => {
+            walk_list!(visitor, visit_pat, pats);
+        }
+        Pat::Box(ref pat) |
+        Pat::Ref(ref pat, _) => {
+            visitor.visit_pat(pat);
+        }
+        Pat::Lit(ref expr) => {
+            visitor.visit_expr(expr);
+        }
+        Pat::Range(ref start, ref end) => {
+            visitor.visit_expr(start);
+            visitor.visit_expr(end);
+        }
+        Pat::Slice(ref start, ref maybe_mid, ref end) => {
+            walk_list!(visitor, visit_pat, start);
+            if let Some(ref mid) = *maybe_mid {
+                visitor.visit_pat(mid);
+            }
+            walk_list!(visitor, visit_pat, end);
+        }
+        Pat::Mac(ref mac) => {
+            visitor.visit_mac(mac);
+        }
+    }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_fn_decl<V: Visitor>(visitor: &mut V, fn_decl: &FnDecl) {
+    for input in &fn_decl.inputs {
+        match *input {
+            FnArg::SelfRef(_, _) | FnArg::SelfValue(_) => {}
+            FnArg::Captured(ref pat, ref ty) => {
+                visitor.visit_pat(pat);
+                visitor.visit_ty(ty);
+            }
+            FnArg::Ignored(ref ty) => {
+                visitor.visit_ty(ty);
+            }
+        }
+    }
+    visitor.visit_fn_ret_ty(&fn_decl.output);
+}
+
+#[cfg(feature = "full")]
+pub fn walk_trait_item<V: Visitor>(visitor: &mut V, trait_item: &TraitItem) {
+    visitor.visit_ident(&trait_item.ident);
+    walk_list!(visitor, visit_attribute, &trait_item.attrs);
+    match trait_item.node {
+        TraitItemKind::Const(ref ty, ref maybe_expr) => {
+            visitor.visit_ty(ty);
+            if let Some(ref expr) = *maybe_expr {
+                visitor.visit_expr(expr);
+            }
+        }
+        TraitItemKind::Method(ref method_sig, ref maybe_block) => {
+            visitor.visit_method_sig(method_sig);
+            if let Some(ref block) = *maybe_block {
+                walk_list!(visitor, visit_stmt, &block.stmts);
+            }
+        }
+        TraitItemKind::Type(ref bounds, ref maybe_ty) => {
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+            if let Some(ref ty) = *maybe_ty {
+                visitor.visit_ty(ty);
+            }
+        }
+        TraitItemKind::Macro(ref mac) => {
+            visitor.visit_mac(mac);
+        }
+    }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_impl_item<V: Visitor>(visitor: &mut V, impl_item: &ImplItem) {
+    visitor.visit_ident(&impl_item.ident);
+    walk_list!(visitor, visit_attribute, &impl_item.attrs);
+    match impl_item.node {
+        ImplItemKind::Const(ref ty, ref expr) => {
+            visitor.visit_ty(ty);
+            visitor.visit_expr(expr);
+        }
+        ImplItemKind::Method(ref method_sig, ref block) => {
+            visitor.visit_method_sig(method_sig);
+            walk_list!(visitor, visit_stmt, &block.stmts);
+        }
+        ImplItemKind::Type(ref ty) => {
+            visitor.visit_ty(ty);
+        }
+        ImplItemKind::Macro(ref mac) => {
+            visitor.visit_mac(mac);
+        }
+    }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_method_sig<V: Visitor>(visitor: &mut V, method_sig: &MethodSig) {
+    visitor.visit_fn_decl(&method_sig.decl);
+    visitor.visit_generics(&method_sig.generics);
+}
+
+#[cfg(feature = "full")]
+pub fn walk_stmt<V: Visitor>(visitor: &mut V, stmt: &Stmt) {
+    match *stmt {
+        Stmt::Local(ref local) => {
+            visitor.visit_local(local);
+        }
+        Stmt::Item(ref item) => {
+            visitor.visit_item(item);
+        }
+        Stmt::Expr(ref expr) |
+        Stmt::Semi(ref expr) => {
+            visitor.visit_expr(expr);
+        }
+        Stmt::Mac(ref details) => {
+            let (ref mac, _, ref attrs) = **details;
+            visitor.visit_mac(mac);
+            walk_list!(visitor, visit_attribute, attrs);
+        }
+    }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_local<V: Visitor>(visitor: &mut V, local: &Local) {
+    visitor.visit_pat(&local.pat);
+    if let Some(ref ty) = local.ty {
+        visitor.visit_ty(ty);
+    }
+    if let Some(ref init) = local.init {
+        visitor.visit_expr(init);
+    }
+    walk_list!(visitor, visit_attribute, &local.attrs);
+}
+
+#[cfg(feature = "full")]
+pub fn walk_view_path<V: Visitor>(visitor: &mut V, view_path: &ViewPath) {
+    match *view_path {
+        ViewPath::Simple(ref path, ref maybe_ident) => {
+            visitor.visit_path(path);
+            walk_opt_ident(visitor, maybe_ident);
+        }
+        ViewPath::Glob(ref path) => {
+            visitor.visit_path(path);
+        }
+        ViewPath::List(ref path, ref items) => {
+            visitor.visit_path(path);
+            for &PathListItem{ref name, ref rename} in items {
+                visitor.visit_ident(name);
+                walk_opt_ident(visitor, rename);
+            }
+        }
     }
 }
diff --git a/tests/rust b/tests/rust
index fc2373c..71c06a5 160000
--- a/tests/rust
+++ b/tests/rust
@@ -1 +1 @@
-Subproject commit fc2373c5a24646745dcbc14dc58889a9d8843f4e
+Subproject commit 71c06a56a120a0d5e3b224105ee3e6754f83e5fa
diff --git a/tests/test_expand.rs b/tests/test_expand.rs
deleted file mode 100644
index dc351ef..0000000
--- a/tests/test_expand.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-#![cfg(feature = "expand")]
-
-extern crate syn;
-use syn::*;
-
-#[macro_use]
-extern crate quote;
-use quote::Tokens;
-
-extern crate tempdir;
-use tempdir::TempDir;
-
-use std::fs::File;
-use std::io::{Read, Write};
-
-#[test]
-fn test_cfg() {
-    let original = quote! {
-        use super::*;
-
-        #[derive(A)]
-        struct P;
-
-        #[cfg_attr(feature = "q", derive(A))]
-        struct Q;
-
-        #[derive(A)]
-        #[cfg(feature = "r")]
-        struct R;
-
-        #[cfg(feature = "s1")]
-        #[cfg(all(feature = "s2", feature = "s3"))]
-        #[cfg_attr(feature = "s4", derive(A))]
-        struct S;
-    };
-
-    let expected = quote! {
-        // Unmodified from the input
-        use super::*;
-
-        type P = ();
-
-        #[cfg(feature = "q")]
-        type Q = ();
-
-        #[cfg(feature = "r")]
-        type R = ();
-
-        #[cfg(all(feature = "s1", feature = "s2", feature = "s3", feature = "s4"))]
-        type S = ();
-    };
-
-    test_expand(original, expected);
-}
-
-#[test]
-fn test_recursive() {
-    let original = quote! {
-        #[d]
-        #[cfg_attr(feature = "f", derive(Copy, B, Clone))]
-        #[e]
-        #[cfg(feature = "e")]
-        struct T;
-    };
-
-    let expected = quote! {
-        // From #[derive(A)] on struct S produced by #[derive(B)]
-        #[cfg(all(feature = "e", feature = "f", feature = "g"))]
-        type S = ();
-
-        // From #[derive(B)] on struct T
-        #[cfg(all(feature = "e", feature = "f"))]
-        impl B for T {}
-
-        // From the input
-        #[d]
-        #[cfg_attr(feature = "f", derive(Copy, Clone))]
-        #[e]
-        #[cfg(feature = "e")]
-        struct T;
-    };
-
-    test_expand(original, expected);
-}
-
-fn test_expand(original: Tokens, expected: Tokens) {
-    let dir = TempDir::new("syn").expect("create temp dir");
-    let src_path = dir.path().join("expand.in.rs");
-    let dst_path = dir.path().join("expand.rs");
-
-    // Write the src file
-    let mut src_file = File::create(&src_path).expect("create temp file");
-    src_file.write_all(original.to_string().as_bytes()).expect("write temp file");
-
-    // Run expansion
-    let mut registry = Registry::new();
-    registry.add_derive("A", expand_a);
-    registry.add_derive("B", expand_b);
-    registry.expand_file(&src_path, &dst_path).unwrap();
-
-    // Read the dst file
-    let mut expanded = String::new();
-    let mut dst_file = File::open(&dst_path).expect("open output file");
-    dst_file.read_to_string(&mut expanded).expect("read output file");
-    let krate = parse_crate(&expanded).expect("parse output file");
-
-    assert_eq!(quote!(#krate), expected);
-}
-
-fn expand_a(input: MacroInput) -> Result<Expanded, String> {
-    let name = &input.ident;
-    let out = quote! {
-        type #name = ();
-    };
-    Ok(Expanded {
-        new_items: parse_items(&out.to_string()).unwrap(),
-        original: None,
-    })
-}
-
-fn expand_b(input: MacroInput) -> Result<Expanded, String> {
-    assert_eq!(quote!(#input), quote! {
-        #[d]
-        #[cfg_attr(feature = "f", derive(Copy, Clone))]
-        #[e]
-        struct T;
-    });
-    let out = quote! {
-        #[cfg_attr(feature = "g", derive(A))]
-        struct S;
-
-        impl B for T {}
-    };
-    Ok(Expanded {
-        new_items: parse_items(&out.to_string()).unwrap(),
-        original: Some(input),
-    })
-}
diff --git a/tests/test_generics.rs b/tests/test_generics.rs
index c0e21fb..822d22d 100644
--- a/tests/test_generics.rs
+++ b/tests/test_generics.rs
@@ -58,14 +58,45 @@
     };
 
     let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
-
     let tokens = quote! {
         impl #impl_generics MyTrait for Test #ty_generics #where_clause {}
     };
-
     let expected = concat!("impl < 'a , 'b : 'a , # [ may_dangle ] T : 'a > ",
                            "MyTrait for Test < 'a , 'b , T > ",
                            "where T : Debug { }");
-
     assert_eq!(expected, tokens.to_string());
+
+    let turbofish = ty_generics.as_turbofish();
+    let tokens = quote! {
+        Test #turbofish
+    };
+    let expected = "Test :: < 'a , 'b , T >";
+    assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_ty_param_bound() {
+    let tokens = quote!('a);
+    let expected = TyParamBound::Region(Lifetime::new("'a"));
+    assert_eq!(expected, parse_ty_param_bound(tokens.as_str()).unwrap());
+
+    let tokens = quote!(Debug);
+    let expected = TyParamBound::Trait(
+        PolyTraitRef {
+            bound_lifetimes: Vec::new(),
+            trait_ref: "Debug".into(),
+        },
+        TraitBoundModifier::None,
+    );
+    assert_eq!(expected, parse_ty_param_bound(tokens.as_str()).unwrap());
+
+    let tokens = quote!(?Sized);
+    let expected = TyParamBound::Trait(
+        PolyTraitRef {
+            bound_lifetimes: Vec::new(),
+            trait_ref: "Sized".into(),
+        },
+        TraitBoundModifier::Maybe,
+    );
+    assert_eq!(expected, parse_ty_param_bound(tokens.as_str()).unwrap());
 }
diff --git a/tests/test_round_trip.rs b/tests/test_round_trip.rs
index 2d808b5..2b8528f 100644
--- a/tests/test_round_trip.rs
+++ b/tests/test_round_trip.rs
@@ -52,13 +52,7 @@
         // TODO better support for attributes
         "tests/rust/src/test/run-pass/item-attributes.rs" |
         // TODO precedence issue with binop vs poly trait ref
-        "tests/rust/src/test/run-pass/try-macro.rs" |
-        // TODO type macros
-        "tests/rust/src/test/run-pass/type-macros-hlist.rs" |
-        // TODO type macros
-        "tests/rust/src/test/run-pass/type-macros-simple.rs" |
-        // TODO type macros
-        "tests/rust/src/test/run-pass-fulldeps/proc_macro.rs" => false,
+        "tests/rust/src/test/run-pass/try-macro.rs" => false,
         _ => true,
     }
 }
@@ -151,8 +145,9 @@
                              Visibility};
     use syntex_syntax::codemap::{self, Spanned};
     use syntex_syntax::fold::{self, Folder};
-    use syntex_syntax::parse::token::{Lit, Token, intern};
+    use syntex_syntax::parse::token::{Lit, Token};
     use syntex_syntax::ptr::P;
+    use syntex_syntax::symbol::Symbol;
     use syntex_syntax::tokenstream::{Delimited, SequenceRepetition, TokenTree};
     use syntex_syntax::util::move_map::MoveMap;
     use syntex_syntax::util::small_vector::SmallVector;
@@ -169,12 +164,12 @@
             // so many equivalent representations of the same literal; they are
             // tested elsewhere
             match l {
-                Lit::Byte(_) => Lit::Byte(intern("")),
-                Lit::Char(_) => Lit::Char(intern("")),
-                Lit::Integer(_) => Lit::Integer(intern("")),
-                Lit::Float(_) => Lit::Float(intern("")),
-                Lit::Str_(_) => Lit::Str_(intern("")),
-                Lit::ByteStr(_) => Lit::ByteStr(intern("")),
+                Lit::Byte(_) => Lit::Byte(Symbol::intern("")),
+                Lit::Char(_) => Lit::Char(Symbol::intern("")),
+                Lit::Integer(_) => Lit::Integer(Symbol::intern("")),
+                Lit::Float(_) => Lit::Float(Symbol::intern("")),
+                Lit::Str_(_) => Lit::Str_(Symbol::intern("")),
+                Lit::ByteStr(_) => Lit::ByteStr(Symbol::intern("")),
                 _ => l,
             }
         }
@@ -295,26 +290,26 @@
         }
 
         fn fold_attribute(&mut self, mut at: Attribute) -> Option<Attribute> {
-            at.node.id.0 = 0;
+            at.id.0 = 0;
             fold::noop_fold_attribute(at, self)
         }
 
-        fn fold_meta_item(&mut self, meta_item: P<MetaItem>) -> P<MetaItem> {
-            meta_item.map(|Spanned { node, span }| {
-                Spanned {
-                    node: match node {
-                        MetaItemKind::Word(id) => MetaItemKind::Word(id),
-                        MetaItemKind::List(id, mis) => {
-                            MetaItemKind::List(id, mis.move_map(|e| self.fold_meta_list_item(e)))
-                        }
-                        // default fold_meta_item does not fold the value span
-                        MetaItemKind::NameValue(id, lit) => {
-                            MetaItemKind::NameValue(id, self.fold_spanned(lit))
-                        }
-                    },
-                    span: self.new_span(span),
-                }
-            })
+        fn fold_meta_item(&mut self, meta_item: MetaItem) -> MetaItem {
+            let MetaItem { name, node, span } = meta_item;
+            MetaItem {
+                name: name,
+                node: match node {
+                    MetaItemKind::Word => MetaItemKind::Word,
+                    MetaItemKind::List(nested) => {
+                        MetaItemKind::List(nested.move_map(|e| self.fold_meta_list_item(e)))
+                    }
+                    // default fold_meta_item does not fold the value span
+                    MetaItemKind::NameValue(lit) => {
+                        MetaItemKind::NameValue(self.fold_spanned(lit))
+                    }
+                },
+                span: self.new_span(span),
+            }
         }
 
         fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {