Move all #[derive] impls behind Cargo feature gates

This commit moves all #[derive] annotations behind Cargo feature gates to add
the ability to strip them all out entirely. The `Clone` and `Copy` impls
continue to be enabled by default as they tend to be mega useful but other
equality/hash/debug impls are all default behind the `extra-impls` gate.

This commit, on my computer, has the following timings:

| features                      | before  | after
|-------------------------------|---------|------
| default                       | 3.67    | 2.96
| *none*                        | 1.78    | 0.49
| {printing, parsing}           | 3.71    | 2.57
| default + {full}              | 8.50    | 6.31
| {full}                        | 3.53    | 0.70
| {full, printing, parsing}     | 8.10    | 5.29

Closes #143
diff --git a/.travis.yml b/.travis.yml
index e5ceaf4..5b33626 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -38,11 +38,14 @@
           cargo build --features full &&
           cargo build --features 'visit fold' &&
           cargo build --features 'full visit fold' &&
+          cargo build --no-default-features --features 'full parsing printing' &&
+          cargo build --no-default-features --features 'visit fold parsing printing' &&
+          cargo build --no-default-features --features 'full visit fold parsing printing' &&
           (cd synom && cargo test)
           ;;
         test)
           git submodule update --init &&
-          cargo test --features 'full aster visit fold' --release
+          cargo test --all-features --release
           ;;
         clippy)
           cargo install clippy --debug --force || exit
diff --git a/Cargo.toml b/Cargo.toml
index b3d0b53..72b7498 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,13 +10,15 @@
 include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
 
 [features]
-default = ["parsing", "printing"]
+default = ["parsing", "printing", "clone-impls"]
 aster = []
 full = []
 parsing = ["unicode-xid", "synom"]
 printing = ["quote"]
 visit = []
 fold = []
+clone-impls = []
+extra-traits = []
 
 [dependencies]
 quote = { version = "0.3.7", optional = true }
diff --git a/src/attr.rs b/src/attr.rs
index fecfd9a..f839ec4 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -133,7 +133,7 @@
     /// Distinguishes between Attributes that decorate items and Attributes that
     /// are contained as statements within items. These two cases need to be
     /// distinguished for pretty-printing.
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum AttrStyle {
         /// Attribute of the form `#![...]`.
         Outer,
@@ -230,14 +230,20 @@
 
     fn outer(self) -> Self::Ret {
         fn is_outer(attr: &&Attribute) -> bool {
-            attr.style == AttrStyle::Outer
+            match attr.style {
+                AttrStyle::Outer => true,
+                _ => false,
+            }
         }
         self.into_iter().filter(is_outer)
     }
 
     fn inner(self) -> Self::Ret {
         fn is_inner(attr: &&Attribute) -> bool {
-            attr.style == AttrStyle::Inner
+            match attr.style {
+                AttrStyle::Inner => true,
+                _ => false,
+            }
         }
         self.into_iter().filter(is_inner)
     }
@@ -369,7 +375,7 @@
             // If this was a sugared doc, emit it in its original form instead of `#[doc = "..."]`
             match *self {
                 Attribute {
-                    style,
+                    ref style,
                     path: Path { global: false, ref segments },
                     ref tts,
                     is_sugared_doc: true,
@@ -380,7 +386,7 @@
                 {
                     if let TokenTree::Token(Token::Eq) = self.tts[0] {
                         if let TokenTree::Token(Token::Literal(Lit::Str(ref value, StrStyle::Cooked))) = self.tts[1] {
-                            match style {
+                            match *style {
                                 AttrStyle::Inner if value.starts_with("//!") => {
                                     tokens.append(&format!("{}\n", value));
                                     return;
diff --git a/src/data.rs b/src/data.rs
index d01d9e5..3916b25 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -247,7 +247,6 @@
 mod printing {
     use super::*;
     use quote::{Tokens, ToTokens};
-    use ty::PathParameters;
 
     impl ToTokens for Variant {
         fn to_tokens(&self, tokens: &mut Tokens) {
@@ -312,7 +311,7 @@
                     if !path.global &&
                        path.segments.len() == 1 &&
                        (path.segments[0].ident == "self" || path.segments[0].ident == "super") &&
-                       path.segments[0].parameters == PathParameters::none() {
+                       path.segments[0].parameters.is_empty() {
 
                         // Don't emit preceding `in` if path is `self` or `super`
                     } else {
diff --git a/src/expr.rs b/src/expr.rs
index 39ab6c7..05f195a 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -341,7 +341,7 @@
 
 ast_enum! {
     /// How a macro was invoked.
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum MacStmtStyle {
         /// The macro statement had a trailing semicolon, e.g. `foo! { ... };`
         /// `foo!(...);`, `foo![...];`
@@ -439,7 +439,7 @@
 
 ast_enum! {
     /// A capture clause
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum CaptureBy {
         Value,
         Ref,
@@ -448,7 +448,7 @@
 
 ast_enum! {
     /// Limit types of a range (inclusive or exclusive)
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum RangeLimits {
         /// Inclusive at the beginning, exclusive at the end
         HalfOpen,
@@ -474,7 +474,7 @@
 }
 
 ast_enum! {
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum BindingMode {
         ByRef(Mutability),
         ByValue(Mutability),
@@ -1823,7 +1823,7 @@
         fn to_tokens(&self, tokens: &mut Tokens) {
             match *self {
                 Pat::Wild => tokens.append("_"),
-                Pat::Ident(mode, ref ident, ref subpat) => {
+                Pat::Ident(ref mode, ref ident, ref subpat) => {
                     mode.to_tokens(tokens);
                     ident.to_tokens(tokens);
                     if let Some(ref subpat) = *subpat {
@@ -1911,7 +1911,7 @@
                     tokens.append("box");
                     inner.to_tokens(tokens);
                 }
-                Pat::Ref(ref target, mutability) => {
+                Pat::Ref(ref target, ref mutability) => {
                     tokens.append("&");
                     mutability.to_tokens(tokens);
                     target.to_tokens(tokens);
@@ -1929,8 +1929,9 @@
                         if !before.is_empty() {
                             tokens.append(",");
                         }
-                        if **rest != Pat::Wild {
-                            rest.to_tokens(tokens);
+                        match **rest {
+                            Pat::Wild => {}
+                            _ => rest.to_tokens(tokens),
                         }
                         tokens.append("..");
                         if !after.is_empty() {
@@ -2012,10 +2013,10 @@
                     tokens.append(";");
                 }
                 Stmt::Mac(ref mac) => {
-                    let (ref mac, style, ref attrs) = **mac;
+                    let (ref mac, ref style, ref attrs) = **mac;
                     tokens.append_all(attrs.outer());
                     mac.to_tokens(tokens);
-                    match style {
+                    match *style {
                         MacStmtStyle::Semicolon => tokens.append(";"),
                         MacStmtStyle::Braces | MacStmtStyle::NoBraces => {
                             // no semicolon
diff --git a/src/generics.rs b/src/generics.rs
index 2841a47..adf6dfa 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -12,19 +12,22 @@
 }
 
 #[cfg(feature = "printing")]
-/// Returned by `Generics::split_for_impl`.
-#[derive(Debug)]
-pub struct ImplGenerics<'a>(&'a Generics);
+ast_struct! {
+    /// Returned by `Generics::split_for_impl`.
+    pub struct ImplGenerics<'a>(&'a Generics);
+}
 
 #[cfg(feature = "printing")]
-/// Returned by `Generics::split_for_impl`.
-#[derive(Debug)]
-pub struct TyGenerics<'a>(&'a Generics);
+ast_struct! {
+    /// Returned by `Generics::split_for_impl`.
+    pub struct TyGenerics<'a>(&'a Generics);
+}
 
 #[cfg(feature = "printing")]
-/// Returned by `TyGenerics::as_turbofish`.
-#[derive(Debug)]
-pub struct Turbofish<'a>(&'a Generics);
+ast_struct! {
+    /// Returned by `TyGenerics::as_turbofish`.
+    pub struct Turbofish<'a>(&'a Generics);
+}
 
 #[cfg(feature = "printing")]
 impl Generics {
@@ -132,7 +135,7 @@
 ast_enum! {
     /// A modifier on a bound, currently this is only used for `?Sized`, where the
     /// modifier is `Maybe`. Negative bounds should also be handled here.
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum TraitBoundModifier {
         None,
         Maybe,
diff --git a/src/item.rs b/src/item.rs
index 7b25f2f..611e52a 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -184,7 +184,7 @@
 }
 
 ast_enum! {
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum Constness {
         Const,
         NotConst,
@@ -192,7 +192,7 @@
 }
 
 ast_enum! {
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum Defaultness {
         Default,
         Final,
@@ -269,7 +269,7 @@
 }
 
 ast_enum! {
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum ImplPolarity {
         /// `impl Trait for Type`
         Positive,
diff --git a/src/lit.rs b/src/lit.rs
index 4811485..72a2f43 100644
--- a/src/lit.rs
+++ b/src/lit.rs
@@ -2,6 +2,7 @@
     /// Literal kind.
     ///
     /// E.g. `"foo"`, `42`, `12.34` or `bool`
+    #[cfg_attr(not(feature = "clone-impls"), derive(Clone))]
     pub enum Lit {
         /// A string literal (`"foo"`)
         Str(String, StrStyle),
@@ -21,6 +22,7 @@
 }
 
 ast_enum! {
+    #[cfg_attr(not(feature = "clone-impls"), derive(Clone))]
     pub enum StrStyle {
         /// A regular string, like `"foo"`
         Cooked,
@@ -69,6 +71,7 @@
 
 ast_enum! {
     #[derive(Copy)]
+    #[cfg_attr(not(feature = "clone-impls"), derive(Clone))]
     pub enum IntTy {
         Isize,
         I8,
@@ -86,6 +89,7 @@
 
 ast_enum! {
     #[derive(Copy)]
+    #[cfg_attr(not(feature = "clone-impls"), derive(Clone))]
     pub enum FloatTy {
         F32,
         F64,
@@ -133,31 +137,35 @@
 ]}
 
 #[cfg(feature = "parsing")]
-#[derive(Debug, Clone)]
-pub struct StrLit {
-    pub value: String,
-    pub style: StrStyle,
+ast_struct! {
+    pub struct StrLit {
+        pub value: String,
+        pub style: StrStyle,
+    }
 }
 
 #[cfg(feature = "parsing")]
-#[derive(Debug, Clone)]
-pub struct ByteStrLit {
-    pub value: Vec<u8>,
-    pub style: StrStyle,
+ast_struct! {
+    pub struct ByteStrLit {
+        pub value: Vec<u8>,
+        pub style: StrStyle,
+    }
 }
 
 #[cfg(feature = "parsing")]
-#[derive(Debug, Clone)]
-pub struct IntLit {
-    pub value: u64,
-    pub suffix: IntTy,
+ast_struct! {
+    pub struct IntLit {
+        pub value: u64,
+        pub suffix: IntTy,
+    }
 }
 
 #[cfg(feature = "parsing")]
-#[derive(Debug, Clone)]
-pub struct FloatLit {
-    pub value: String,
-    pub suffix: FloatTy,
+ast_struct! {
+    pub struct FloatLit {
+        pub value: String,
+        pub suffix: FloatTy,
+    }
 }
 
 #[cfg(feature = "parsing")]
diff --git a/src/mac.rs b/src/mac.rs
index e6132e4..dbed4eb 100644
--- a/src/mac.rs
+++ b/src/mac.rs
@@ -89,7 +89,7 @@
 }
 
 ast_enum! {
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum BinOpToken {
         Plus,
         Minus,
@@ -106,7 +106,7 @@
 
 ast_enum! {
     /// A delimiter token
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum DelimToken {
         /// A round parenthesis: `(` or `)`
         Paren,
@@ -371,8 +371,8 @@
                 Token::OrOr => tokens.append("||"),
                 Token::Not => tokens.append("!"),
                 Token::Tilde => tokens.append("~"),
-                Token::BinOp(binop) => tokens.append(binop.op()),
-                Token::BinOpEq(binop) => tokens.append(binop.assign_op()),
+                Token::BinOp(ref binop) => tokens.append(binop.op()),
+                Token::BinOpEq(ref binop) => tokens.append(binop.assign_op()),
                 Token::At => tokens.append("@"),
                 Token::Dot => tokens.append("."),
                 Token::DotDot => tokens.append(".."),
diff --git a/src/macros.rs b/src/macros.rs
index 656fe90..bd686ac 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -1,21 +1,12 @@
 macro_rules! ast_struct {
     (
         $(#[$attr:meta])*
-        pub struct $name:ident {
-            $(
-                $(#[$field_attr:meta])*
-                pub $field:ident: $ty:ty,
-            )*
-        }
+        pub struct $name:ident $($rest:tt)*
     ) => {
         $(#[$attr])*
-        #[derive(Debug, Clone, Eq, PartialEq, Hash)]
-        pub struct $name {
-            $(
-                $(#[$field_attr])*
-                pub $field: $ty,
-            )*
-        }
+        #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+        #[cfg_attr(feature = "clone-impls", derive(Clone))]
+        pub struct $name $($rest)*
     }
 }
 
@@ -25,7 +16,8 @@
         pub enum $name:ident { $($variants:tt)* }
     ) => (
         $(#[$enum_attr])*
-        #[derive(Debug, Clone, Eq, PartialEq, Hash)]
+        #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+        #[cfg_attr(feature = "clone-impls", derive(Clone))]
         pub enum $name {
             $($variants)*
         }
diff --git a/src/op.rs b/src/op.rs
index cac1741..6393e00 100644
--- a/src/op.rs
+++ b/src/op.rs
@@ -1,5 +1,5 @@
 ast_enum! {
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum BinOp {
         /// The `+` operator (addition)
         Add,
@@ -41,7 +41,7 @@
 }
 
 ast_enum! {
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum UnOp {
         /// The `*` operator for dereferencing
         Deref,
diff --git a/src/ty.rs b/src/ty.rs
index 4fb3328..7345da7 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -69,7 +69,7 @@
 }
 
 ast_enum! {
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum Mutability {
         Mutable,
         Immutable,
@@ -234,7 +234,7 @@
 }
 
 ast_enum! {
-    #[derive(Copy)]
+    #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum Unsafety {
         Unsafe,
         Normal,
@@ -422,7 +422,7 @@
     named!(ty_path -> Ty, do_parse!(
         qpath: qpath >>
         parenthesized: cond!(
-            qpath.1.segments.last().unwrap().parameters == PathParameters::none(),
+            qpath.1.segments.last().unwrap().parameters.is_empty(),
             option!(parenthesized_parameter_data)
         ) >>
         bounds: many0!(preceded!(punct!("+"), ty_param_bound)) >>
@@ -605,7 +605,7 @@
         bound_lifetimes: bound_lifetimes >>
         trait_ref: path >>
         parenthesized: option!(cond_reduce!(
-            trait_ref.segments.last().unwrap().parameters == PathParameters::none(),
+            trait_ref.segments.last().unwrap().parameters.is_empty(),
             parenthesized_parameter_data
         )) >>
         ({
diff --git a/synom/Cargo.toml b/synom/Cargo.toml
index fde5ed4..988c5bc 100644
--- a/synom/Cargo.toml
+++ b/synom/Cargo.toml
@@ -16,5 +16,5 @@
 [dev-dependencies.syn]
 version = "0.11"
 path = ".."
-features = ["parsing", "full"]
+features = ["parsing", "full", "extra-traits"]
 default-features = false
diff --git a/tests/test_generics.rs b/tests/test_generics.rs
index 08886bb..92ae9e9 100644
--- a/tests/test_generics.rs
+++ b/tests/test_generics.rs
@@ -1,3 +1,5 @@
+#![cfg(feature = "extra-traits")]
+
 extern crate syn;
 use syn::*;
 
diff --git a/tests/test_macro_input.rs b/tests/test_macro_input.rs
index 4e6bbd8..653fbe2 100644
--- a/tests/test_macro_input.rs
+++ b/tests/test_macro_input.rs
@@ -2,6 +2,7 @@
 //!
 //! Deprecation warnings are suppressed to keep the output clean.
 #![allow(deprecated)]
+#![cfg(feature = "extra-traits")]
 
 extern crate syn;
 use syn::*;
diff --git a/tests/test_meta_item.rs b/tests/test_meta_item.rs
index 735c9a2..72cec3a 100644
--- a/tests/test_meta_item.rs
+++ b/tests/test_meta_item.rs
@@ -1,3 +1,5 @@
+#![cfg(feature = "extra-traits")]
+
 extern crate syn;
 use syn::*;
 
diff --git a/tests/test_token_trees.rs b/tests/test_token_trees.rs
index 8351f54..33dbdda 100644
--- a/tests/test_token_trees.rs
+++ b/tests/test_token_trees.rs
@@ -1,3 +1,5 @@
+#![cfg(feature = "extra-traits")]
+
 extern crate syn;
 use syn::TokenTree::{self, Token};
 use syn::DelimToken::*;