about summary refs log tree commit diff
path: root/src/libsyntax_ext
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsyntax_ext')
-rw-r--r--src/libsyntax_ext/asm.rs245
-rw-r--r--src/libsyntax_ext/cfg.rs45
-rw-r--r--src/libsyntax_ext/concat.rs66
-rw-r--r--src/libsyntax_ext/concat_idents.rs73
-rw-r--r--src/libsyntax_ext/deriving/bounds.rs50
-rw-r--r--src/libsyntax_ext/deriving/clone.rs115
-rw-r--r--src/libsyntax_ext/deriving/cmp/eq.rs73
-rw-r--r--src/libsyntax_ext/deriving/cmp/ord.rs136
-rw-r--r--src/libsyntax_ext/deriving/cmp/partial_eq.rs97
-rw-r--r--src/libsyntax_ext/deriving/cmp/partial_ord.rs233
-rw-r--r--src/libsyntax_ext/deriving/debug.rs156
-rw-r--r--src/libsyntax_ext/deriving/decodable.rs224
-rw-r--r--src/libsyntax_ext/deriving/default.rs85
-rw-r--r--src/libsyntax_ext/deriving/encodable.rs289
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs1634
-rw-r--r--src/libsyntax_ext/deriving/generic/ty.rs284
-rw-r--r--src/libsyntax_ext/deriving/hash.rs100
-rw-r--r--src/libsyntax_ext/deriving/mod.rs202
-rw-r--r--src/libsyntax_ext/deriving/primitive.rs142
-rw-r--r--src/libsyntax_ext/env.rs106
-rw-r--r--src/libsyntax_ext/format.rs716
-rw-r--r--src/libsyntax_ext/lib.rs82
-rw-r--r--src/libsyntax_ext/log_syntax.rs34
-rw-r--r--src/libsyntax_ext/trace_macros.rs43
24 files changed, 5230 insertions, 0 deletions
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
new file mode 100644
index 00000000000..072be571221
--- /dev/null
+++ b/src/libsyntax_ext/asm.rs
@@ -0,0 +1,245 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*
+ * Inline assembly support.
+ */
+use self::State::*;
+
+use syntax::ast;
+use syntax::codemap;
+use syntax::codemap::Span;
+use syntax::ext::base;
+use syntax::ext::base::*;
+use syntax::feature_gate;
+use syntax::parse::token::{intern, InternedString};
+use syntax::parse::token;
+use syntax::ptr::P;
+use syntax::ast::AsmDialect;
+
+enum State {
+    Asm,
+    Outputs,
+    Inputs,
+    Clobbers,
+    Options,
+    StateNone
+}
+
+impl State {
+    fn next(&self) -> State {
+        match *self {
+            Asm       => Outputs,
+            Outputs   => Inputs,
+            Inputs    => Clobbers,
+            Clobbers  => Options,
+            Options   => StateNone,
+            StateNone => StateNone
+        }
+    }
+}
+
+const OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"];
+
+pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
+                       -> Box<base::MacResult+'cx> {
+    if !cx.ecfg.enable_asm() {
+        feature_gate::emit_feature_err(
+            &cx.parse_sess.span_diagnostic, "asm", sp,
+            feature_gate::GateIssue::Language,
+            feature_gate::EXPLAIN_ASM);
+        return DummyResult::expr(sp);
+    }
+
+    let mut p = cx.new_parser_from_tts(tts);
+    let mut asm = InternedString::new("");
+    let mut asm_str_style = None;
+    let mut outputs = Vec::new();
+    let mut inputs = Vec::new();
+    let mut clobs = Vec::new();
+    let mut volatile = false;
+    let mut alignstack = false;
+    let mut dialect = AsmDialect::Att;
+
+    let mut state = Asm;
+
+    'statement: loop {
+        match state {
+            Asm => {
+                if asm_str_style.is_some() {
+                    // If we already have a string with instructions,
+                    // ending up in Asm state again is an error.
+                    cx.span_err(sp, "malformed inline assembly");
+                    return DummyResult::expr(sp);
+                }
+                let (s, style) = match expr_to_string(cx, panictry!(p.parse_expr()),
+                                                   "inline assembly must be a string literal") {
+                    Some((s, st)) => (s, st),
+                    // let compilation continue
+                    None => return DummyResult::expr(sp),
+                };
+                asm = s;
+                asm_str_style = Some(style);
+            }
+            Outputs => {
+                while p.token != token::Eof &&
+                      p.token != token::Colon &&
+                      p.token != token::ModSep {
+
+                    if !outputs.is_empty() {
+                        panictry!(p.eat(&token::Comma));
+                    }
+
+                    let (constraint, _str_style) = panictry!(p.parse_str());
+
+                    let span = p.last_span;
+
+                    panictry!(p.expect(&token::OpenDelim(token::Paren)));
+                    let out = panictry!(p.parse_expr());
+                    panictry!(p.expect(&token::CloseDelim(token::Paren)));
+
+                    // Expands a read+write operand into two operands.
+                    //
+                    // Use '+' modifier when you want the same expression
+                    // to be both an input and an output at the same time.
+                    // It's the opposite of '=&' which means that the memory
+                    // cannot be shared with any other operand (usually when
+                    // a register is clobbered early.)
+                    let output = match constraint.slice_shift_char() {
+                        Some(('=', _)) => None,
+                        Some(('+', operand)) => {
+                            Some(token::intern_and_get_ident(&format!(
+                                        "={}", operand)))
+                        }
+                        _ => {
+                            cx.span_err(span, "output operand constraint lacks '=' or '+'");
+                            None
+                        }
+                    };
+
+                    let is_rw = output.is_some();
+                    let is_indirect = constraint.contains("*");
+                    outputs.push(ast::InlineAsmOutput {
+                        constraint: output.unwrap_or(constraint),
+                        expr: out,
+                        is_rw: is_rw,
+                        is_indirect: is_indirect,
+                    });
+                }
+            }
+            Inputs => {
+                while p.token != token::Eof &&
+                      p.token != token::Colon &&
+                      p.token != token::ModSep {
+
+                    if !inputs.is_empty() {
+                        panictry!(p.eat(&token::Comma));
+                    }
+
+                    let (constraint, _str_style) = panictry!(p.parse_str());
+
+                    if constraint.starts_with("=") {
+                        cx.span_err(p.last_span, "input operand constraint contains '='");
+                    } else if constraint.starts_with("+") {
+                        cx.span_err(p.last_span, "input operand constraint contains '+'");
+                    }
+
+                    panictry!(p.expect(&token::OpenDelim(token::Paren)));
+                    let input = panictry!(p.parse_expr());
+                    panictry!(p.expect(&token::CloseDelim(token::Paren)));
+
+                    inputs.push((constraint, input));
+                }
+            }
+            Clobbers => {
+                while p.token != token::Eof &&
+                      p.token != token::Colon &&
+                      p.token != token::ModSep {
+
+                    if !clobs.is_empty() {
+                        panictry!(p.eat(&token::Comma));
+                    }
+
+                    let (s, _str_style) = panictry!(p.parse_str());
+
+                    if OPTIONS.iter().any(|&opt| s == opt) {
+                        cx.span_warn(p.last_span, "expected a clobber, found an option");
+                    }
+                    clobs.push(s);
+                }
+            }
+            Options => {
+                let (option, _str_style) = panictry!(p.parse_str());
+
+                if option == "volatile" {
+                    // Indicates that the inline assembly has side effects
+                    // and must not be optimized out along with its outputs.
+                    volatile = true;
+                } else if option == "alignstack" {
+                    alignstack = true;
+                } else if option == "intel" {
+                    dialect = AsmDialect::Intel;
+                } else {
+                    cx.span_warn(p.last_span, "unrecognized option");
+                }
+
+                if p.token == token::Comma {
+                    panictry!(p.eat(&token::Comma));
+                }
+            }
+            StateNone => ()
+        }
+
+        loop {
+            // MOD_SEP is a double colon '::' without space in between.
+            // When encountered, the state must be advanced twice.
+            match (&p.token, state.next(), state.next().next()) {
+                (&token::Colon, StateNone, _)   |
+                (&token::ModSep, _, StateNone) => {
+                    panictry!(p.bump());
+                    break 'statement;
+                }
+                (&token::Colon, st, _)   |
+                (&token::ModSep, _, st) => {
+                    panictry!(p.bump());
+                    state = st;
+                }
+                (&token::Eof, _, _) => break 'statement,
+                _ => break
+            }
+        }
+    }
+
+    let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
+        call_site: sp,
+        callee: codemap::NameAndSpan {
+            format: codemap::MacroBang(intern("asm")),
+            span: None,
+            allow_internal_unstable: false,
+        },
+    });
+
+    MacEager::expr(P(ast::Expr {
+        id: ast::DUMMY_NODE_ID,
+        node: ast::ExprInlineAsm(ast::InlineAsm {
+            asm: token::intern_and_get_ident(&asm),
+            asm_str_style: asm_str_style.unwrap(),
+            outputs: outputs,
+            inputs: inputs,
+            clobbers: clobs,
+            volatile: volatile,
+            alignstack: alignstack,
+            dialect: dialect,
+            expn_id: expn_id,
+        }),
+        span: sp,
+        attrs: None,
+    }))
+}
diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs
new file mode 100644
index 00000000000..1e1bf538876
--- /dev/null
+++ b/src/libsyntax_ext/cfg.rs
@@ -0,0 +1,45 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/// The compiler code necessary to support the cfg! extension, which expands to
+/// a literal `true` or `false` based on whether the given cfg matches the
+/// current compilation environment.
+
+use syntax::ast;
+use syntax::codemap::Span;
+use syntax::ext::base::*;
+use syntax::ext::base;
+use syntax::ext::build::AstBuilder;
+use syntax::attr;
+use syntax::attr::*;
+use syntax::parse::token;
+use syntax::config::CfgDiagReal;
+
+pub fn expand_cfg<'cx>(cx: &mut ExtCtxt,
+                       sp: Span,
+                       tts: &[ast::TokenTree])
+                       -> Box<base::MacResult+'static> {
+    let mut p = cx.new_parser_from_tts(tts);
+    let cfg = panictry!(p.parse_meta_item());
+
+    if !panictry!(p.eat(&token::Eof)){
+        cx.span_err(sp, "expected 1 cfg-pattern");
+        return DummyResult::expr(sp);
+    }
+
+    let matches_cfg = {
+        let mut diag = CfgDiagReal {
+            diag: &cx.parse_sess.span_diagnostic,
+            feature_gated_cfgs: cx.feature_gated_cfgs,
+        };
+        attr::cfg_matches(&cx.cfg, &cfg, &mut diag)
+    };
+    MacEager::expr(cx.expr_bool(sp, matches_cfg))
+}
diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs
new file mode 100644
index 00000000000..de913fe0431
--- /dev/null
+++ b/src/libsyntax_ext/concat.rs
@@ -0,0 +1,66 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use syntax::ast;
+use syntax::codemap;
+use syntax::ext::base;
+use syntax::ext::build::AstBuilder;
+use syntax::parse::token;
+
+use std::string::String;
+
+pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
+                         sp: codemap::Span,
+                         tts: &[ast::TokenTree])
+                         -> Box<base::MacResult+'static> {
+    let es = match base::get_exprs_from_tts(cx, sp, tts) {
+        Some(e) => e,
+        None => return base::DummyResult::expr(sp)
+    };
+    let mut accumulator = String::new();
+    for e in es {
+        match e.node {
+            ast::ExprLit(ref lit) => {
+                match lit.node {
+                    ast::LitStr(ref s, _) |
+                    ast::LitFloat(ref s, _) |
+                    ast::LitFloatUnsuffixed(ref s) => {
+                        accumulator.push_str(&s);
+                    }
+                    ast::LitChar(c) => {
+                        accumulator.push(c);
+                    }
+                    ast::LitInt(i, ast::UnsignedIntLit(_)) |
+                    ast::LitInt(i, ast::SignedIntLit(_, ast::Plus)) |
+                    ast::LitInt(i, ast::UnsuffixedIntLit(ast::Plus)) => {
+                        accumulator.push_str(&format!("{}", i));
+                    }
+                    ast::LitInt(i, ast::SignedIntLit(_, ast::Minus)) |
+                    ast::LitInt(i, ast::UnsuffixedIntLit(ast::Minus)) => {
+                        accumulator.push_str(&format!("-{}", i));
+                    }
+                    ast::LitBool(b) => {
+                        accumulator.push_str(&format!("{}", b));
+                    }
+                    ast::LitByte(..) |
+                    ast::LitByteStr(..) => {
+                        cx.span_err(e.span, "cannot concatenate a byte string literal");
+                    }
+                }
+            }
+            _ => {
+                cx.span_err(e.span, "expected a literal");
+            }
+        }
+    }
+    base::MacEager::expr(cx.expr_str(
+            sp,
+            token::intern_and_get_ident(&accumulator[..])))
+}
diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs
new file mode 100644
index 00000000000..9702b24ffd4
--- /dev/null
+++ b/src/libsyntax_ext/concat_idents.rs
@@ -0,0 +1,73 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use syntax::ast::{self, TokenTree};
+use syntax::codemap::Span;
+use syntax::ext::base::*;
+use syntax::ext::base;
+use syntax::feature_gate;
+use syntax::parse::token;
+use syntax::parse::token::str_to_ident;
+use syntax::ptr::P;
+
+pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
+                              -> Box<base::MacResult+'cx> {
+    if !cx.ecfg.enable_concat_idents() {
+        feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
+                                       "concat_idents",
+                                       sp,
+                                       feature_gate::GateIssue::Language,
+                                       feature_gate::EXPLAIN_CONCAT_IDENTS);
+        return base::DummyResult::expr(sp);
+    }
+
+    let mut res_str = String::new();
+    for (i, e) in tts.iter().enumerate() {
+        if i & 1 == 1 {
+            match *e {
+                TokenTree::Token(_, token::Comma) => {},
+                _ => {
+                    cx.span_err(sp, "concat_idents! expecting comma.");
+                    return DummyResult::expr(sp);
+                },
+            }
+        } else {
+            match *e {
+                TokenTree::Token(_, token::Ident(ident, _)) => {
+                    res_str.push_str(&ident.name.as_str())
+                },
+                _ => {
+                    cx.span_err(sp, "concat_idents! requires ident args.");
+                    return DummyResult::expr(sp);
+                },
+            }
+        }
+    }
+    let res = str_to_ident(&res_str);
+
+    let e = P(ast::Expr {
+        id: ast::DUMMY_NODE_ID,
+        node: ast::ExprPath(None,
+            ast::Path {
+                 span: sp,
+                 global: false,
+                 segments: vec!(
+                    ast::PathSegment {
+                        identifier: res,
+                        parameters: ast::PathParameters::none(),
+                    }
+                )
+            }
+        ),
+        span: sp,
+        attrs: None,
+    });
+    MacEager::expr(e)
+}
diff --git a/src/libsyntax_ext/deriving/bounds.rs b/src/libsyntax_ext/deriving/bounds.rs
new file mode 100644
index 00000000000..9bc0e088110
--- /dev/null
+++ b/src/libsyntax_ext/deriving/bounds.rs
@@ -0,0 +1,50 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use deriving::generic::*;
+use deriving::generic::ty::*;
+
+use syntax::ast::MetaItem;
+use syntax::codemap::Span;
+use syntax::ext::base::{ExtCtxt, Annotatable};
+
+pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt,
+                                    span: Span,
+                                    _: &MetaItem,
+                                    _: &Annotatable,
+                                    _: &mut FnMut(Annotatable))
+{
+    cx.span_err(span, "this unsafe trait should be implemented explicitly");
+}
+
+pub fn expand_deriving_copy(cx: &mut ExtCtxt,
+                            span: Span,
+                            mitem: &MetaItem,
+                            item: &Annotatable,
+                            push: &mut FnMut(Annotatable))
+{
+    let mut v = cx.crate_root.map(|s| vec![s]).unwrap_or(Vec::new());
+    v.push("marker");
+    v.push("Copy");
+    let path = Path::new(v);
+
+    let trait_def = TraitDef {
+        span: span,
+        attributes: Vec::new(),
+        path: path,
+        additional_bounds: Vec::new(),
+        generics: LifetimeBounds::empty(),
+        is_unsafe: false,
+        methods: Vec::new(),
+        associated_types: Vec::new(),
+    };
+
+    trait_def.expand(cx, mitem, item, push);
+}
diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs
new file mode 100644
index 00000000000..1825c3d347e
--- /dev/null
+++ b/src/libsyntax_ext/deriving/clone.rs
@@ -0,0 +1,115 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use deriving::generic::*;
+use deriving::generic::ty::*;
+
+use syntax::ast::{MetaItem, Expr};
+use syntax::codemap::Span;
+use syntax::ext::base::{ExtCtxt, Annotatable};
+use syntax::ext::build::AstBuilder;
+use syntax::parse::token::InternedString;
+use syntax::ptr::P;
+
+pub fn expand_deriving_clone(cx: &mut ExtCtxt,
+                             span: Span,
+                             mitem: &MetaItem,
+                             item: &Annotatable,
+                             push: &mut FnMut(Annotatable))
+{
+    let inline = cx.meta_word(span, InternedString::new("inline"));
+    let attrs = vec!(cx.attribute(span, inline));
+    let trait_def = TraitDef {
+        span: span,
+        attributes: Vec::new(),
+        path: path_std!(cx, core::clone::Clone),
+        additional_bounds: Vec::new(),
+        generics: LifetimeBounds::empty(),
+        is_unsafe: false,
+        methods: vec!(
+            MethodDef {
+                name: "clone",
+                generics: LifetimeBounds::empty(),
+                explicit_self: borrowed_explicit_self(),
+                args: Vec::new(),
+                ret_ty: Self_,
+                attributes: attrs,
+                is_unsafe: false,
+                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
+                    cs_clone("Clone", c, s, sub)
+                })),
+            }
+        ),
+        associated_types: Vec::new(),
+    };
+
+    trait_def.expand(cx, mitem, item, push)
+}
+
+fn cs_clone(
+    name: &str,
+    cx: &mut ExtCtxt, trait_span: Span,
+    substr: &Substructure) -> P<Expr> {
+    let ctor_path;
+    let all_fields;
+    let fn_path = cx.std_path(&["clone", "Clone", "clone"]);
+    let subcall = |field: &FieldInfo| {
+        let args = vec![cx.expr_addr_of(field.span, field.self_.clone())];
+
+        cx.expr_call_global(field.span, fn_path.clone(), args)
+    };
+
+    match *substr.fields {
+        Struct(ref af) => {
+            ctor_path = cx.path(trait_span, vec![substr.type_ident]);
+            all_fields = af;
+        }
+        EnumMatching(_, variant, ref af) => {
+            ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.node.name]);
+            all_fields = af;
+        },
+        EnumNonMatchingCollapsed (..) => {
+            cx.span_bug(trait_span,
+                        &format!("non-matching enum variants in \
+                                 `derive({})`", name))
+        }
+        StaticEnum(..) | StaticStruct(..) => {
+            cx.span_bug(trait_span,
+                        &format!("static method in `derive({})`", name))
+        }
+    }
+
+    if !all_fields.is_empty() && all_fields[0].name.is_none() {
+        // enum-like
+        let subcalls = all_fields.iter().map(subcall).collect();
+        let path = cx.expr_path(ctor_path);
+        cx.expr_call(trait_span, path, subcalls)
+    } else {
+        // struct-like
+        let fields = all_fields.iter().map(|field| {
+            let ident = match field.name {
+                Some(i) => i,
+                None => {
+                    cx.span_bug(trait_span,
+                                &format!("unnamed field in normal struct in \
+                                         `derive({})`", name))
+                }
+            };
+            cx.field_imm(field.span, ident, subcall(field))
+        }).collect::<Vec<_>>();
+
+        if fields.is_empty() {
+            // no fields, so construct like `None`
+            cx.expr_path(ctor_path)
+        } else {
+            cx.expr_struct(trait_span, ctor_path, fields)
+        }
+    }
+}
diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs
new file mode 100644
index 00000000000..1b855c56a48
--- /dev/null
+++ b/src/libsyntax_ext/deriving/cmp/eq.rs
@@ -0,0 +1,73 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use deriving::generic::*;
+use deriving::generic::ty::*;
+
+use syntax::ast::{MetaItem, Expr};
+use syntax::codemap::Span;
+use syntax::ext::base::{ExtCtxt, Annotatable};
+use syntax::ext::build::AstBuilder;
+use syntax::parse::token::InternedString;
+use syntax::ptr::P;
+
+pub fn expand_deriving_eq(cx: &mut ExtCtxt,
+                          span: Span,
+                          mitem: &MetaItem,
+                          item: &Annotatable,
+                          push: &mut FnMut(Annotatable))
+{
+    fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
+        cs_same_method(
+            |cx, span, exprs| {
+                // create `a.<method>(); b.<method>(); c.<method>(); ...`
+                // (where method is `assert_receiver_is_total_eq`)
+                let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect();
+                let block = cx.block(span, stmts, None);
+                cx.expr_block(block)
+            },
+            Box::new(|cx, sp, _, _| {
+                cx.span_bug(sp, "non matching enums in derive(Eq)?") }),
+            cx,
+            span,
+            substr
+        )
+    }
+
+    let inline = cx.meta_word(span, InternedString::new("inline"));
+    let hidden = cx.meta_word(span, InternedString::new("hidden"));
+    let doc = cx.meta_list(span, InternedString::new("doc"), vec!(hidden));
+    let attrs = vec!(cx.attribute(span, inline),
+                     cx.attribute(span, doc));
+    let trait_def = TraitDef {
+        span: span,
+        attributes: Vec::new(),
+        path: path_std!(cx, core::cmp::Eq),
+        additional_bounds: Vec::new(),
+        generics: LifetimeBounds::empty(),
+        is_unsafe: false,
+        methods: vec!(
+            MethodDef {
+                name: "assert_receiver_is_total_eq",
+                generics: LifetimeBounds::empty(),
+                explicit_self: borrowed_explicit_self(),
+                args: vec!(),
+                ret_ty: nil_ty(),
+                attributes: attrs,
+                is_unsafe: false,
+                combine_substructure: combine_substructure(Box::new(|a, b, c| {
+                    cs_total_eq_assert(a, b, c)
+                }))
+            }
+        ),
+        associated_types: Vec::new(),
+    };
+    trait_def.expand(cx, mitem, item, push)
+}
diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs
new file mode 100644
index 00000000000..95a5d184d0e
--- /dev/null
+++ b/src/libsyntax_ext/deriving/cmp/ord.rs
@@ -0,0 +1,136 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use deriving::generic::*;
+use deriving::generic::ty::*;
+
+use syntax::ast;
+use syntax::ast::{MetaItem, Expr};
+use syntax::codemap::Span;
+use syntax::ext::base::{ExtCtxt, Annotatable};
+use syntax::ext::build::AstBuilder;
+use syntax::parse::token::InternedString;
+use syntax::ptr::P;
+
+pub fn expand_deriving_ord(cx: &mut ExtCtxt,
+                           span: Span,
+                           mitem: &MetaItem,
+                           item: &Annotatable,
+                           push: &mut FnMut(Annotatable))
+{
+    let inline = cx.meta_word(span, InternedString::new("inline"));
+    let attrs = vec!(cx.attribute(span, inline));
+    let trait_def = TraitDef {
+        span: span,
+        attributes: Vec::new(),
+        path: path_std!(cx, core::cmp::Ord),
+        additional_bounds: Vec::new(),
+        generics: LifetimeBounds::empty(),
+        is_unsafe: false,
+        methods: vec!(
+            MethodDef {
+                name: "cmp",
+                generics: LifetimeBounds::empty(),
+                explicit_self: borrowed_explicit_self(),
+                args: vec!(borrowed_self()),
+                ret_ty: Literal(path_std!(cx, core::cmp::Ordering)),
+                attributes: attrs,
+                is_unsafe: false,
+                combine_substructure: combine_substructure(Box::new(|a, b, c| {
+                    cs_cmp(a, b, c)
+                })),
+            }
+        ),
+        associated_types: Vec::new(),
+    };
+
+    trait_def.expand(cx, mitem, item, push)
+}
+
+
+pub fn ordering_collapsed(cx: &mut ExtCtxt,
+                          span: Span,
+                          self_arg_tags: &[ast::Ident]) -> P<ast::Expr> {
+    let lft = cx.expr_ident(span, self_arg_tags[0]);
+    let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
+    cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt])
+}
+
+pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
+              substr: &Substructure) -> P<Expr> {
+    let test_id = cx.ident_of("__test");
+    let equals_path = cx.path_global(span,
+                                     cx.std_path(&["cmp", "Ordering", "Equal"]));
+
+    let cmp_path = cx.std_path(&["cmp", "Ord", "cmp"]);
+
+    /*
+    Builds:
+
+    let __test = ::std::cmp::Ord::cmp(&self_field1, &other_field1);
+    if other == ::std::cmp::Ordering::Equal {
+        let __test = ::std::cmp::Ord::cmp(&self_field2, &other_field2);
+        if __test == ::std::cmp::Ordering::Equal {
+            ...
+        } else {
+            __test
+        }
+    } else {
+        __test
+    }
+
+    FIXME #6449: These `if`s could/should be `match`es.
+    */
+    cs_fold(
+        // foldr nests the if-elses correctly, leaving the first field
+        // as the outermost one, and the last as the innermost.
+        false,
+        |cx, span, old, self_f, other_fs| {
+            // let __test = new;
+            // if __test == ::std::cmp::Ordering::Equal {
+            //    old
+            // } else {
+            //    __test
+            // }
+
+            let new = {
+                let other_f = match (other_fs.len(), other_fs.get(0)) {
+                    (1, Some(o_f)) => o_f,
+                    _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
+                };
+
+                let args = vec![
+                    cx.expr_addr_of(span, self_f),
+                    cx.expr_addr_of(span, other_f.clone()),
+                ];
+
+                cx.expr_call_global(span, cmp_path.clone(), args)
+            };
+
+            let assign = cx.stmt_let(span, false, test_id, new);
+
+            let cond = cx.expr_binary(span, ast::BiEq,
+                                      cx.expr_ident(span, test_id),
+                                      cx.expr_path(equals_path.clone()));
+            let if_ = cx.expr_if(span,
+                                 cond,
+                                 old, Some(cx.expr_ident(span, test_id)));
+            cx.expr_block(cx.block(span, vec!(assign), Some(if_)))
+        },
+        cx.expr_path(equals_path.clone()),
+        Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
+            if self_args.len() != 2 {
+                cx.span_bug(span, "not exactly 2 arguments in `derives(Ord)`")
+            } else {
+                ordering_collapsed(cx, span, tag_tuple)
+            }
+        }),
+        cx, span, substr)
+}
diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs
new file mode 100644
index 00000000000..29be5a7ddc3
--- /dev/null
+++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs
@@ -0,0 +1,97 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use deriving::generic::*;
+use deriving::generic::ty::*;
+
+use syntax::ast::{MetaItem, Expr, self};
+use syntax::codemap::Span;
+use syntax::ext::base::{ExtCtxt, Annotatable};
+use syntax::ext::build::AstBuilder;
+use syntax::parse::token::InternedString;
+use syntax::ptr::P;
+
+pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt,
+                                  span: Span,
+                                  mitem: &MetaItem,
+                                  item: &Annotatable,
+                                  push: &mut FnMut(Annotatable))
+{
+    // structures are equal if all fields are equal, and non equal, if
+    // any fields are not equal or if the enum variants are different
+    fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
+        cs_fold(
+            true,  // use foldl
+            |cx, span, subexpr, self_f, other_fs| {
+                let other_f = match (other_fs.len(), other_fs.get(0)) {
+                    (1, Some(o_f)) => o_f,
+                    _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`")
+                };
+
+                let eq = cx.expr_binary(span, ast::BiEq, self_f, other_f.clone());
+
+                cx.expr_binary(span, ast::BiAnd, subexpr, eq)
+            },
+            cx.expr_bool(span, true),
+            Box::new(|cx, span, _, _| cx.expr_bool(span, false)),
+            cx, span, substr)
+    }
+    fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
+        cs_fold(
+            true,  // use foldl
+            |cx, span, subexpr, self_f, other_fs| {
+                let other_f = match (other_fs.len(), other_fs.get(0)) {
+                    (1, Some(o_f)) => o_f,
+                    _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`")
+                };
+
+                let eq = cx.expr_binary(span, ast::BiNe, self_f, other_f.clone());
+
+                cx.expr_binary(span, ast::BiOr, subexpr, eq)
+            },
+            cx.expr_bool(span, false),
+            Box::new(|cx, span, _, _| cx.expr_bool(span, true)),
+            cx, span, substr)
+    }
+
+    macro_rules! md {
+        ($name:expr, $f:ident) => { {
+            let inline = cx.meta_word(span, InternedString::new("inline"));
+            let attrs = vec!(cx.attribute(span, inline));
+            MethodDef {
+                name: $name,
+                generics: LifetimeBounds::empty(),
+                explicit_self: borrowed_explicit_self(),
+                args: vec!(borrowed_self()),
+                ret_ty: Literal(path_local!(bool)),
+                attributes: attrs,
+                is_unsafe: false,
+                combine_substructure: combine_substructure(Box::new(|a, b, c| {
+                    $f(a, b, c)
+                }))
+            }
+        } }
+    }
+
+    let trait_def = TraitDef {
+        span: span,
+        attributes: Vec::new(),
+        path: path_std!(cx, core::cmp::PartialEq),
+        additional_bounds: Vec::new(),
+        generics: LifetimeBounds::empty(),
+        is_unsafe: false,
+        methods: vec!(
+            md!("eq", cs_eq),
+            md!("ne", cs_ne)
+        ),
+        associated_types: Vec::new(),
+    };
+    trait_def.expand(cx, mitem, item, push)
+}
diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs
new file mode 100644
index 00000000000..bd825e5c8df
--- /dev/null
+++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs
@@ -0,0 +1,233 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use self::OrderingOp::*;
+
+use deriving::generic::*;
+use deriving::generic::ty::*;
+
+use syntax::ast;
+use syntax::ast::{MetaItem, Expr};
+use syntax::codemap::Span;
+use syntax::ext::base::{ExtCtxt, Annotatable};
+use syntax::ext::build::AstBuilder;
+use syntax::parse::token::InternedString;
+use syntax::ptr::P;
+
+pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
+                                   span: Span,
+                                   mitem: &MetaItem,
+                                   item: &Annotatable,
+                                   push: &mut FnMut(Annotatable))
+{
+    macro_rules! md {
+        ($name:expr, $op:expr, $equal:expr) => { {
+            let inline = cx.meta_word(span, InternedString::new("inline"));
+            let attrs = vec!(cx.attribute(span, inline));
+            MethodDef {
+                name: $name,
+                generics: LifetimeBounds::empty(),
+                explicit_self: borrowed_explicit_self(),
+                args: vec!(borrowed_self()),
+                ret_ty: Literal(path_local!(bool)),
+                attributes: attrs,
+                is_unsafe: false,
+                combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
+                    cs_op($op, $equal, cx, span, substr)
+                }))
+            }
+        } }
+    }
+
+    let ordering_ty = Literal(path_std!(cx, core::cmp::Ordering));
+    let ret_ty = Literal(Path::new_(pathvec_std!(cx, core::option::Option),
+                                    None,
+                                    vec![Box::new(ordering_ty)],
+                                    true));
+
+    let inline = cx.meta_word(span, InternedString::new("inline"));
+    let attrs = vec!(cx.attribute(span, inline));
+
+    let partial_cmp_def = MethodDef {
+        name: "partial_cmp",
+        generics: LifetimeBounds::empty(),
+        explicit_self: borrowed_explicit_self(),
+        args: vec![borrowed_self()],
+        ret_ty: ret_ty,
+        attributes: attrs,
+        is_unsafe: false,
+        combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
+            cs_partial_cmp(cx, span, substr)
+        }))
+    };
+
+    let trait_def = TraitDef {
+        span: span,
+        attributes: vec![],
+        path: path_std!(cx, core::cmp::PartialOrd),
+        additional_bounds: vec![],
+        generics: LifetimeBounds::empty(),
+        is_unsafe: false,
+        methods: vec![
+            partial_cmp_def,
+            md!("lt", true, false),
+            md!("le", true, true),
+            md!("gt", false, false),
+            md!("ge", false, true)
+        ],
+        associated_types: Vec::new(),
+    };
+    trait_def.expand(cx, mitem, item, push)
+}
+
+#[derive(Copy, Clone)]
+pub enum OrderingOp {
+    PartialCmpOp, LtOp, LeOp, GtOp, GeOp,
+}
+
+pub fn some_ordering_collapsed(cx: &mut ExtCtxt,
+                               span: Span,
+                               op: OrderingOp,
+                               self_arg_tags: &[ast::Ident]) -> P<ast::Expr> {
+    let lft = cx.expr_ident(span, self_arg_tags[0]);
+    let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
+    let op_str = match op {
+        PartialCmpOp => "partial_cmp",
+        LtOp => "lt", LeOp => "le",
+        GtOp => "gt", GeOp => "ge",
+    };
+    cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt])
+}
+
+pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span,
+              substr: &Substructure) -> P<Expr> {
+    let test_id = cx.ident_of("__test");
+    let ordering = cx.path_global(span,
+                                  cx.std_path(&["cmp", "Ordering", "Equal"]));
+    let ordering = cx.expr_path(ordering);
+    let equals_expr = cx.expr_some(span, ordering);
+
+    let partial_cmp_path = cx.std_path(&["cmp", "PartialOrd", "partial_cmp"]);
+
+    /*
+    Builds:
+
+    let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1);
+    if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) {
+        let __test = ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2);
+        if __test == ::std::option::Option::Some(::std::cmp::Ordering::Equal) {
+            ...
+        } else {
+            __test
+        }
+    } else {
+        __test
+    }
+
+    FIXME #6449: These `if`s could/should be `match`es.
+    */
+    cs_fold(
+        // foldr nests the if-elses correctly, leaving the first field
+        // as the outermost one, and the last as the innermost.
+        false,
+        |cx, span, old, self_f, other_fs| {
+            // let __test = new;
+            // if __test == Some(::std::cmp::Ordering::Equal) {
+            //    old
+            // } else {
+            //    __test
+            // }
+
+            let new = {
+                let other_f = match (other_fs.len(), other_fs.get(0)) {
+                    (1, Some(o_f)) => o_f,
+                    _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
+                };
+
+                let args = vec![
+                    cx.expr_addr_of(span, self_f),
+                    cx.expr_addr_of(span, other_f.clone()),
+                ];
+
+                cx.expr_call_global(span, partial_cmp_path.clone(), args)
+            };
+
+            let assign = cx.stmt_let(span, false, test_id, new);
+
+            let cond = cx.expr_binary(span, ast::BiEq,
+                                      cx.expr_ident(span, test_id),
+                                      equals_expr.clone());
+            let if_ = cx.expr_if(span,
+                                 cond,
+                                 old, Some(cx.expr_ident(span, test_id)));
+            cx.expr_block(cx.block(span, vec!(assign), Some(if_)))
+        },
+        equals_expr.clone(),
+        Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
+            if self_args.len() != 2 {
+                cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
+            } else {
+                some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple)
+            }
+        }),
+        cx, span, substr)
+}
+
+/// Strict inequality.
+fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt,
+         span: Span, substr: &Substructure) -> P<Expr> {
+    let op = if less {ast::BiLt} else {ast::BiGt};
+    cs_fold(
+        false, // need foldr,
+        |cx, span, subexpr, self_f, other_fs| {
+            /*
+            build up a series of chain ||'s and &&'s from the inside
+            out (hence foldr) to get lexical ordering, i.e. for op ==
+            `ast::lt`
+
+            ```
+            self.f1 < other.f1 || (!(other.f1 < self.f1) &&
+                (self.f2 < other.f2 || (!(other.f2 < self.f2) &&
+                    (false)
+                ))
+            )
+            ```
+
+            The optimiser should remove the redundancy. We explicitly
+            get use the binops to avoid auto-deref dereferencing too many
+            layers of pointers, if the type includes pointers.
+            */
+            let other_f = match (other_fs.len(), other_fs.get(0)) {
+                (1, Some(o_f)) => o_f,
+                _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
+            };
+
+            let cmp = cx.expr_binary(span, op, self_f.clone(), other_f.clone());
+
+            let not_cmp = cx.expr_unary(span, ast::UnNot,
+                                        cx.expr_binary(span, op, other_f.clone(), self_f));
+
+            let and = cx.expr_binary(span, ast::BiAnd, not_cmp, subexpr);
+            cx.expr_binary(span, ast::BiOr, cmp, and)
+        },
+        cx.expr_bool(span, equal),
+        Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
+            if self_args.len() != 2 {
+                cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
+            } else {
+                let op = match (less, equal) {
+                    (true,  true) => LeOp, (true,  false) => LtOp,
+                    (false, true) => GeOp, (false, false) => GtOp,
+                };
+                some_ordering_collapsed(cx, span, op, tag_tuple)
+            }
+        }),
+        cx, span, substr)
+}
diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs
new file mode 100644
index 00000000000..ed3f764c1d2
--- /dev/null
+++ b/src/libsyntax_ext/deriving/debug.rs
@@ -0,0 +1,156 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use deriving::generic::*;
+use deriving::generic::ty::*;
+
+use syntax::ast;
+use syntax::ast::{MetaItem, Expr};
+use syntax::codemap::{Span, respan};
+use syntax::ext::base::{ExtCtxt, Annotatable};
+use syntax::ext::build::AstBuilder;
+use syntax::parse::token;
+use syntax::ptr::P;
+
+pub fn expand_deriving_debug(cx: &mut ExtCtxt,
+                            span: Span,
+                            mitem: &MetaItem,
+                            item: &Annotatable,
+                            push: &mut FnMut(Annotatable))
+{
+    // &mut ::std::fmt::Formatter
+    let fmtr = Ptr(Box::new(Literal(path_std!(cx, core::fmt::Formatter))),
+                   Borrowed(None, ast::MutMutable));
+
+    let trait_def = TraitDef {
+        span: span,
+        attributes: Vec::new(),
+        path: path_std!(cx, core::fmt::Debug),
+        additional_bounds: Vec::new(),
+        generics: LifetimeBounds::empty(),
+        is_unsafe: false,
+        methods: vec![
+            MethodDef {
+                name: "fmt",
+                generics: LifetimeBounds::empty(),
+                explicit_self: borrowed_explicit_self(),
+                args: vec!(fmtr),
+                ret_ty: Literal(path_std!(cx, core::fmt::Result)),
+                attributes: Vec::new(),
+                is_unsafe: false,
+                combine_substructure: combine_substructure(Box::new(|a, b, c| {
+                    show_substructure(a, b, c)
+                }))
+            }
+        ],
+        associated_types: Vec::new(),
+    };
+    trait_def.expand(cx, mitem, item, push)
+}
+
+/// We use the debug builders to do the heavy lifting here
+fn show_substructure(cx: &mut ExtCtxt, span: Span,
+                     substr: &Substructure) -> P<Expr> {
+    // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
+    // or fmt.debug_tuple(<name>).field(&<fieldval>)....build()
+    // based on the "shape".
+    let ident = match *substr.fields {
+        Struct(_) => substr.type_ident,
+        EnumMatching(_, v, _) => v.node.name,
+        EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
+            cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
+        }
+    };
+
+    // We want to make sure we have the expn_id set so that we can use unstable methods
+    let span = Span { expn_id: cx.backtrace(), .. span };
+    let name = cx.expr_lit(span, ast::Lit_::LitStr(ident.name.as_str(),
+                                                   ast::StrStyle::CookedStr));
+    let builder = token::str_to_ident("builder");
+    let builder_expr = cx.expr_ident(span, builder.clone());
+
+    let fmt = substr.nonself_args[0].clone();
+
+    let stmts = match *substr.fields {
+        Struct(ref fields) | EnumMatching(_, _, ref fields) => {
+            let mut stmts = vec![];
+            if fields.is_empty() || fields[0].name.is_none() {
+                // tuple struct/"normal" variant
+                let expr = cx.expr_method_call(span,
+                                               fmt,
+                                               token::str_to_ident("debug_tuple"),
+                                               vec![name]);
+                stmts.push(cx.stmt_let(span, true, builder, expr));
+
+                for field in fields {
+                    // Use double indirection to make sure this works for unsized types
+                    let field = cx.expr_addr_of(field.span, field.self_.clone());
+                    let field = cx.expr_addr_of(field.span, field);
+
+                    let expr = cx.expr_method_call(span,
+                                                   builder_expr.clone(),
+                                                   token::str_to_ident("field"),
+                                                   vec![field]);
+
+                    // Use `let _ = expr;` to avoid triggering the
+                    // unused_results lint.
+                    stmts.push(stmt_let_undescore(cx, span, expr));
+                }
+            } else {
+                // normal struct/struct variant
+                let expr = cx.expr_method_call(span,
+                                               fmt,
+                                               token::str_to_ident("debug_struct"),
+                                               vec![name]);
+                stmts.push(cx.stmt_let(span, true, builder, expr));
+
+                for field in fields {
+                    let name = cx.expr_lit(field.span, ast::Lit_::LitStr(
+                            field.name.unwrap().name.as_str(),
+                            ast::StrStyle::CookedStr));
+
+                    // Use double indirection to make sure this works for unsized types
+                    let field = cx.expr_addr_of(field.span, field.self_.clone());
+                    let field = cx.expr_addr_of(field.span, field);
+                    let expr = cx.expr_method_call(span,
+                                                   builder_expr.clone(),
+                                                   token::str_to_ident("field"),
+                                                   vec![name, field]);
+                    stmts.push(stmt_let_undescore(cx, span, expr));
+                }
+            }
+            stmts
+        }
+        _ => unreachable!()
+    };
+
+    let expr = cx.expr_method_call(span,
+                                   builder_expr,
+                                   token::str_to_ident("finish"),
+                                   vec![]);
+
+    let block = cx.block(span, stmts, Some(expr));
+    cx.expr_block(block)
+}
+
+fn stmt_let_undescore(cx: &mut ExtCtxt,
+                      sp: Span,
+                      expr: P<ast::Expr>) -> P<ast::Stmt> {
+    let local = P(ast::Local {
+        pat: cx.pat_wild(sp),
+        ty: None,
+        init: Some(expr),
+        id: ast::DUMMY_NODE_ID,
+        span: sp,
+        attrs: None,
+    });
+    let decl = respan(sp, ast::DeclLocal(local));
+    P(respan(sp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)))
+}
diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs
new file mode 100644
index 00000000000..4ea4f04623a
--- /dev/null
+++ b/src/libsyntax_ext/deriving/decodable.rs
@@ -0,0 +1,224 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The compiler code necessary for `#[derive(Decodable)]`. See encodable.rs for more.
+
+use deriving::generic::*;
+use deriving::generic::ty::*;
+
+use syntax::ast;
+use syntax::ast::{MetaItem, Expr, MutMutable};
+use syntax::codemap::Span;
+use syntax::ext::base::{ExtCtxt, Annotatable};
+use syntax::ext::build::AstBuilder;
+use syntax::parse::token::InternedString;
+use syntax::parse::token;
+use syntax::ptr::P;
+
+pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt,
+                                       span: Span,
+                                       mitem: &MetaItem,
+                                       item: &Annotatable,
+                                       push: &mut FnMut(Annotatable))
+{
+    expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize")
+}
+
+pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
+                                 span: Span,
+                                 mitem: &MetaItem,
+                                 item: &Annotatable,
+                                 push: &mut FnMut(Annotatable))
+{
+    expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
+}
+
+fn expand_deriving_decodable_imp(cx: &mut ExtCtxt,
+                                 span: Span,
+                                 mitem: &MetaItem,
+                                 item: &Annotatable,
+                                 push: &mut FnMut(Annotatable),
+                                 krate: &'static str)
+{
+    if cx.crate_root != Some("std") {
+        // FIXME(#21880): lift this requirement.
+        cx.span_err(span, "this trait cannot be derived with #![no_std] \
+                           or #![no_core]");
+        return
+    }
+
+    let trait_def = TraitDef {
+        span: span,
+        attributes: Vec::new(),
+        path: Path::new_(vec!(krate, "Decodable"), None, vec!(), true),
+        additional_bounds: Vec::new(),
+        generics: LifetimeBounds::empty(),
+        is_unsafe: false,
+        methods: vec!(
+            MethodDef {
+                name: "decode",
+                generics: LifetimeBounds {
+                    lifetimes: Vec::new(),
+                    bounds: vec!(("__D", vec!(Path::new_(
+                                    vec!(krate, "Decoder"), None,
+                                    vec!(), true))))
+                },
+                explicit_self: None,
+                args: vec!(Ptr(Box::new(Literal(Path::new_local("__D"))),
+                            Borrowed(None, MutMutable))),
+                ret_ty: Literal(Path::new_(
+                    pathvec_std!(cx, core::result::Result),
+                    None,
+                    vec!(Box::new(Self_), Box::new(Literal(Path::new_(
+                        vec!["__D", "Error"], None, vec![], false
+                    )))),
+                    true
+                )),
+                attributes: Vec::new(),
+                is_unsafe: false,
+                combine_substructure: combine_substructure(Box::new(|a, b, c| {
+                    decodable_substructure(a, b, c, krate)
+                })),
+            }
+        ),
+        associated_types: Vec::new(),
+    };
+
+    trait_def.expand(cx, mitem, item, push)
+}
+
+fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
+                          substr: &Substructure,
+                          krate: &str) -> P<Expr> {
+    let decoder = substr.nonself_args[0].clone();
+    let recurse = vec!(cx.ident_of(krate),
+                    cx.ident_of("Decodable"),
+                    cx.ident_of("decode"));
+    let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse));
+    // throw an underscore in front to suppress unused variable warnings
+    let blkarg = cx.ident_of("_d");
+    let blkdecoder = cx.expr_ident(trait_span, blkarg);
+
+    return match *substr.fields {
+        StaticStruct(_, ref summary) => {
+            let nfields = match *summary {
+                Unnamed(ref fields) => fields.len(),
+                Named(ref fields) => fields.len()
+            };
+            let read_struct_field = cx.ident_of("read_struct_field");
+
+            let path = cx.path_ident(trait_span, substr.type_ident);
+            let result = decode_static_fields(cx,
+                                              trait_span,
+                                              path,
+                                              summary,
+                                              |cx, span, name, field| {
+                cx.expr_try(span,
+                    cx.expr_method_call(span, blkdecoder.clone(), read_struct_field,
+                                        vec!(cx.expr_str(span, name),
+                                          cx.expr_usize(span, field),
+                                          exprdecode.clone())))
+            });
+            let result = cx.expr_ok(trait_span, result);
+            cx.expr_method_call(trait_span,
+                                decoder,
+                                cx.ident_of("read_struct"),
+                                vec!(
+                cx.expr_str(trait_span, substr.type_ident.name.as_str()),
+                cx.expr_usize(trait_span, nfields),
+                cx.lambda_expr_1(trait_span, result, blkarg)
+            ))
+        }
+        StaticEnum(_, ref fields) => {
+            let variant = cx.ident_of("i");
+
+            let mut arms = Vec::new();
+            let mut variants = Vec::new();
+            let rvariant_arg = cx.ident_of("read_enum_variant_arg");
+
+            for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() {
+                variants.push(cx.expr_str(v_span, ident.name.as_str()));
+
+                let path = cx.path(trait_span, vec![substr.type_ident, ident]);
+                let decoded = decode_static_fields(cx,
+                                                   v_span,
+                                                   path,
+                                                   parts,
+                                                   |cx, span, _, field| {
+                    let idx = cx.expr_usize(span, field);
+                    cx.expr_try(span,
+                        cx.expr_method_call(span, blkdecoder.clone(), rvariant_arg,
+                                            vec!(idx, exprdecode.clone())))
+                });
+
+                arms.push(cx.arm(v_span,
+                                 vec!(cx.pat_lit(v_span, cx.expr_usize(v_span, i))),
+                                 decoded));
+            }
+
+            arms.push(cx.arm_unreachable(trait_span));
+
+            let result = cx.expr_ok(trait_span,
+                                    cx.expr_match(trait_span,
+                                                  cx.expr_ident(trait_span, variant), arms));
+            let lambda = cx.lambda_expr(trait_span, vec!(blkarg, variant), result);
+            let variant_vec = cx.expr_vec(trait_span, variants);
+            let variant_vec = cx.expr_addr_of(trait_span, variant_vec);
+            let result = cx.expr_method_call(trait_span, blkdecoder,
+                                             cx.ident_of("read_enum_variant"),
+                                             vec!(variant_vec, lambda));
+            cx.expr_method_call(trait_span,
+                                decoder,
+                                cx.ident_of("read_enum"),
+                                vec!(
+                cx.expr_str(trait_span, substr.type_ident.name.as_str()),
+                cx.lambda_expr_1(trait_span, result, blkarg)
+            ))
+        }
+        _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)")
+    };
+}
+
+/// Create a decoder for a single enum variant/struct:
+/// - `outer_pat_path` is the path to this enum variant/struct
+/// - `getarg` should retrieve the `usize`-th field with name `@str`.
+fn decode_static_fields<F>(cx: &mut ExtCtxt,
+                           trait_span: Span,
+                           outer_pat_path: ast::Path,
+                           fields: &StaticFields,
+                           mut getarg: F)
+                           -> P<Expr> where
+    F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P<Expr>,
+{
+    match *fields {
+        Unnamed(ref fields) => {
+            let path_expr = cx.expr_path(outer_pat_path);
+            if fields.is_empty() {
+                path_expr
+            } else {
+                let fields = fields.iter().enumerate().map(|(i, &span)| {
+                    getarg(cx, span,
+                           token::intern_and_get_ident(&format!("_field{}", i)),
+                           i)
+                }).collect();
+
+                cx.expr_call(trait_span, path_expr, fields)
+            }
+        }
+        Named(ref fields) => {
+            // use the field's span to get nicer error messages.
+            let fields = fields.iter().enumerate().map(|(i, &(ident, span))| {
+                let arg = getarg(cx, span, ident.name.as_str(), i);
+                cx.field_imm(span, ident, arg)
+            }).collect();
+            cx.expr_struct(trait_span, outer_pat_path, fields)
+        }
+    }
+}
diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs
new file mode 100644
index 00000000000..bee63a98c25
--- /dev/null
+++ b/src/libsyntax_ext/deriving/default.rs
@@ -0,0 +1,85 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use deriving::generic::*;
+use deriving::generic::ty::*;
+
+use syntax::ast::{MetaItem, Expr};
+use syntax::codemap::Span;
+use syntax::ext::base::{ExtCtxt, Annotatable};
+use syntax::ext::build::AstBuilder;
+use syntax::parse::token::InternedString;
+use syntax::ptr::P;
+
+pub fn expand_deriving_default(cx: &mut ExtCtxt,
+                               span: Span,
+                               mitem: &MetaItem,
+                               item: &Annotatable,
+                               push: &mut FnMut(Annotatable))
+{
+    let inline = cx.meta_word(span, InternedString::new("inline"));
+    let attrs = vec!(cx.attribute(span, inline));
+    let trait_def = TraitDef {
+        span: span,
+        attributes: Vec::new(),
+        path: path_std!(cx, core::default::Default),
+        additional_bounds: Vec::new(),
+        generics: LifetimeBounds::empty(),
+        is_unsafe: false,
+        methods: vec!(
+            MethodDef {
+                name: "default",
+                generics: LifetimeBounds::empty(),
+                explicit_self: None,
+                args: Vec::new(),
+                ret_ty: Self_,
+                attributes: attrs,
+                is_unsafe: false,
+                combine_substructure: combine_substructure(Box::new(|a, b, c| {
+                    default_substructure(a, b, c)
+                }))
+            }
+        ),
+        associated_types: Vec::new(),
+    };
+    trait_def.expand(cx, mitem, item, push)
+}
+
+fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
+    let default_ident = cx.std_path(&["default", "Default", "default"]);
+    let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new());
+
+    return match *substr.fields {
+        StaticStruct(_, ref summary) => {
+            match *summary {
+                Unnamed(ref fields) => {
+                    if fields.is_empty() {
+                        cx.expr_ident(trait_span, substr.type_ident)
+                    } else {
+                        let exprs = fields.iter().map(|sp| default_call(*sp)).collect();
+                        cx.expr_call_ident(trait_span, substr.type_ident, exprs)
+                    }
+                }
+                Named(ref fields) => {
+                    let default_fields = fields.iter().map(|&(ident, span)| {
+                        cx.field_imm(span, ident, default_call(span))
+                    }).collect();
+                    cx.expr_struct_ident(trait_span, substr.type_ident, default_fields)
+                }
+            }
+        }
+        StaticEnum(..) => {
+            cx.span_err(trait_span, "`Default` cannot be derived for enums, only structs");
+            // let compilation continue
+            cx.expr_usize(trait_span, 0)
+        }
+        _ => cx.span_bug(trait_span, "Non-static method in `derive(Default)`")
+    };
+}
diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs
new file mode 100644
index 00000000000..02747d38c00
--- /dev/null
+++ b/src/libsyntax_ext/deriving/encodable.rs
@@ -0,0 +1,289 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The compiler code necessary to implement the `#[derive(Encodable)]`
+//! (and `Decodable`, in decodable.rs) extension.  The idea here is that
+//! type-defining items may be tagged with `#[derive(Encodable, Decodable)]`.
+//!
+//! For example, a type like:
+//!
+//! ```ignore
+//! #[derive(Encodable, Decodable)]
+//! struct Node { id: usize }
+//! ```
+//!
+//! would generate two implementations like:
+//!
+//! ```ignore
+//! impl<S: Encoder<E>, E> Encodable<S, E> for Node {
+//!     fn encode(&self, s: &mut S) -> Result<(), E> {
+//!         s.emit_struct("Node", 1, |this| {
+//!             this.emit_struct_field("id", 0, |this| {
+//!                 Encodable::encode(&self.id, this)
+//!                 /* this.emit_usize(self.id) can also be used */
+//!             })
+//!         })
+//!     }
+//! }
+//!
+//! impl<D: Decoder<E>, E> Decodable<D, E> for Node {
+//!     fn decode(d: &mut D) -> Result<Node, E> {
+//!         d.read_struct("Node", 1, |this| {
+//!             match this.read_struct_field("id", 0, |this| Decodable::decode(this)) {
+//!                 Ok(id) => Ok(Node { id: id }),
+//!                 Err(e) => Err(e),
+//!             }
+//!         })
+//!     }
+//! }
+//! ```
+//!
+//! Other interesting scenarios are when the item has type parameters or
+//! references other non-built-in types.  A type definition like:
+//!
+//! ```ignore
+//! #[derive(Encodable, Decodable)]
+//! struct Spanned<T> { node: T, span: Span }
+//! ```
+//!
+//! would yield functions like:
+//!
+//! ```ignore
+//! impl<
+//!     S: Encoder<E>,
+//!     E,
+//!     T: Encodable<S, E>
+//! > Encodable<S, E> for Spanned<T> {
+//!     fn encode(&self, s: &mut S) -> Result<(), E> {
+//!         s.emit_struct("Spanned", 2, |this| {
+//!             this.emit_struct_field("node", 0, |this| self.node.encode(this))
+//!                 .unwrap();
+//!             this.emit_struct_field("span", 1, |this| self.span.encode(this))
+//!         })
+//!     }
+//! }
+//!
+//! impl<
+//!     D: Decoder<E>,
+//!     E,
+//!     T: Decodable<D, E>
+//! > Decodable<D, E> for Spanned<T> {
+//!     fn decode(d: &mut D) -> Result<Spanned<T>, E> {
+//!         d.read_struct("Spanned", 2, |this| {
+//!             Ok(Spanned {
+//!                 node: this.read_struct_field("node", 0, |this| Decodable::decode(this))
+//!                     .unwrap(),
+//!                 span: this.read_struct_field("span", 1, |this| Decodable::decode(this))
+//!                     .unwrap(),
+//!             })
+//!         })
+//!     }
+//! }
+//! ```
+
+use deriving::generic::*;
+use deriving::generic::ty::*;
+
+use syntax::ast::{MetaItem, Expr, ExprRet, MutMutable};
+use syntax::codemap::Span;
+use syntax::ext::base::{ExtCtxt,Annotatable};
+use syntax::ext::build::AstBuilder;
+use syntax::parse::token;
+use syntax::ptr::P;
+
+pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt,
+                                       span: Span,
+                                       mitem: &MetaItem,
+                                       item: &Annotatable,
+                                       push: &mut FnMut(Annotatable))
+{
+    expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize")
+}
+
+pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
+                                 span: Span,
+                                 mitem: &MetaItem,
+                                 item: &Annotatable,
+                                 push: &mut FnMut(Annotatable))
+{
+    expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
+}
+
+fn expand_deriving_encodable_imp(cx: &mut ExtCtxt,
+                                 span: Span,
+                                 mitem: &MetaItem,
+                                 item: &Annotatable,
+                                 push: &mut FnMut(Annotatable),
+                                 krate: &'static str)
+{
+    if cx.crate_root != Some("std") {
+        // FIXME(#21880): lift this requirement.
+        cx.span_err(span, "this trait cannot be derived with #![no_std] \
+                           or #![no_core]");
+        return;
+    }
+
+    let trait_def = TraitDef {
+        span: span,
+        attributes: Vec::new(),
+        path: Path::new_(vec!(krate, "Encodable"), None, vec!(), true),
+        additional_bounds: Vec::new(),
+        generics: LifetimeBounds::empty(),
+        is_unsafe: false,
+        methods: vec!(
+            MethodDef {
+                name: "encode",
+                generics: LifetimeBounds {
+                    lifetimes: Vec::new(),
+                    bounds: vec!(("__S", vec!(Path::new_(
+                                    vec!(krate, "Encoder"), None,
+                                    vec!(), true))))
+                },
+                explicit_self: borrowed_explicit_self(),
+                args: vec!(Ptr(Box::new(Literal(Path::new_local("__S"))),
+                            Borrowed(None, MutMutable))),
+                ret_ty: Literal(Path::new_(
+                    pathvec_std!(cx, core::result::Result),
+                    None,
+                    vec!(Box::new(Tuple(Vec::new())), Box::new(Literal(Path::new_(
+                        vec!["__S", "Error"], None, vec![], false
+                    )))),
+                    true
+                )),
+                attributes: Vec::new(),
+                is_unsafe: false,
+                combine_substructure: combine_substructure(Box::new(|a, b, c| {
+                    encodable_substructure(a, b, c)
+                })),
+            }
+        ),
+        associated_types: Vec::new(),
+    };
+
+    trait_def.expand(cx, mitem, item, push)
+}
+
+fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
+                          substr: &Substructure) -> P<Expr> {
+    let encoder = substr.nonself_args[0].clone();
+    // throw an underscore in front to suppress unused variable warnings
+    let blkarg = cx.ident_of("_e");
+    let blkencoder = cx.expr_ident(trait_span, blkarg);
+    let encode = cx.ident_of("encode");
+
+    return match *substr.fields {
+        Struct(ref fields) => {
+            let emit_struct_field = cx.ident_of("emit_struct_field");
+            let mut stmts = Vec::new();
+            for (i, &FieldInfo {
+                    name,
+                    ref self_,
+                    span,
+                    ..
+                }) in fields.iter().enumerate() {
+                let name = match name {
+                    Some(id) => id.name.as_str(),
+                    None => {
+                        token::intern_and_get_ident(&format!("_field{}", i))
+                    }
+                };
+                let enc = cx.expr_method_call(span, self_.clone(),
+                                              encode, vec!(blkencoder.clone()));
+                let lambda = cx.lambda_expr_1(span, enc, blkarg);
+                let call = cx.expr_method_call(span, blkencoder.clone(),
+                                               emit_struct_field,
+                                               vec!(cx.expr_str(span, name),
+                                                 cx.expr_usize(span, i),
+                                                 lambda));
+
+                // last call doesn't need a try!
+                let last = fields.len() - 1;
+                let call = if i != last {
+                    cx.expr_try(span, call)
+                } else {
+                    cx.expr(span, ExprRet(Some(call)))
+                };
+                stmts.push(cx.stmt_expr(call));
+            }
+
+            // unit structs have no fields and need to return Ok()
+            if stmts.is_empty() {
+                let ret_ok = cx.expr(trait_span,
+                                     ExprRet(Some(cx.expr_ok(trait_span,
+                                                             cx.expr_tuple(trait_span, vec![])))));
+                stmts.push(cx.stmt_expr(ret_ok));
+            }
+
+            let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
+            cx.expr_method_call(trait_span,
+                                encoder,
+                                cx.ident_of("emit_struct"),
+                                vec!(
+                cx.expr_str(trait_span, substr.type_ident.name.as_str()),
+                cx.expr_usize(trait_span, fields.len()),
+                blk
+            ))
+        }
+
+        EnumMatching(idx, variant, ref fields) => {
+            // We're not generating an AST that the borrow checker is expecting,
+            // so we need to generate a unique local variable to take the
+            // mutable loan out on, otherwise we get conflicts which don't
+            // actually exist.
+            let me = cx.stmt_let(trait_span, false, blkarg, encoder);
+            let encoder = cx.expr_ident(trait_span, blkarg);
+            let emit_variant_arg = cx.ident_of("emit_enum_variant_arg");
+            let mut stmts = Vec::new();
+            if !fields.is_empty() {
+                let last = fields.len() - 1;
+                for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() {
+                    let enc = cx.expr_method_call(span, self_.clone(),
+                                                  encode, vec!(blkencoder.clone()));
+                    let lambda = cx.lambda_expr_1(span, enc, blkarg);
+                    let call = cx.expr_method_call(span, blkencoder.clone(),
+                                                   emit_variant_arg,
+                                                   vec!(cx.expr_usize(span, i),
+                                                        lambda));
+                    let call = if i != last {
+                        cx.expr_try(span, call)
+                    } else {
+                        cx.expr(span, ExprRet(Some(call)))
+                    };
+                    stmts.push(cx.stmt_expr(call));
+                }
+            } else {
+                let ret_ok = cx.expr(trait_span,
+                                     ExprRet(Some(cx.expr_ok(trait_span,
+                                                             cx.expr_tuple(trait_span, vec![])))));
+                stmts.push(cx.stmt_expr(ret_ok));
+            }
+
+            let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
+            let name = cx.expr_str(trait_span, variant.node.name.name.as_str());
+            let call = cx.expr_method_call(trait_span, blkencoder,
+                                           cx.ident_of("emit_enum_variant"),
+                                           vec!(name,
+                                             cx.expr_usize(trait_span, idx),
+                                             cx.expr_usize(trait_span, fields.len()),
+                                             blk));
+            let blk = cx.lambda_expr_1(trait_span, call, blkarg);
+            let ret = cx.expr_method_call(trait_span,
+                                          encoder,
+                                          cx.ident_of("emit_enum"),
+                                          vec!(
+                cx.expr_str(trait_span, substr.type_ident.name.as_str()),
+                blk
+            ));
+            cx.expr_block(cx.block(trait_span, vec!(me), Some(ret)))
+        }
+
+        _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)")
+    };
+}
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
new file mode 100644
index 00000000000..5977144dae7
--- /dev/null
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -0,0 +1,1634 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Some code that abstracts away much of the boilerplate of writing
+//! `derive` instances for traits. Among other things it manages getting
+//! access to the fields of the 4 different sorts of structs and enum
+//! variants, as well as creating the method and impl ast instances.
+//!
+//! Supported features (fairly exhaustive):
+//!
+//! - Methods taking any number of parameters of any type, and returning
+//!   any type, other than vectors, bottom and closures.
+//! - Generating `impl`s for types with type parameters and lifetimes
+//!   (e.g. `Option<T>`), the parameters are automatically given the
+//!   current trait as a bound. (This includes separate type parameters
+//!   and lifetimes for methods.)
+//! - Additional bounds on the type parameters (`TraitDef.additional_bounds`)
+//!
+//! The most important thing for implementers is the `Substructure` and
+//! `SubstructureFields` objects. The latter groups 5 possibilities of the
+//! arguments:
+//!
+//! - `Struct`, when `Self` is a struct (including tuple structs, e.g
+//!   `struct T(i32, char)`).
+//! - `EnumMatching`, when `Self` is an enum and all the arguments are the
+//!   same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`)
+//! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments
+//!   are not the same variant (e.g. `None`, `Some(1)` and `None`).
+//! - `StaticEnum` and `StaticStruct` for static methods, where the type
+//!   being derived upon is either an enum or struct respectively. (Any
+//!   argument with type Self is just grouped among the non-self
+//!   arguments.)
+//!
+//! In the first two cases, the values from the corresponding fields in
+//! all the arguments are grouped together. For `EnumNonMatchingCollapsed`
+//! this isn't possible (different variants have different fields), so the
+//! fields are inaccessible. (Previous versions of the deriving infrastructure
+//! had a way to expand into code that could access them, at the cost of
+//! generating exponential amounts of code; see issue #15375). There are no
+//! fields with values in the static cases, so these are treated entirely
+//! differently.
+//!
+//! The non-static cases have `Option<ident>` in several places associated
+//! with field `expr`s. This represents the name of the field it is
+//! associated with. It is only not `None` when the associated field has
+//! an identifier in the source code. For example, the `x`s in the
+//! following snippet
+//!
+//! ```rust
+//! # #![allow(dead_code)]
+//! struct A { x : i32 }
+//!
+//! struct B(i32);
+//!
+//! enum C {
+//!     C0(i32),
+//!     C1 { x: i32 }
+//! }
+//! ```
+//!
+//! The `i32`s in `B` and `C0` don't have an identifier, so the
+//! `Option<ident>`s would be `None` for them.
+//!
+//! In the static cases, the structure is summarised, either into the just
+//! spans of the fields or a list of spans and the field idents (for tuple
+//! structs and record structs, respectively), or a list of these, for
+//! enums (one for each variant). For empty struct and empty enum
+//! variants, it is represented as a count of 0.
+//!
+//! # "`cs`" functions
+//!
+//! The `cs_...` functions ("combine substructure) are designed to
+//! make life easier by providing some pre-made recipes for common
+//! threads; mostly calling the function being derived on all the
+//! arguments and then combining them back together in some way (or
+//! letting the user chose that). They are not meant to be the only
+//! way to handle the structures that this code creates.
+//!
+//! # Examples
+//!
+//! The following simplified `PartialEq` is used for in-code examples:
+//!
+//! ```rust
+//! trait PartialEq {
+//!     fn eq(&self, other: &Self) -> bool;
+//! }
+//! impl PartialEq for i32 {
+//!     fn eq(&self, other: &i32) -> bool {
+//!         *self == *other
+//!     }
+//! }
+//! ```
+//!
+//! Some examples of the values of `SubstructureFields` follow, using the
+//! above `PartialEq`, `A`, `B` and `C`.
+//!
+//! ## Structs
+//!
+//! When generating the `expr` for the `A` impl, the `SubstructureFields` is
+//!
+//! ```{.text}
+//! Struct(vec![FieldInfo {
+//!            span: <span of x>
+//!            name: Some(<ident of x>),
+//!            self_: <expr for &self.x>,
+//!            other: vec![<expr for &other.x]
+//!          }])
+//! ```
+//!
+//! For the `B` impl, called with `B(a)` and `B(b)`,
+//!
+//! ```{.text}
+//! Struct(vec![FieldInfo {
+//!           span: <span of `i32`>,
+//!           name: None,
+//!           self_: <expr for &a>
+//!           other: vec![<expr for &b>]
+//!          }])
+//! ```
+//!
+//! ## Enums
+//!
+//! When generating the `expr` for a call with `self == C0(a)` and `other
+//! == C0(b)`, the SubstructureFields is
+//!
+//! ```{.text}
+//! EnumMatching(0, <ast::Variant for C0>,
+//!              vec![FieldInfo {
+//!                 span: <span of i32>
+//!                 name: None,
+//!                 self_: <expr for &a>,
+//!                 other: vec![<expr for &b>]
+//!               }])
+//! ```
+//!
+//! For `C1 {x}` and `C1 {x}`,
+//!
+//! ```{.text}
+//! EnumMatching(1, <ast::Variant for C1>,
+//!              vec![FieldInfo {
+//!                 span: <span of x>
+//!                 name: Some(<ident of x>),
+//!                 self_: <expr for &self.x>,
+//!                 other: vec![<expr for &other.x>]
+//!                }])
+//! ```
+//!
+//! For `C0(a)` and `C1 {x}` ,
+//!
+//! ```{.text}
+//! EnumNonMatchingCollapsed(
+//!     vec![<ident of self>, <ident of __arg_1>],
+//!     &[<ast::Variant for C0>, <ast::Variant for C1>],
+//!     &[<ident for self index value>, <ident of __arg_1 index value>])
+//! ```
+//!
+//! It is the same for when the arguments are flipped to `C1 {x}` and
+//! `C0(a)`; the only difference is what the values of the identifiers
+//! <ident for self index value> and <ident of __arg_1 index value> will
+//! be in the generated code.
+//!
+//! `EnumNonMatchingCollapsed` deliberately provides far less information
+//! than is generally available for a given pair of variants; see #15375
+//! for discussion.
+//!
+//! ## Static
+//!
+//! A static method on the types above would result in,
+//!
+//! ```{.text}
+//! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))
+//!
+//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
+//!
+//! StaticEnum(<ast::EnumDef of C>,
+//!            vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
+//!                 (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])
+//! ```
+
+pub use self::StaticFields::*;
+pub use self::SubstructureFields::*;
+use self::StructType::*;
+
+use std::cell::RefCell;
+use std::collections::HashSet;
+use std::vec;
+
+use syntax::abi::Abi;
+use syntax::abi;
+use syntax::ast;
+use syntax::ast::{EnumDef, Expr, Ident, Generics, VariantData};
+use syntax::ast_util;
+use syntax::attr;
+use syntax::attr::AttrMetaMethods;
+use syntax::ext::base::{ExtCtxt, Annotatable};
+use syntax::ext::build::AstBuilder;
+use syntax::codemap::{self, DUMMY_SP};
+use syntax::codemap::Span;
+use syntax::diagnostic::SpanHandler;
+use syntax::util::move_map::MoveMap;
+use syntax::owned_slice::OwnedSlice;
+use syntax::parse::token::{intern, InternedString};
+use syntax::parse::token::special_idents;
+use syntax::ptr::P;
+
+use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty};
+
+pub mod ty;
+
+pub struct TraitDef<'a> {
+    /// The span for the current #[derive(Foo)] header.
+    pub span: Span,
+
+    pub attributes: Vec<ast::Attribute>,
+
+    /// Path of the trait, including any type parameters
+    pub path: Path<'a>,
+
+    /// Additional bounds required of any type parameters of the type,
+    /// other than the current trait
+    pub additional_bounds: Vec<Ty<'a>>,
+
+    /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder`
+    pub generics: LifetimeBounds<'a>,
+
+    /// Is it an `unsafe` trait?
+    pub is_unsafe: bool,
+
+    pub methods: Vec<MethodDef<'a>>,
+
+    pub associated_types: Vec<(ast::Ident, Ty<'a>)>,
+}
+
+
+pub struct MethodDef<'a> {
+    /// name of the method
+    pub name: &'a str,
+    /// List of generics, e.g. `R: rand::Rng`
+    pub generics: LifetimeBounds<'a>,
+
+    /// Whether there is a self argument (outer Option) i.e. whether
+    /// this is a static function, and whether it is a pointer (inner
+    /// Option)
+    pub explicit_self: Option<Option<PtrTy<'a>>>,
+
+    /// Arguments other than the self argument
+    pub args: Vec<Ty<'a>>,
+
+    /// Return type
+    pub ret_ty: Ty<'a>,
+
+    pub attributes: Vec<ast::Attribute>,
+
+    // Is it an `unsafe fn`?
+    pub is_unsafe: bool,
+
+    pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
+}
+
+/// All the data about the data structure/method being derived upon.
+pub struct Substructure<'a> {
+    /// ident of self
+    pub type_ident: Ident,
+    /// ident of the method
+    pub method_ident: Ident,
+    /// dereferenced access to any `Self_` or `Ptr(Self_, _)` arguments
+    pub self_args: &'a [P<Expr>],
+    /// verbatim access to any other arguments
+    pub nonself_args: &'a [P<Expr>],
+    pub fields: &'a SubstructureFields<'a>
+}
+
+/// Summary of the relevant parts of a struct/enum field.
+pub struct FieldInfo<'a> {
+    pub span: Span,
+    /// None for tuple structs/normal enum variants, Some for normal
+    /// structs/struct enum variants.
+    pub name: Option<Ident>,
+    /// The expression corresponding to this field of `self`
+    /// (specifically, a reference to it).
+    pub self_: P<Expr>,
+    /// The expressions corresponding to references to this field in
+    /// the other `Self` arguments.
+    pub other: Vec<P<Expr>>,
+    /// The attributes on the field
+    pub attrs: &'a [ast::Attribute],
+}
+
+/// Fields for a static method
+pub enum StaticFields {
+    /// Tuple structs/enum variants like this.
+    Unnamed(Vec<Span>),
+    /// Normal structs/struct variants.
+    Named(Vec<(Ident, Span)>),
+}
+
+/// A summary of the possible sets of fields.
+pub enum SubstructureFields<'a> {
+    Struct(Vec<FieldInfo<'a>>),
+    /// Matching variants of the enum: variant index, ast::Variant,
+    /// fields: the field name is only non-`None` in the case of a struct
+    /// variant.
+    EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo<'a>>),
+
+    /// Non-matching variants of the enum, but with all state hidden from
+    /// the consequent code.  The first component holds `Ident`s for all of
+    /// the `Self` arguments; the second component is a slice of all of the
+    /// variants for the enum itself, and the third component is a list of
+    /// `Ident`s bound to the variant index values for each of the actual
+    /// input `Self` arguments.
+    EnumNonMatchingCollapsed(Vec<Ident>, &'a [P<ast::Variant>], &'a [Ident]),
+
+    /// A static method where `Self` is a struct.
+    StaticStruct(&'a ast::VariantData, StaticFields),
+    /// A static method where `Self` is an enum.
+    StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
+}
+
+
+
+/// Combine the values of all the fields together. The last argument is
+/// all the fields of all the structures.
+pub type CombineSubstructureFunc<'a> =
+    Box<FnMut(&mut ExtCtxt, Span, &Substructure) -> P<Expr> + 'a>;
+
+/// Deal with non-matching enum variants.  The tuple is a list of
+/// identifiers (one for each `Self` argument, which could be any of the
+/// variants since they have been collapsed together) and the identifiers
+/// holding the variant index value for each of the `Self` arguments.  The
+/// last argument is all the non-`Self` args of the method being derived.
+pub type EnumNonMatchCollapsedFunc<'a> =
+    Box<FnMut(&mut ExtCtxt, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
+
+pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
+    -> RefCell<CombineSubstructureFunc<'a>> {
+    RefCell::new(f)
+}
+
+/// This method helps to extract all the type parameters referenced from a
+/// type. For a type parameter `<T>`, it looks for either a `TyPath` that
+/// is not global and starts with `T`, or a `TyQPath`.
+fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec<P<ast::Ty>> {
+    use syntax::visit;
+
+    struct Visitor<'a> {
+        ty_param_names: &'a [ast::Name],
+        types: Vec<P<ast::Ty>>,
+    }
+
+    impl<'a> visit::Visitor<'a> for Visitor<'a> {
+        fn visit_ty(&mut self, ty: &'a ast::Ty) {
+            match ty.node {
+                ast::TyPath(_, ref path) if !path.global => {
+                    match path.segments.first() {
+                        Some(segment) => {
+                            if self.ty_param_names.contains(&segment.identifier.name) {
+                                self.types.push(P(ty.clone()));
+                            }
+                        }
+                        None => {}
+                    }
+                }
+                _ => {}
+            }
+
+            visit::walk_ty(self, ty)
+        }
+    }
+
+    let mut visitor = Visitor {
+        ty_param_names: ty_param_names,
+        types: Vec::new(),
+    };
+
+    visit::Visitor::visit_ty(&mut visitor, ty);
+
+    visitor.types
+}
+
+impl<'a> TraitDef<'a> {
+    pub fn expand(&self,
+                  cx: &mut ExtCtxt,
+                  mitem: &ast::MetaItem,
+                  item: &'a Annotatable,
+                  push: &mut FnMut(Annotatable))
+    {
+        match *item {
+            Annotatable::Item(ref item) => {
+                let newitem = match item.node {
+                    ast::ItemStruct(ref struct_def, ref generics) => {
+                        self.expand_struct_def(cx,
+                                               &struct_def,
+                                               item.ident,
+                                               generics)
+                    }
+                    ast::ItemEnum(ref enum_def, ref generics) => {
+                        self.expand_enum_def(cx,
+                                             enum_def,
+                                             &item.attrs,
+                                             item.ident,
+                                             generics)
+                    }
+                    _ => {
+                        cx.span_err(mitem.span,
+                                    "`derive` may only be applied to structs and enums");
+                        return;
+                    }
+                };
+                // Keep the lint attributes of the previous item to control how the
+                // generated implementations are linted
+                let mut attrs = newitem.attrs.clone();
+                attrs.extend(item.attrs.iter().filter(|a| {
+                    match &a.name()[..] {
+                        "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true,
+                        _ => false,
+                    }
+                }).cloned());
+                push(Annotatable::Item(P(ast::Item {
+                    attrs: attrs,
+                    ..(*newitem).clone()
+                })))
+            }
+            _ => {
+                cx.span_err(mitem.span, "`derive` may only be applied to structs and enums");
+            }
+        }
+    }
+
+    /// Given that we are deriving a trait `DerivedTrait` for a type like:
+    ///
+    /// ```ignore
+    /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait {
+    ///     a: A,
+    ///     b: B::Item,
+    ///     b1: <B as DeclaredTrait>::Item,
+    ///     c1: <C as WhereTrait>::Item,
+    ///     c2: Option<<C as WhereTrait>::Item>,
+    ///     ...
+    /// }
+    /// ```
+    ///
+    /// create an impl like:
+    ///
+    /// ```ignore
+    /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ...  Z> where
+    ///     C:                       WhereTrait,
+    ///     A: DerivedTrait + B1 + ... + BN,
+    ///     B: DerivedTrait + B1 + ... + BN,
+    ///     C: DerivedTrait + B1 + ... + BN,
+    ///     B::Item:                 DerivedTrait + B1 + ... + BN,
+    ///     <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN,
+    ///     ...
+    /// {
+    ///     ...
+    /// }
+    /// ```
+    ///
+    /// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and
+    /// therefore does not get bound by the derived trait.
+    fn create_derived_impl(&self,
+                           cx: &mut ExtCtxt,
+                           type_ident: Ident,
+                           generics: &Generics,
+                           field_tys: Vec<P<ast::Ty>>,
+                           methods: Vec<P<ast::ImplItem>>) -> P<ast::Item> {
+        let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
+
+        // Transform associated types from `deriving::ty::Ty` into `ast::ImplItem`
+        let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| {
+            P(ast::ImplItem {
+                id: ast::DUMMY_NODE_ID,
+                span: self.span,
+                ident: ident,
+                vis: ast::Inherited,
+                attrs: Vec::new(),
+                node: ast::ImplItemKind::Type(type_def.to_ty(cx,
+                    self.span,
+                    type_ident,
+                    generics
+                )),
+            })
+        });
+
+        let Generics { mut lifetimes, ty_params, mut where_clause } =
+            self.generics.to_generics(cx, self.span, type_ident, generics);
+        let mut ty_params = ty_params.into_vec();
+
+        // Copy the lifetimes
+        lifetimes.extend(generics.lifetimes.iter().cloned());
+
+        // Create the type parameters.
+        ty_params.extend(generics.ty_params.iter().map(|ty_param| {
+            // I don't think this can be moved out of the loop, since
+            // a TyParamBound requires an ast id
+            let mut bounds: Vec<_> =
+                // extra restrictions on the generics parameters to the type being derived upon
+                self.additional_bounds.iter().map(|p| {
+                    cx.typarambound(p.to_path(cx, self.span,
+                                                  type_ident, generics))
+                }).collect();
+
+            // require the current trait
+            bounds.push(cx.typarambound(trait_path.clone()));
+
+            // also add in any bounds from the declaration
+            for declared_bound in ty_param.bounds.iter() {
+                bounds.push((*declared_bound).clone());
+            }
+
+            cx.typaram(self.span,
+                       ty_param.ident,
+                       OwnedSlice::from_vec(bounds),
+                       None)
+        }));
+
+        // and similarly for where clauses
+        where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
+            match *clause {
+                ast::WherePredicate::BoundPredicate(ref wb) => {
+                    ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+                        span: self.span,
+                        bound_lifetimes: wb.bound_lifetimes.clone(),
+                        bounded_ty: wb.bounded_ty.clone(),
+                        bounds: OwnedSlice::from_vec(wb.bounds.iter().cloned().collect())
+                    })
+                }
+                ast::WherePredicate::RegionPredicate(ref rb) => {
+                    ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
+                        span: self.span,
+                        lifetime: rb.lifetime,
+                        bounds: rb.bounds.iter().cloned().collect()
+                    })
+                }
+                ast::WherePredicate::EqPredicate(ref we) => {
+                    ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
+                        id: ast::DUMMY_NODE_ID,
+                        span: self.span,
+                        path: we.path.clone(),
+                        ty: we.ty.clone()
+                    })
+                }
+            }
+        }));
+
+        if !ty_params.is_empty() {
+            let ty_param_names: Vec<ast::Name> = ty_params.iter()
+                .map(|ty_param| ty_param.ident.name)
+                .collect();
+
+            let mut processed_field_types = HashSet::new();
+            for field_ty in field_tys {
+                let tys = find_type_parameters(&*field_ty, &ty_param_names);
+
+                for ty in tys {
+                    // if we have already handled this type, skip it
+                    if let ast::TyPath(_, ref p) = ty.node {
+                        if p.segments.len() == 1
+                            && ty_param_names.contains(&p.segments[0].identifier.name)
+                            || processed_field_types.contains(&p.segments) {
+                            continue;
+                        };
+                        processed_field_types.insert(p.segments.clone());
+                    }
+                    let mut bounds: Vec<_> = self.additional_bounds.iter().map(|p| {
+                        cx.typarambound(p.to_path(cx, self.span, type_ident, generics))
+                    }).collect();
+
+                    // require the current trait
+                    bounds.push(cx.typarambound(trait_path.clone()));
+
+                    let predicate = ast::WhereBoundPredicate {
+                        span: self.span,
+                        bound_lifetimes: vec![],
+                        bounded_ty: ty,
+                        bounds: OwnedSlice::from_vec(bounds),
+                    };
+
+                    let predicate = ast::WherePredicate::BoundPredicate(predicate);
+                    where_clause.predicates.push(predicate);
+                }
+            }
+        }
+
+        let trait_generics = Generics {
+            lifetimes: lifetimes,
+            ty_params: OwnedSlice::from_vec(ty_params),
+            where_clause: where_clause
+        };
+
+        // Create the reference to the trait.
+        let trait_ref = cx.trait_ref(trait_path);
+
+        // Create the type parameters on the `self` path.
+        let self_ty_params = generics.ty_params.map(|ty_param| {
+            cx.ty_ident(self.span, ty_param.ident)
+        });
+
+        let self_lifetimes: Vec<ast::Lifetime> =
+            generics.lifetimes
+            .iter()
+            .map(|ld| ld.lifetime)
+            .collect();
+
+        // Create the type of `self`.
+        let self_type = cx.ty_path(
+            cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes,
+                        self_ty_params.into_vec(), Vec::new()));
+
+        let attr = cx.attribute(
+            self.span,
+            cx.meta_word(self.span,
+                         InternedString::new("automatically_derived")));
+        // Just mark it now since we know that it'll end up used downstream
+        attr::mark_used(&attr);
+        let opt_trait_ref = Some(trait_ref);
+        let ident = ast_util::impl_pretty_name(&opt_trait_ref, Some(&*self_type));
+        let unused_qual = cx.attribute(
+            self.span,
+            cx.meta_list(self.span,
+                         InternedString::new("allow"),
+                         vec![cx.meta_word(self.span,
+                                           InternedString::new("unused_qualifications"))]));
+        let mut a = vec![attr, unused_qual];
+        a.extend(self.attributes.iter().cloned());
+
+        let unsafety = if self.is_unsafe {
+            ast::Unsafety::Unsafe
+        } else {
+            ast::Unsafety::Normal
+        };
+
+        cx.item(
+            self.span,
+            ident,
+            a,
+            ast::ItemImpl(unsafety,
+                          ast::ImplPolarity::Positive,
+                          trait_generics,
+                          opt_trait_ref,
+                          self_type,
+                          methods.into_iter().chain(associated_types).collect()))
+    }
+
+    fn expand_struct_def(&self,
+                         cx: &mut ExtCtxt,
+                         struct_def: &'a VariantData,
+                         type_ident: Ident,
+                         generics: &Generics) -> P<ast::Item> {
+        let field_tys: Vec<P<ast::Ty>> = struct_def.fields().iter()
+            .map(|field| field.node.ty.clone())
+            .collect();
+
+        let methods = self.methods.iter().map(|method_def| {
+            let (explicit_self, self_args, nonself_args, tys) =
+                method_def.split_self_nonself_args(
+                    cx, self, type_ident, generics);
+
+            let body = if method_def.is_static() {
+                method_def.expand_static_struct_method_body(
+                    cx,
+                    self,
+                    struct_def,
+                    type_ident,
+                    &self_args[..],
+                    &nonself_args[..])
+            } else {
+                method_def.expand_struct_method_body(cx,
+                                                     self,
+                                                     struct_def,
+                                                     type_ident,
+                                                     &self_args[..],
+                                                     &nonself_args[..])
+            };
+
+            method_def.create_method(cx,
+                                     self,
+                                     type_ident,
+                                     generics,
+                                     abi::Rust,
+                                     explicit_self,
+                                     tys,
+                                     body)
+        }).collect();
+
+        self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
+    }
+
+    fn expand_enum_def(&self,
+                       cx: &mut ExtCtxt,
+                       enum_def: &'a EnumDef,
+                       type_attrs: &[ast::Attribute],
+                       type_ident: Ident,
+                       generics: &Generics) -> P<ast::Item> {
+        let mut field_tys = Vec::new();
+
+        for variant in &enum_def.variants {
+            field_tys.extend(variant.node.data.fields().iter()
+                .map(|field| field.node.ty.clone()));
+        }
+
+        let methods = self.methods.iter().map(|method_def| {
+            let (explicit_self, self_args, nonself_args, tys) =
+                method_def.split_self_nonself_args(cx, self,
+                                                   type_ident, generics);
+
+            let body = if method_def.is_static() {
+                method_def.expand_static_enum_method_body(
+                    cx,
+                    self,
+                    enum_def,
+                    type_ident,
+                    &self_args[..],
+                    &nonself_args[..])
+            } else {
+                method_def.expand_enum_method_body(cx,
+                                                   self,
+                                                   enum_def,
+                                                   type_attrs,
+                                                   type_ident,
+                                                   self_args,
+                                                   &nonself_args[..])
+            };
+
+            method_def.create_method(cx,
+                                     self,
+                                     type_ident,
+                                     generics,
+                                     abi::Rust,
+                                     explicit_self,
+                                     tys,
+                                     body)
+        }).collect();
+
+        self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
+    }
+}
+
+fn find_repr_type_name(diagnostic: &SpanHandler,
+                       type_attrs: &[ast::Attribute]) -> &'static str {
+    let mut repr_type_name = "i32";
+    for a in type_attrs {
+        for r in &attr::find_repr_attrs(diagnostic, a) {
+            repr_type_name = match *r {
+                attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue,
+                attr::ReprExtern => "i32",
+
+                attr::ReprInt(_, attr::SignedInt(ast::TyIs)) => "isize",
+                attr::ReprInt(_, attr::SignedInt(ast::TyI8)) => "i8",
+                attr::ReprInt(_, attr::SignedInt(ast::TyI16)) => "i16",
+                attr::ReprInt(_, attr::SignedInt(ast::TyI32)) => "i32",
+                attr::ReprInt(_, attr::SignedInt(ast::TyI64)) => "i64",
+
+                attr::ReprInt(_, attr::UnsignedInt(ast::TyUs)) => "usize",
+                attr::ReprInt(_, attr::UnsignedInt(ast::TyU8)) => "u8",
+                attr::ReprInt(_, attr::UnsignedInt(ast::TyU16)) => "u16",
+                attr::ReprInt(_, attr::UnsignedInt(ast::TyU32)) => "u32",
+                attr::ReprInt(_, attr::UnsignedInt(ast::TyU64)) => "u64",
+            }
+        }
+    }
+    repr_type_name
+}
+
+impl<'a> MethodDef<'a> {
+    fn call_substructure_method(&self,
+                                cx: &mut ExtCtxt,
+                                trait_: &TraitDef,
+                                type_ident: Ident,
+                                self_args: &[P<Expr>],
+                                nonself_args: &[P<Expr>],
+                                fields: &SubstructureFields)
+        -> P<Expr> {
+        let substructure = Substructure {
+            type_ident: type_ident,
+            method_ident: cx.ident_of(self.name),
+            self_args: self_args,
+            nonself_args: nonself_args,
+            fields: fields
+        };
+        let mut f = self.combine_substructure.borrow_mut();
+        let f: &mut CombineSubstructureFunc = &mut *f;
+        f(cx, trait_.span, &substructure)
+    }
+
+    fn get_ret_ty(&self,
+                  cx: &mut ExtCtxt,
+                  trait_: &TraitDef,
+                  generics: &Generics,
+                  type_ident: Ident)
+                  -> P<ast::Ty> {
+        self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
+    }
+
+    fn is_static(&self) -> bool {
+        self.explicit_self.is_none()
+    }
+
+    fn split_self_nonself_args(&self,
+                               cx: &mut ExtCtxt,
+                               trait_: &TraitDef,
+                               type_ident: Ident,
+                               generics: &Generics)
+        -> (ast::ExplicitSelf, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
+
+        let mut self_args = Vec::new();
+        let mut nonself_args = Vec::new();
+        let mut arg_tys = Vec::new();
+        let mut nonstatic = false;
+
+        let ast_explicit_self = match self.explicit_self {
+            Some(ref self_ptr) => {
+                let (self_expr, explicit_self) =
+                    ty::get_explicit_self(cx, trait_.span, self_ptr);
+
+                self_args.push(self_expr);
+                nonstatic = true;
+
+                explicit_self
+            }
+            None => codemap::respan(trait_.span, ast::SelfStatic),
+        };
+
+        for (i, ty) in self.args.iter().enumerate() {
+            let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
+            let ident = cx.ident_of(&format!("__arg_{}", i));
+            arg_tys.push((ident, ast_ty));
+
+            let arg_expr = cx.expr_ident(trait_.span, ident);
+
+            match *ty {
+                // for static methods, just treat any Self
+                // arguments as a normal arg
+                Self_ if nonstatic  => {
+                    self_args.push(arg_expr);
+                }
+                Ptr(ref ty, _) if **ty == Self_ && nonstatic => {
+                    self_args.push(cx.expr_deref(trait_.span, arg_expr))
+                }
+                _ => {
+                    nonself_args.push(arg_expr);
+                }
+            }
+        }
+
+        (ast_explicit_self, self_args, nonself_args, arg_tys)
+    }
+
+    fn create_method(&self,
+                     cx: &mut ExtCtxt,
+                     trait_: &TraitDef,
+                     type_ident: Ident,
+                     generics: &Generics,
+                     abi: Abi,
+                     explicit_self: ast::ExplicitSelf,
+                     arg_types: Vec<(Ident, P<ast::Ty>)> ,
+                     body: P<Expr>) -> P<ast::ImplItem> {
+        // create the generics that aren't for Self
+        let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
+
+        let self_arg = match explicit_self.node {
+            ast::SelfStatic => None,
+            // creating fresh self id
+            _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable, special_idents::self_))
+        };
+        let args = {
+            let args = arg_types.into_iter().map(|(name, ty)| {
+                    cx.arg(trait_.span, name, ty)
+                });
+            self_arg.into_iter().chain(args).collect()
+        };
+
+        let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
+
+        let method_ident = cx.ident_of(self.name);
+        let fn_decl = cx.fn_decl(args, ret_type);
+        let body_block = cx.block_expr(body);
+
+        let unsafety = if self.is_unsafe {
+            ast::Unsafety::Unsafe
+        } else {
+            ast::Unsafety::Normal
+        };
+
+        // Create the method.
+        P(ast::ImplItem {
+            id: ast::DUMMY_NODE_ID,
+            attrs: self.attributes.clone(),
+            span: trait_.span,
+            vis: ast::Inherited,
+            ident: method_ident,
+            node: ast::ImplItemKind::Method(ast::MethodSig {
+                generics: fn_generics,
+                abi: abi,
+                explicit_self: explicit_self,
+                unsafety: unsafety,
+                constness: ast::Constness::NotConst,
+                decl: fn_decl
+            }, body_block)
+        })
+    }
+
+    /// ```ignore
+    /// #[derive(PartialEq)]
+    /// struct A { x: i32, y: i32 }
+    ///
+    /// // equivalent to:
+    /// impl PartialEq for A {
+    ///     fn eq(&self, __arg_1: &A) -> bool {
+    ///         match *self {
+    ///             A {x: ref __self_0_0, y: ref __self_0_1} => {
+    ///                 match *__arg_1 {
+    ///                     A {x: ref __self_1_0, y: ref __self_1_1} => {
+    ///                         __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
+    ///                     }
+    ///                 }
+    ///             }
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    fn expand_struct_method_body<'b>(&self,
+                                 cx: &mut ExtCtxt,
+                                 trait_: &TraitDef<'b>,
+                                 struct_def: &'b VariantData,
+                                 type_ident: Ident,
+                                 self_args: &[P<Expr>],
+                                 nonself_args: &[P<Expr>])
+        -> P<Expr> {
+
+        let mut raw_fields = Vec::new(); // Vec<[fields of self],
+                                 // [fields of next Self arg], [etc]>
+        let mut patterns = Vec::new();
+        for i in 0..self_args.len() {
+            let struct_path= cx.path(DUMMY_SP, vec!( type_ident ));
+            let (pat, ident_expr) =
+                trait_.create_struct_pattern(cx,
+                                             struct_path,
+                                             struct_def,
+                                             &format!("__self_{}",
+                                                     i),
+                                             ast::MutImmutable);
+            patterns.push(pat);
+            raw_fields.push(ident_expr);
+        }
+
+        // transpose raw_fields
+        let fields = if !raw_fields.is_empty() {
+            let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter());
+            let first_field = raw_fields.next().unwrap();
+            let mut other_fields: Vec<vec::IntoIter<_>>
+                = raw_fields.collect();
+            first_field.map(|(span, opt_id, field, attrs)| {
+                FieldInfo {
+                    span: span,
+                    name: opt_id,
+                    self_: field,
+                    other: other_fields.iter_mut().map(|l| {
+                        match l.next().unwrap() {
+                            (_, _, ex, _) => ex
+                        }
+                    }).collect(),
+                    attrs: attrs,
+                }
+            }).collect()
+        } else {
+            cx.span_bug(trait_.span,
+                        "no self arguments to non-static method in generic \
+                         `derive`")
+        };
+
+        // body of the inner most destructuring match
+        let mut body = self.call_substructure_method(
+            cx,
+            trait_,
+            type_ident,
+            self_args,
+            nonself_args,
+            &Struct(fields));
+
+        // make a series of nested matches, to destructure the
+        // structs. This is actually right-to-left, but it shouldn't
+        // matter.
+        for (arg_expr, pat) in self_args.iter().zip(patterns) {
+            body = cx.expr_match(trait_.span, arg_expr.clone(),
+                                     vec!( cx.arm(trait_.span, vec!(pat.clone()), body) ))
+        }
+        body
+    }
+
+    fn expand_static_struct_method_body(&self,
+                                        cx: &mut ExtCtxt,
+                                        trait_: &TraitDef,
+                                        struct_def: &VariantData,
+                                        type_ident: Ident,
+                                        self_args: &[P<Expr>],
+                                        nonself_args: &[P<Expr>])
+        -> P<Expr> {
+        let summary = trait_.summarise_struct(cx, struct_def);
+
+        self.call_substructure_method(cx,
+                                      trait_,
+                                      type_ident,
+                                      self_args, nonself_args,
+                                      &StaticStruct(struct_def, summary))
+    }
+
+    /// ```ignore
+    /// #[derive(PartialEq)]
+    /// enum A {
+    ///     A1,
+    ///     A2(i32)
+    /// }
+    ///
+    /// // is equivalent to
+    ///
+    /// impl PartialEq for A {
+    ///     fn eq(&self, __arg_1: &A) -> ::bool {
+    ///         match (&*self, &*__arg_1) {
+    ///             (&A1, &A1) => true,
+    ///             (&A2(ref __self_0),
+    ///              &A2(ref __arg_1_0)) => (*__self_0).eq(&(*__arg_1_0)),
+    ///             _ => {
+    ///                 let __self_vi = match *self { A1(..) => 0, A2(..) => 1 };
+    ///                 let __arg_1_vi = match *__arg_1 { A1(..) => 0, A2(..) => 1 };
+    ///                 false
+    ///             }
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// (Of course `__self_vi` and `__arg_1_vi` are unused for
+    /// `PartialEq`, and those subcomputations will hopefully be removed
+    /// as their results are unused.  The point of `__self_vi` and
+    /// `__arg_1_vi` is for `PartialOrd`; see #15503.)
+    fn expand_enum_method_body<'b>(&self,
+                               cx: &mut ExtCtxt,
+                               trait_: &TraitDef<'b>,
+                               enum_def: &'b EnumDef,
+                               type_attrs: &[ast::Attribute],
+                               type_ident: Ident,
+                               self_args: Vec<P<Expr>>,
+                               nonself_args: &[P<Expr>])
+                               -> P<Expr> {
+        self.build_enum_match_tuple(
+            cx, trait_, enum_def, type_attrs, type_ident, self_args, nonself_args)
+    }
+
+
+    /// Creates a match for a tuple of all `self_args`, where either all
+    /// variants match, or it falls into a catch-all for when one variant
+    /// does not match.
+
+    /// There are N + 1 cases because is a case for each of the N
+    /// variants where all of the variants match, and one catch-all for
+    /// when one does not match.
+
+    /// As an optimization we generate code which checks whether all variants
+    /// match first which makes llvm see that C-like enums can be compiled into
+    /// a simple equality check (for PartialEq).
+
+    /// The catch-all handler is provided access the variant index values
+    /// for each of the self-args, carried in precomputed variables.
+
+    /// ```{.text}
+    /// let __self0_vi = unsafe {
+    ///     std::intrinsics::discriminant_value(&self) } as i32;
+    /// let __self1_vi = unsafe {
+    ///     std::intrinsics::discriminant_value(&__arg1) } as i32;
+    /// let __self2_vi = unsafe {
+    ///     std::intrinsics::discriminant_value(&__arg2) } as i32;
+    ///
+    /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... {
+    ///     match (...) {
+    ///         (Variant1, Variant1, ...) => Body1
+    ///         (Variant2, Variant2, ...) => Body2,
+    ///         ...
+    ///         _ => ::core::intrinsics::unreachable()
+    ///     }
+    /// }
+    /// else {
+    ///     ... // catch-all remainder can inspect above variant index values.
+    /// }
+    /// ```
+    fn build_enum_match_tuple<'b>(
+        &self,
+        cx: &mut ExtCtxt,
+        trait_: &TraitDef<'b>,
+        enum_def: &'b EnumDef,
+        type_attrs: &[ast::Attribute],
+        type_ident: Ident,
+        self_args: Vec<P<Expr>>,
+        nonself_args: &[P<Expr>]) -> P<Expr> {
+
+        let sp = trait_.span;
+        let variants = &enum_def.variants;
+
+        let self_arg_names = self_args.iter().enumerate()
+            .map(|(arg_count, _self_arg)| {
+                if arg_count == 0 {
+                    "__self".to_string()
+                } else {
+                    format!("__arg_{}", arg_count)
+                }
+            })
+            .collect::<Vec<String>>();
+
+        let self_arg_idents = self_arg_names.iter()
+            .map(|name|cx.ident_of(&name[..]))
+            .collect::<Vec<ast::Ident>>();
+
+        // The `vi_idents` will be bound, solely in the catch-all, to
+        // a series of let statements mapping each self_arg to an int
+        // value corresponding to its discriminant.
+        let vi_idents: Vec<ast::Ident> = self_arg_names.iter()
+            .map(|name| { let vi_suffix = format!("{}_vi", &name[..]);
+                          cx.ident_of(&vi_suffix[..]) })
+            .collect::<Vec<ast::Ident>>();
+
+        // Builds, via callback to call_substructure_method, the
+        // delegated expression that handles the catch-all case,
+        // using `__variants_tuple` to drive logic if necessary.
+        let catch_all_substructure = EnumNonMatchingCollapsed(
+            self_arg_idents, &variants[..], &vi_idents[..]);
+
+        // These arms are of the form:
+        // (Variant1, Variant1, ...) => Body1
+        // (Variant2, Variant2, ...) => Body2
+        // ...
+        // where each tuple has length = self_args.len()
+        let mut match_arms: Vec<ast::Arm> = variants.iter().enumerate()
+            .map(|(index, variant)| {
+                let mk_self_pat = |cx: &mut ExtCtxt, self_arg_name: &str| {
+                    let (p, idents) = trait_.create_enum_variant_pattern(cx, type_ident,
+                                                                         &**variant,
+                                                                         self_arg_name,
+                                                                         ast::MutImmutable);
+                    (cx.pat(sp, ast::PatRegion(p, ast::MutImmutable)), idents)
+                };
+
+                // A single arm has form (&VariantK, &VariantK, ...) => BodyK
+                // (see "Final wrinkle" note below for why.)
+                let mut subpats = Vec::with_capacity(self_arg_names.len());
+                let mut self_pats_idents = Vec::with_capacity(self_arg_names.len() - 1);
+                let first_self_pat_idents = {
+                    let (p, idents) = mk_self_pat(cx, &self_arg_names[0]);
+                    subpats.push(p);
+                    idents
+                };
+                for self_arg_name in &self_arg_names[1..] {
+                    let (p, idents) = mk_self_pat(cx, &self_arg_name[..]);
+                    subpats.push(p);
+                    self_pats_idents.push(idents);
+                }
+
+                // Here is the pat = `(&VariantK, &VariantK, ...)`
+                let single_pat = cx.pat_tuple(sp, subpats);
+
+                // For the BodyK, we need to delegate to our caller,
+                // passing it an EnumMatching to indicate which case
+                // we are in.
+
+                // All of the Self args have the same variant in these
+                // cases.  So we transpose the info in self_pats_idents
+                // to gather the getter expressions together, in the
+                // form that EnumMatching expects.
+
+                // The transposition is driven by walking across the
+                // arg fields of the variant for the first self pat.
+                let field_tuples = first_self_pat_idents.into_iter().enumerate()
+                    // For each arg field of self, pull out its getter expr ...
+                    .map(|(field_index, (sp, opt_ident, self_getter_expr, attrs))| {
+                        // ... but FieldInfo also wants getter expr
+                        // for matching other arguments of Self type;
+                        // so walk across the *other* self_pats_idents
+                        // and pull out getter for same field in each
+                        // of them (using `field_index` tracked above).
+                        // That is the heart of the transposition.
+                        let others = self_pats_idents.iter().map(|fields| {
+                            let (_, _opt_ident, ref other_getter_expr, _) =
+                                fields[field_index];
+
+                            // All Self args have same variant, so
+                            // opt_idents are the same.  (Assert
+                            // here to make it self-evident that
+                            // it is okay to ignore `_opt_ident`.)
+                            assert!(opt_ident == _opt_ident);
+
+                            other_getter_expr.clone()
+                        }).collect::<Vec<P<Expr>>>();
+
+                        FieldInfo { span: sp,
+                                    name: opt_ident,
+                                    self_: self_getter_expr,
+                                    other: others,
+                                    attrs: attrs,
+                        }
+                    }).collect::<Vec<FieldInfo>>();
+
+                // Now, for some given VariantK, we have built up
+                // expressions for referencing every field of every
+                // Self arg, assuming all are instances of VariantK.
+                // Build up code associated with such a case.
+                let substructure = EnumMatching(index,
+                                                &**variant,
+                                                field_tuples);
+                let arm_expr = self.call_substructure_method(
+                    cx, trait_, type_ident, &self_args[..], nonself_args,
+                    &substructure);
+
+                cx.arm(sp, vec![single_pat], arm_expr)
+            }).collect();
+        // We will usually need the catch-all after matching the
+        // tuples `(VariantK, VariantK, ...)` for each VariantK of the
+        // enum.  But:
+        //
+        // * when there is only one Self arg, the arms above suffice
+        // (and the deriving we call back into may not be prepared to
+        // handle EnumNonMatchCollapsed), and,
+        //
+        // * when the enum has only one variant, the single arm that
+        // is already present always suffices.
+        //
+        // * In either of the two cases above, if we *did* add a
+        //   catch-all `_` match, it would trigger the
+        //   unreachable-pattern error.
+        //
+        if variants.len() > 1 && self_args.len() > 1 {
+            // Build a series of let statements mapping each self_arg
+            // to its discriminant value. If this is a C-style enum
+            // with a specific repr type, then casts the values to
+            // that type.  Otherwise casts to `i32` (the default repr
+            // type).
+            //
+            // i.e. for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
+            // with three Self args, builds three statements:
+            //
+            // ```
+            // let __self0_vi = unsafe {
+            //     std::intrinsics::discriminant_value(&self) } as i32;
+            // let __self1_vi = unsafe {
+            //     std::intrinsics::discriminant_value(&__arg1) } as i32;
+            // let __self2_vi = unsafe {
+            //     std::intrinsics::discriminant_value(&__arg2) } as i32;
+            // ```
+            let mut index_let_stmts: Vec<P<ast::Stmt>> = Vec::new();
+
+            //We also build an expression which checks whether all discriminants are equal
+            // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ...
+            let mut discriminant_test = cx.expr_bool(sp, true);
+
+            let target_type_name =
+                find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs);
+
+            let mut first_ident = None;
+            for (&ident, self_arg) in vi_idents.iter().zip(&self_args) {
+                let path = cx.std_path(&["intrinsics", "discriminant_value"]);
+                let call = cx.expr_call_global(
+                    sp, path, vec![cx.expr_addr_of(sp, self_arg.clone())]);
+                let variant_value = cx.expr_block(P(ast::Block {
+                    stmts: vec![],
+                    expr: Some(call),
+                    id: ast::DUMMY_NODE_ID,
+                    rules: ast::UnsafeBlock(ast::CompilerGenerated),
+                    span: sp }));
+
+                let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name));
+                let variant_disr = cx.expr_cast(sp, variant_value, target_ty);
+                let let_stmt = cx.stmt_let(sp, false, ident, variant_disr);
+                index_let_stmts.push(let_stmt);
+
+                match first_ident {
+                    Some(first) => {
+                        let first_expr = cx.expr_ident(sp, first);
+                        let id = cx.expr_ident(sp, ident);
+                        let test = cx.expr_binary(sp, ast::BiEq, first_expr, id);
+                        discriminant_test = cx.expr_binary(sp, ast::BiAnd, discriminant_test, test)
+                    }
+                    None => {
+                        first_ident = Some(ident);
+                    }
+                }
+            }
+
+            let arm_expr = self.call_substructure_method(
+                cx, trait_, type_ident, &self_args[..], nonself_args,
+                &catch_all_substructure);
+
+            //Since we know that all the arguments will match if we reach the match expression we
+            //add the unreachable intrinsics as the result of the catch all which should help llvm
+            //in optimizing it
+            let path = cx.std_path(&["intrinsics", "unreachable"]);
+            let call = cx.expr_call_global(
+                sp, path, vec![]);
+            let unreachable = cx.expr_block(P(ast::Block {
+                stmts: vec![],
+                expr: Some(call),
+                id: ast::DUMMY_NODE_ID,
+                rules: ast::UnsafeBlock(ast::CompilerGenerated),
+                span: sp }));
+            match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], unreachable));
+
+            // Final wrinkle: the self_args are expressions that deref
+            // down to desired l-values, but we cannot actually deref
+            // them when they are fed as r-values into a tuple
+            // expression; here add a layer of borrowing, turning
+            // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
+            let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
+            let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
+
+            //Lastly we create an expression which branches on all discriminants being equal
+            //  if discriminant_test {
+            //      match (...) {
+            //          (Variant1, Variant1, ...) => Body1
+            //          (Variant2, Variant2, ...) => Body2,
+            //          ...
+            //          _ => ::core::intrinsics::unreachable()
+            //      }
+            //  }
+            //  else {
+            //      <delegated expression referring to __self0_vi, et al.>
+            //  }
+            let all_match = cx.expr_match(sp, match_arg, match_arms);
+            let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr));
+            cx.expr_block(
+                cx.block_all(sp, index_let_stmts, Some(arm_expr)))
+        } else if variants.is_empty() {
+            // As an additional wrinkle, For a zero-variant enum A,
+            // currently the compiler
+            // will accept `fn (a: &Self) { match   *a   { } }`
+            // but rejects `fn (a: &Self) { match (&*a,) { } }`
+            // as well as  `fn (a: &Self) { match ( *a,) { } }`
+            //
+            // This means that the strategy of building up a tuple of
+            // all Self arguments fails when Self is a zero variant
+            // enum: rustc rejects the expanded program, even though
+            // the actual code tends to be impossible to execute (at
+            // least safely), according to the type system.
+            //
+            // The most expedient fix for this is to just let the
+            // code fall through to the catch-all.  But even this is
+            // error-prone, since the catch-all as defined above would
+            // generate code like this:
+            //
+            //     _ => { let __self0 = match *self { };
+            //            let __self1 = match *__arg_0 { };
+            //            <catch-all-expr> }
+            //
+            // Which is yields bindings for variables which type
+            // inference cannot resolve to unique types.
+            //
+            // One option to the above might be to add explicit type
+            // annotations.  But the *only* reason to go down that path
+            // would be to try to make the expanded output consistent
+            // with the case when the number of enum variants >= 1.
+            //
+            // That just isn't worth it.  In fact, trying to generate
+            // sensible code for *any* deriving on a zero-variant enum
+            // does not make sense.  But at the same time, for now, we
+            // do not want to cause a compile failure just because the
+            // user happened to attach a deriving to their
+            // zero-variant enum.
+            //
+            // Instead, just generate a failing expression for the
+            // zero variant case, skipping matches and also skipping
+            // delegating back to the end user code entirely.
+            //
+            // (See also #4499 and #12609; note that some of the
+            // discussions there influence what choice we make here;
+            // e.g. if we feature-gate `match x { ... }` when x refers
+            // to an uninhabited type (e.g. a zero-variant enum or a
+            // type holding such an enum), but do not feature-gate
+            // zero-variant enums themselves, then attempting to
+            // derive Debug on such a type could here generate code
+            // that needs the feature gate enabled.)
+
+            cx.expr_unreachable(sp)
+        }
+        else {
+
+            // Final wrinkle: the self_args are expressions that deref
+            // down to desired l-values, but we cannot actually deref
+            // them when they are fed as r-values into a tuple
+            // expression; here add a layer of borrowing, turning
+            // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
+            let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
+            let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
+            cx.expr_match(sp, match_arg, match_arms)
+        }
+    }
+
+    fn expand_static_enum_method_body(&self,
+                                      cx: &mut ExtCtxt,
+                                      trait_: &TraitDef,
+                                      enum_def: &EnumDef,
+                                      type_ident: Ident,
+                                      self_args: &[P<Expr>],
+                                      nonself_args: &[P<Expr>])
+        -> P<Expr> {
+        let summary = enum_def.variants.iter().map(|v| {
+            let ident = v.node.name;
+            let summary = trait_.summarise_struct(cx, &v.node.data);
+            (ident, v.span, summary)
+        }).collect();
+        self.call_substructure_method(cx, trait_, type_ident,
+                                      self_args, nonself_args,
+                                      &StaticEnum(enum_def, summary))
+    }
+}
+
+#[derive(PartialEq)] // dogfooding!
+enum StructType {
+    Unknown, Record, Tuple
+}
+
+// general helper methods.
+impl<'a> TraitDef<'a> {
+    fn set_expn_info(&self,
+                     cx: &mut ExtCtxt,
+                     mut to_set: Span) -> Span {
+        let trait_name = match self.path.path.last() {
+            None => cx.span_bug(self.span, "trait with empty path in generic `derive`"),
+            Some(name) => *name
+        };
+        to_set.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
+            call_site: to_set,
+            callee: codemap::NameAndSpan {
+                format: codemap::MacroAttribute(intern(&format!("derive({})", trait_name))),
+                span: Some(self.span),
+                allow_internal_unstable: false,
+            }
+        });
+        to_set
+    }
+
+    fn summarise_struct(&self,
+                        cx: &mut ExtCtxt,
+                        struct_def: &VariantData) -> StaticFields {
+        let mut named_idents = Vec::new();
+        let mut just_spans = Vec::new();
+        for field in struct_def.fields(){
+            let sp = self.set_expn_info(cx, field.span);
+            match field.node.kind {
+                ast::NamedField(ident, _) => named_idents.push((ident, sp)),
+                ast::UnnamedField(..) => just_spans.push(sp),
+            }
+        }
+
+        match (just_spans.is_empty(), named_idents.is_empty()) {
+            (false, false) => cx.span_bug(self.span,
+                                          "a struct with named and unnamed \
+                                          fields in generic `derive`"),
+            // named fields
+            (_, false) => Named(named_idents),
+            // tuple structs (includes empty structs)
+            (_, _)     => Unnamed(just_spans)
+        }
+    }
+
+    fn create_subpatterns(&self,
+                          cx: &mut ExtCtxt,
+                          field_paths: Vec<ast::SpannedIdent> ,
+                          mutbl: ast::Mutability)
+                          -> Vec<P<ast::Pat>> {
+        field_paths.iter().map(|path| {
+            cx.pat(path.span,
+                        ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
+        }).collect()
+    }
+
+    fn create_struct_pattern(&self,
+                             cx: &mut ExtCtxt,
+                             struct_path: ast::Path,
+                             struct_def: &'a VariantData,
+                             prefix: &str,
+                             mutbl: ast::Mutability)
+                             -> (P<ast::Pat>, Vec<(Span, Option<Ident>,
+                                                   P<Expr>,
+                                                   &'a [ast::Attribute])>) {
+        if struct_def.fields().is_empty() {
+            return (cx.pat_enum(self.span, struct_path, vec![]), vec![]);
+        }
+
+        let mut paths = Vec::new();
+        let mut ident_expr = Vec::new();
+        let mut struct_type = Unknown;
+
+        for (i, struct_field) in struct_def.fields().iter().enumerate() {
+            let sp = self.set_expn_info(cx, struct_field.span);
+            let opt_id = match struct_field.node.kind {
+                ast::NamedField(ident, _) if (struct_type == Unknown ||
+                                              struct_type == Record) => {
+                    struct_type = Record;
+                    Some(ident)
+                }
+                ast::UnnamedField(..) if (struct_type == Unknown ||
+                                          struct_type == Tuple) => {
+                    struct_type = Tuple;
+                    None
+                }
+                _ => {
+                    cx.span_bug(sp, "a struct with named and unnamed fields in `derive`");
+                }
+            };
+            let ident = cx.ident_of(&format!("{}_{}", prefix, i));
+            paths.push(codemap::Spanned{span: sp, node: ident});
+            let val = cx.expr(
+                sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)))));
+            ident_expr.push((sp, opt_id, val, &struct_field.node.attrs[..]));
+        }
+
+        let subpats = self.create_subpatterns(cx, paths, mutbl);
+
+        // struct_type is definitely not Unknown, since struct_def.fields
+        // must be nonempty to reach here
+        let pattern = if struct_type == Record {
+            let field_pats = subpats.into_iter().zip(&ident_expr)
+                                    .map(|(pat, &(_, id, _, _))| {
+                // id is guaranteed to be Some
+                codemap::Spanned {
+                    span: pat.span,
+                    node: ast::FieldPat { ident: id.unwrap(), pat: pat, is_shorthand: false },
+                }
+            }).collect();
+            cx.pat_struct(self.span, struct_path, field_pats)
+        } else {
+            cx.pat_enum(self.span, struct_path, subpats)
+        };
+
+        (pattern, ident_expr)
+    }
+
+    fn create_enum_variant_pattern(&self,
+                                   cx: &mut ExtCtxt,
+                                   enum_ident: ast::Ident,
+                                   variant: &'a ast::Variant,
+                                   prefix: &str,
+                                   mutbl: ast::Mutability)
+        -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
+        let variant_ident = variant.node.name;
+        let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]);
+        self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl)
+    }
+}
+
+/* helpful premade recipes */
+
+/// Fold the fields. `use_foldl` controls whether this is done
+/// left-to-right (`true`) or right-to-left (`false`).
+pub fn cs_fold<F>(use_foldl: bool,
+                  mut f: F,
+                  base: P<Expr>,
+                  mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
+                  cx: &mut ExtCtxt,
+                  trait_span: Span,
+                  substructure: &Substructure)
+                  -> P<Expr> where
+    F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
+{
+    match *substructure.fields {
+        EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
+            if use_foldl {
+                all_fields.iter().fold(base, |old, field| {
+                    f(cx,
+                      field.span,
+                      old,
+                      field.self_.clone(),
+                      &field.other)
+                })
+            } else {
+                all_fields.iter().rev().fold(base, |old, field| {
+                    f(cx,
+                      field.span,
+                      old,
+                      field.self_.clone(),
+                      &field.other)
+                })
+            }
+        },
+        EnumNonMatchingCollapsed(ref all_args, _, tuple) =>
+            enum_nonmatch_f(cx, trait_span, (&all_args[..], tuple),
+                            substructure.nonself_args),
+        StaticEnum(..) | StaticStruct(..) => {
+            cx.span_bug(trait_span, "static function in `derive`")
+        }
+    }
+}
+
+
+/// Call the method that is being derived on all the fields, and then
+/// process the collected results. i.e.
+///
+/// ```ignore
+/// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1),
+///                  self_2.method(__arg_1_2, __arg_2_2)])
+/// ```
+#[inline]
+pub fn cs_same_method<F>(f: F,
+                         mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
+                         cx: &mut ExtCtxt,
+                         trait_span: Span,
+                         substructure: &Substructure)
+                         -> P<Expr> where
+    F: FnOnce(&mut ExtCtxt, Span, Vec<P<Expr>>) -> P<Expr>,
+{
+    match *substructure.fields {
+        EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => {
+            // call self_n.method(other_1_n, other_2_n, ...)
+            let called = all_fields.iter().map(|field| {
+                cx.expr_method_call(field.span,
+                                    field.self_.clone(),
+                                    substructure.method_ident,
+                                    field.other.iter()
+                                               .map(|e| cx.expr_addr_of(field.span, e.clone()))
+                                               .collect())
+            }).collect();
+
+            f(cx, trait_span, called)
+        },
+        EnumNonMatchingCollapsed(ref all_self_args, _, tuple) =>
+            enum_nonmatch_f(cx, trait_span, (&all_self_args[..], tuple),
+                            substructure.nonself_args),
+        StaticEnum(..) | StaticStruct(..) => {
+            cx.span_bug(trait_span, "static function in `derive`")
+        }
+    }
+}
diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs
new file mode 100644
index 00000000000..0c4a81361ae
--- /dev/null
+++ b/src/libsyntax_ext/deriving/generic/ty.rs
@@ -0,0 +1,284 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use
+//! when specifying impls to be derived.
+
+pub use self::PtrTy::*;
+pub use self::Ty::*;
+
+use syntax::ast;
+use syntax::ast::{Expr,Generics,Ident};
+use syntax::ext::base::ExtCtxt;
+use syntax::ext::build::AstBuilder;
+use syntax::codemap::{Span,respan};
+use syntax::owned_slice::OwnedSlice;
+use syntax::parse::token::special_idents;
+use syntax::ptr::P;
+
+/// The types of pointers
+#[derive(Clone, Eq, PartialEq)]
+#[allow(dead_code)]
+pub enum PtrTy<'a> {
+    /// &'lifetime mut
+    Borrowed(Option<&'a str>, ast::Mutability),
+    /// *mut
+    Raw(ast::Mutability),
+}
+
+/// A path, e.g. `::std::option::Option::<i32>` (global). Has support
+/// for type parameters and a lifetime.
+#[derive(Clone, Eq, PartialEq)]
+pub struct Path<'a> {
+    pub path: Vec<&'a str> ,
+    pub lifetime: Option<&'a str>,
+    pub params: Vec<Box<Ty<'a>>>,
+    pub global: bool,
+}
+
+impl<'a> Path<'a> {
+    pub fn new<'r>(path: Vec<&'r str> ) -> Path<'r> {
+        Path::new_(path, None, Vec::new(), true)
+    }
+    pub fn new_local<'r>(path: &'r str) -> Path<'r> {
+        Path::new_(vec!( path ), None, Vec::new(), false)
+    }
+    pub fn new_<'r>(path: Vec<&'r str> ,
+                    lifetime: Option<&'r str>,
+                    params: Vec<Box<Ty<'r>>>,
+                    global: bool)
+                    -> Path<'r> {
+        Path {
+            path: path,
+            lifetime: lifetime,
+            params: params,
+            global: global
+        }
+    }
+
+    pub fn to_ty(&self,
+                 cx: &ExtCtxt,
+                 span: Span,
+                 self_ty: Ident,
+                 self_generics: &Generics)
+                 -> P<ast::Ty> {
+        cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
+    }
+    pub fn to_path(&self,
+                   cx: &ExtCtxt,
+                   span: Span,
+                   self_ty: Ident,
+                   self_generics: &Generics)
+                   -> ast::Path {
+        let idents = self.path.iter().map(|s| cx.ident_of(*s)).collect();
+        let lt = mk_lifetimes(cx, span, &self.lifetime);
+        let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
+
+        cx.path_all(span, self.global, idents, lt, tys, Vec::new())
+    }
+}
+
+/// A type. Supports pointers, Self, and literals
+#[derive(Clone, Eq, PartialEq)]
+pub enum Ty<'a> {
+    Self_,
+    /// &/Box/ Ty
+    Ptr(Box<Ty<'a>>, PtrTy<'a>),
+    /// mod::mod::Type<[lifetime], [Params...]>, including a plain type
+    /// parameter, and things like `i32`
+    Literal(Path<'a>),
+    /// includes unit
+    Tuple(Vec<Ty<'a>> )
+}
+
+pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
+    Borrowed(None, ast::MutImmutable)
+}
+pub fn borrowed<'r>(ty: Box<Ty<'r>>) -> Ty<'r> {
+    Ptr(ty, borrowed_ptrty())
+}
+
+pub fn borrowed_explicit_self<'r>() -> Option<Option<PtrTy<'r>>> {
+    Some(Some(borrowed_ptrty()))
+}
+
+pub fn borrowed_self<'r>() -> Ty<'r> {
+    borrowed(Box::new(Self_))
+}
+
+pub fn nil_ty<'r>() -> Ty<'r> {
+    Tuple(Vec::new())
+}
+
+fn mk_lifetime(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Option<ast::Lifetime> {
+    match *lt {
+        Some(ref s) => Some(cx.lifetime(span, cx.ident_of(*s).name)),
+        None => None
+    }
+}
+
+fn mk_lifetimes(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Vec<ast::Lifetime> {
+    match *lt {
+        Some(ref s) => vec!(cx.lifetime(span, cx.ident_of(*s).name)),
+        None => vec!()
+    }
+}
+
+impl<'a> Ty<'a> {
+    pub fn to_ty(&self,
+                 cx: &ExtCtxt,
+                 span: Span,
+                 self_ty: Ident,
+                 self_generics: &Generics)
+                 -> P<ast::Ty> {
+        match *self {
+            Ptr(ref ty, ref ptr) => {
+                let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
+                match *ptr {
+                    Borrowed(ref lt, mutbl) => {
+                        let lt = mk_lifetime(cx, span, lt);
+                        cx.ty_rptr(span, raw_ty, lt, mutbl)
+                    }
+                    Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl)
+                }
+            }
+            Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) }
+            Self_  => {
+                cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
+            }
+            Tuple(ref fields) => {
+                let ty = ast::TyTup(fields.iter()
+                    .map(|f| f.to_ty(cx, span, self_ty, self_generics))
+                    .collect());
+                cx.ty(span, ty)
+            }
+        }
+    }
+
+    pub fn to_path(&self,
+                   cx: &ExtCtxt,
+                   span: Span,
+                   self_ty: Ident,
+                   self_generics: &Generics)
+                   -> ast::Path {
+        match *self {
+            Self_ => {
+                let self_params = self_generics.ty_params.map(|ty_param| {
+                    cx.ty_ident(span, ty_param.ident)
+                });
+                let lifetimes = self_generics.lifetimes.iter()
+                                                       .map(|d| d.lifetime)
+                                                       .collect();
+
+                cx.path_all(span, false, vec!(self_ty), lifetimes,
+                            self_params.into_vec(), Vec::new())
+            }
+            Literal(ref p) => {
+                p.to_path(cx, span, self_ty, self_generics)
+            }
+            Ptr(..) => { cx.span_bug(span, "pointer in a path in generic `derive`") }
+            Tuple(..) => { cx.span_bug(span, "tuple in a path in generic `derive`") }
+        }
+    }
+}
+
+
+fn mk_ty_param(cx: &ExtCtxt,
+               span: Span,
+               name: &str,
+               bounds: &[Path],
+               self_ident: Ident,
+               self_generics: &Generics)
+               -> ast::TyParam {
+    let bounds =
+        bounds.iter().map(|b| {
+            let path = b.to_path(cx, span, self_ident, self_generics);
+            cx.typarambound(path)
+        }).collect();
+    cx.typaram(span, cx.ident_of(name), bounds, None)
+}
+
+fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>)
+               -> Generics {
+    Generics {
+        lifetimes: lifetimes,
+        ty_params: OwnedSlice::from_vec(ty_params),
+        where_clause: ast::WhereClause {
+            id: ast::DUMMY_NODE_ID,
+            predicates: Vec::new(),
+        },
+    }
+}
+
+/// Lifetimes and bounds on type parameters
+#[derive(Clone)]
+pub struct LifetimeBounds<'a> {
+    pub lifetimes: Vec<(&'a str, Vec<&'a str>)>,
+    pub bounds: Vec<(&'a str, Vec<Path<'a>>)>,
+}
+
+impl<'a> LifetimeBounds<'a> {
+    pub fn empty() -> LifetimeBounds<'a> {
+        LifetimeBounds {
+            lifetimes: Vec::new(), bounds: Vec::new()
+        }
+    }
+    pub fn to_generics(&self,
+                       cx: &ExtCtxt,
+                       span: Span,
+                       self_ty: Ident,
+                       self_generics: &Generics)
+                       -> Generics {
+        let lifetimes = self.lifetimes.iter().map(|&(ref lt, ref bounds)| {
+            let bounds =
+                bounds.iter().map(
+                    |b| cx.lifetime(span, cx.ident_of(*b).name)).collect();
+            cx.lifetime_def(span, cx.ident_of(*lt).name, bounds)
+        }).collect();
+        let ty_params = self.bounds.iter().map(|t| {
+            match *t {
+                (ref name, ref bounds) => {
+                    mk_ty_param(cx,
+                                span,
+                                *name,
+                                bounds,
+                                self_ty,
+                                self_generics)
+                }
+            }
+        }).collect();
+        mk_generics(lifetimes, ty_params)
+    }
+}
+
+pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option<PtrTy>)
+    -> (P<Expr>, ast::ExplicitSelf) {
+    // this constructs a fresh `self` path, which will match the fresh `self` binding
+    // created below.
+    let self_path = cx.expr_self(span);
+    match *self_ptr {
+        None => {
+            (self_path, respan(span, ast::SelfValue(special_idents::self_)))
+        }
+        Some(ref ptr) => {
+            let self_ty = respan(
+                span,
+                match *ptr {
+                    Borrowed(ref lt, mutbl) => {
+                        let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name));
+                        ast::SelfRegion(lt, mutbl, special_idents::self_)
+                    }
+                    Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition")
+                });
+            let self_expr = cx.expr_deref(span, self_path);
+            (self_expr, self_ty)
+        }
+    }
+}
diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs
new file mode 100644
index 00000000000..6bd21f7c0e0
--- /dev/null
+++ b/src/libsyntax_ext/deriving/hash.rs
@@ -0,0 +1,100 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use deriving::generic::*;
+use deriving::generic::ty::*;
+
+use syntax::ast::{MetaItem, Expr, MutMutable};
+use syntax::codemap::Span;
+use syntax::ext::base::{ExtCtxt, Annotatable};
+use syntax::ext::build::AstBuilder;
+use syntax::ptr::P;
+
+pub fn expand_deriving_hash(cx: &mut ExtCtxt,
+                            span: Span,
+                            mitem: &MetaItem,
+                            item: &Annotatable,
+                            push: &mut FnMut(Annotatable))
+{
+
+    let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None,
+                          vec!(), true);
+    let arg = Path::new_local("__H");
+    let hash_trait_def = TraitDef {
+        span: span,
+        attributes: Vec::new(),
+        path: path,
+        additional_bounds: Vec::new(),
+        generics: LifetimeBounds::empty(),
+        is_unsafe: false,
+        methods: vec!(
+            MethodDef {
+                name: "hash",
+                generics: LifetimeBounds {
+                    lifetimes: Vec::new(),
+                    bounds: vec![("__H",
+                                  vec![path_std!(cx, core::hash::Hasher)])],
+                },
+                explicit_self: borrowed_explicit_self(),
+                args: vec!(Ptr(Box::new(Literal(arg)), Borrowed(None, MutMutable))),
+                ret_ty: nil_ty(),
+                attributes: vec![],
+                is_unsafe: false,
+                combine_substructure: combine_substructure(Box::new(|a, b, c| {
+                    hash_substructure(a, b, c)
+                }))
+            }
+        ),
+        associated_types: Vec::new(),
+    };
+
+    hash_trait_def.expand(cx, mitem, item, push);
+}
+
+fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
+    let state_expr = match (substr.nonself_args.len(), substr.nonself_args.get(0)) {
+        (1, Some(o_f)) => o_f,
+        _ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`")
+    };
+    let call_hash = |span, thing_expr| {
+        let hash_path = {
+            let strs = cx.std_path(&["hash", "Hash", "hash"]);
+
+            cx.expr_path(cx.path_global(span, strs))
+        };
+        let ref_thing = cx.expr_addr_of(span, thing_expr);
+        let expr = cx.expr_call(span, hash_path, vec!(ref_thing, state_expr.clone()));
+        cx.stmt_expr(expr)
+    };
+    let mut stmts = Vec::new();
+
+    let fields = match *substr.fields {
+        Struct(ref fs) => fs,
+        EnumMatching(index, variant, ref fs) => {
+            // Determine the discriminant. We will feed this value to the byte
+            // iteration function.
+            let discriminant = match variant.node.disr_expr {
+                Some(ref d) => d.clone(),
+                None => cx.expr_usize(trait_span, index)
+            };
+
+            stmts.push(call_hash(trait_span, discriminant));
+
+            fs
+        }
+        _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`")
+    };
+
+    for &FieldInfo { ref self_, span, .. } in fields {
+        stmts.push(call_hash(span, self_.clone()));
+    }
+
+    cx.expr_block(cx.block(trait_span, stmts, None))
+}
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
new file mode 100644
index 00000000000..919540724ca
--- /dev/null
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -0,0 +1,202 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The compiler code necessary to implement the `#[derive]` extensions.
+//!
+//! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is
+//! the standard library, and "std" is the core library.
+
+use syntax::ast::{MetaItem, MetaWord};
+use syntax::attr::AttrMetaMethods;
+use syntax::ext::base::{ExtCtxt, SyntaxEnv, Annotatable};
+use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier};
+use syntax::ext::build::AstBuilder;
+use syntax::feature_gate;
+use syntax::codemap::Span;
+use syntax::parse::token::{intern, intern_and_get_ident};
+
+macro_rules! pathvec {
+    ($($x:ident)::+) => (
+        vec![ $( stringify!($x) ),+ ]
+    )
+}
+
+macro_rules! path {
+    ($($x:tt)*) => (
+        ::ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) )
+    )
+}
+
+macro_rules! path_local {
+    ($x:ident) => (
+        ::deriving::generic::ty::Path::new_local(stringify!($x))
+    )
+}
+
+macro_rules! pathvec_std {
+    ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
+        let mut v = pathvec!($($rest)::+);
+        if let Some(s) = $cx.crate_root {
+            v.insert(0, s);
+        }
+        v
+    })
+}
+
+macro_rules! path_std {
+    ($($x:tt)*) => (
+        ::deriving::generic::ty::Path::new( pathvec_std!( $($x)* ) )
+    )
+}
+
+pub mod bounds;
+pub mod clone;
+pub mod encodable;
+pub mod decodable;
+pub mod hash;
+pub mod debug;
+pub mod default;
+pub mod primitive;
+
+#[path="cmp/partial_eq.rs"]
+pub mod partial_eq;
+#[path="cmp/eq.rs"]
+pub mod eq;
+#[path="cmp/partial_ord.rs"]
+pub mod partial_ord;
+#[path="cmp/ord.rs"]
+pub mod ord;
+
+
+pub mod generic;
+
+fn expand_derive(cx: &mut ExtCtxt,
+                 span: Span,
+                 mitem: &MetaItem,
+                 annotatable: Annotatable)
+                 -> Annotatable {
+    annotatable.map_item_or(|item| {
+        item.map(|mut item| {
+            if mitem.value_str().is_some() {
+                cx.span_err(mitem.span, "unexpected value in `derive`");
+            }
+
+            let traits = mitem.meta_item_list().unwrap_or(&[]);
+            if traits.is_empty() {
+                cx.span_warn(mitem.span, "empty trait list in `derive`");
+            }
+
+            for titem in traits.iter().rev() {
+                let tname = match titem.node {
+                    MetaWord(ref tname) => tname,
+                    _ => {
+                        cx.span_err(titem.span, "malformed `derive` entry");
+                        continue;
+                    }
+                };
+
+                if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) {
+                    feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
+                                                   "custom_derive",
+                                                   titem.span,
+                                                   feature_gate::GateIssue::Language,
+                                                   feature_gate::EXPLAIN_CUSTOM_DERIVE);
+                    continue;
+                }
+
+                // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
+                item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span,
+                    intern_and_get_ident(&format!("derive_{}", tname)))));
+            }
+
+            item
+        })
+    }, |a| {
+        cx.span_err(span, "`derive` can only be applied to items");
+        a
+    })
+}
+
+macro_rules! derive_traits {
+    ($( $name:expr => $func:path, )+) => {
+        pub fn register_all(env: &mut SyntaxEnv) {
+            // Define the #[derive_*] extensions.
+            $({
+                struct DeriveExtension;
+
+                impl MultiItemDecorator for DeriveExtension {
+                    fn expand(&self,
+                              ecx: &mut ExtCtxt,
+                              sp: Span,
+                              mitem: &MetaItem,
+                              annotatable: &Annotatable,
+                              push: &mut FnMut(Annotatable)) {
+                        warn_if_deprecated(ecx, sp, $name);
+                        $func(ecx, sp, mitem, annotatable, push);
+                    }
+                }
+
+                env.insert(intern(concat!("derive_", $name)),
+                           MultiDecorator(Box::new(DeriveExtension)));
+            })+
+
+            env.insert(intern("derive"),
+                       MultiModifier(Box::new(expand_derive)));
+        }
+
+        fn is_builtin_trait(name: &str) -> bool {
+            match name {
+                $( $name )|+ => true,
+                _ => false,
+            }
+        }
+    }
+}
+
+derive_traits! {
+    "Clone" => clone::expand_deriving_clone,
+
+    "Hash" => hash::expand_deriving_hash,
+
+    "RustcEncodable" => encodable::expand_deriving_rustc_encodable,
+
+    "RustcDecodable" => decodable::expand_deriving_rustc_decodable,
+
+    "PartialEq" => partial_eq::expand_deriving_partial_eq,
+    "Eq" => eq::expand_deriving_eq,
+    "PartialOrd" => partial_ord::expand_deriving_partial_ord,
+    "Ord" => ord::expand_deriving_ord,
+
+    "Debug" => debug::expand_deriving_debug,
+
+    "Default" => default::expand_deriving_default,
+
+    "FromPrimitive" => primitive::expand_deriving_from_primitive,
+
+    "Send" => bounds::expand_deriving_unsafe_bound,
+    "Sync" => bounds::expand_deriving_unsafe_bound,
+    "Copy" => bounds::expand_deriving_copy,
+
+    // deprecated
+    "Encodable" => encodable::expand_deriving_encodable,
+    "Decodable" => decodable::expand_deriving_decodable,
+}
+
+#[inline] // because `name` is a compile-time constant
+fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
+    if let Some(replacement) = match name {
+        "Encodable" => Some("RustcEncodable"),
+        "Decodable" => Some("RustcDecodable"),
+        _ => None,
+    } {
+        ecx.span_warn(sp, &format!("derive({}) is deprecated in favor of derive({})",
+                                   name, replacement));
+    }
+}
diff --git a/src/libsyntax_ext/deriving/primitive.rs b/src/libsyntax_ext/deriving/primitive.rs
new file mode 100644
index 00000000000..121fe01976e
--- /dev/null
+++ b/src/libsyntax_ext/deriving/primitive.rs
@@ -0,0 +1,142 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use deriving::generic::*;
+use deriving::generic::ty::*;
+
+use syntax::ast::{MetaItem, Expr};
+use syntax::ast;
+use syntax::codemap::Span;
+use syntax::ext::base::{ExtCtxt, Annotatable};
+use syntax::ext::build::AstBuilder;
+use syntax::parse::token::InternedString;
+use syntax::ptr::P;
+
+pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
+                                      span: Span,
+                                      mitem: &MetaItem,
+                                      item: &Annotatable,
+                                      push: &mut FnMut(Annotatable))
+{
+    let inline = cx.meta_word(span, InternedString::new("inline"));
+    let attrs = vec!(cx.attribute(span, inline));
+    let trait_def = TraitDef {
+        span: span,
+        attributes: Vec::new(),
+        path: path_std!(cx, core::num::FromPrimitive),
+        additional_bounds: Vec::new(),
+        generics: LifetimeBounds::empty(),
+        is_unsafe: false,
+        methods: vec!(
+            MethodDef {
+                name: "from_i64",
+                generics: LifetimeBounds::empty(),
+                explicit_self: None,
+                args: vec!(Literal(path_local!(i64))),
+                ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
+                                           None,
+                                           vec!(Box::new(Self_)),
+                                           true)),
+                // #[inline] liable to cause code-bloat
+                attributes: attrs.clone(),
+                is_unsafe: false,
+                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
+                    cs_from("i64", c, s, sub)
+                })),
+            },
+            MethodDef {
+                name: "from_u64",
+                generics: LifetimeBounds::empty(),
+                explicit_self: None,
+                args: vec!(Literal(path_local!(u64))),
+                ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
+                                           None,
+                                           vec!(Box::new(Self_)),
+                                           true)),
+                // #[inline] liable to cause code-bloat
+                attributes: attrs,
+                is_unsafe: false,
+                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
+                    cs_from("u64", c, s, sub)
+                })),
+            }
+        ),
+        associated_types: Vec::new(),
+    };
+
+    trait_def.expand(cx, mitem, item, push)
+}
+
+fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
+    let n = match (substr.nonself_args.len(), substr.nonself_args.get(0)) {
+        (1, Some(o_f)) => o_f,
+        _ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(FromPrimitive)`")
+    };
+
+    match *substr.fields {
+        StaticStruct(..) => {
+            cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs");
+            return cx.expr_fail(trait_span, InternedString::new(""));
+        }
+        StaticEnum(enum_def, _) => {
+            if enum_def.variants.is_empty() {
+                cx.span_err(trait_span,
+                            "`FromPrimitive` cannot be derived for enums with no variants");
+                return cx.expr_fail(trait_span, InternedString::new(""));
+            }
+
+            let mut arms = Vec::new();
+
+            for variant in &enum_def.variants {
+                let def = &variant.node.data;
+                if !def.is_unit() {
+                    cx.span_err(trait_span, "`FromPrimitive` cannot be derived \
+                                             for enums with non-unit variants");
+                    return cx.expr_fail(trait_span,
+                                        InternedString::new(""));
+                }
+
+                let span = variant.span;
+
+                // expr for `$n == $variant as $name`
+                let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
+                let variant = cx.expr_path(path);
+                let ty = cx.ty_ident(span, cx.ident_of(name));
+                let cast = cx.expr_cast(span, variant.clone(), ty);
+                let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast);
+
+                // expr for `Some($variant)`
+                let body = cx.expr_some(span, variant);
+
+                // arm for `_ if $guard => $body`
+                let arm = ast::Arm {
+                    attrs: vec!(),
+                    pats: vec!(cx.pat_wild(span)),
+                    guard: Some(guard),
+                    body: body,
+                };
+
+                arms.push(arm);
+            }
+
+            // arm for `_ => None`
+            let arm = ast::Arm {
+                attrs: vec!(),
+                pats: vec!(cx.pat_wild(trait_span)),
+                guard: None,
+                body: cx.expr_none(trait_span),
+            };
+            arms.push(arm);
+
+            cx.expr_match(trait_span, n.clone(), arms)
+        }
+        _ => cx.span_bug(trait_span, "expected StaticEnum in derive(FromPrimitive)")
+    }
+}
diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs
new file mode 100644
index 00000000000..f1dd6854a3a
--- /dev/null
+++ b/src/libsyntax_ext/env.rs
@@ -0,0 +1,106 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*
+ * The compiler code necessary to support the env! extension.  Eventually this
+ * should all get sucked into either the compiler syntax extension plugin
+ * interface.
+ */
+
+use syntax::ast;
+use syntax::codemap::Span;
+use syntax::ext::base::*;
+use syntax::ext::base;
+use syntax::ext::build::AstBuilder;
+use syntax::parse::token;
+
+use std::env;
+
+pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
+                              -> Box<base::MacResult+'cx> {
+    let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") {
+        None => return DummyResult::expr(sp),
+        Some(v) => v
+    };
+
+    let e = match env::var(&var[..]) {
+      Err(..) => {
+          cx.expr_path(cx.path_all(sp,
+                                   true,
+                                   cx.std_path(&["option", "Option", "None"]),
+                                   Vec::new(),
+                                   vec!(cx.ty_rptr(sp,
+                                                   cx.ty_ident(sp,
+                                                        cx.ident_of("str")),
+                                                   Some(cx.lifetime(sp,
+                                                        cx.ident_of(
+                                                            "'static").name)),
+                                                   ast::MutImmutable)),
+                                   Vec::new()))
+      }
+      Ok(s) => {
+          cx.expr_call_global(sp,
+                              cx.std_path(&["option", "Option", "Some"]),
+                              vec!(cx.expr_str(sp,
+                                               token::intern_and_get_ident(
+                                          &s[..]))))
+      }
+    };
+    MacEager::expr(e)
+}
+
+pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
+                       -> Box<base::MacResult+'cx> {
+    let mut exprs = match get_exprs_from_tts(cx, sp, tts) {
+        Some(ref exprs) if exprs.is_empty() => {
+            cx.span_err(sp, "env! takes 1 or 2 arguments");
+            return DummyResult::expr(sp);
+        }
+        None => return DummyResult::expr(sp),
+        Some(exprs) => exprs.into_iter()
+    };
+
+    let var = match expr_to_string(cx,
+                                exprs.next().unwrap(),
+                                "expected string literal") {
+        None => return DummyResult::expr(sp),
+        Some((v, _style)) => v
+    };
+    let msg = match exprs.next() {
+        None => {
+            token::intern_and_get_ident(&format!("environment variable `{}` \
+                                                 not defined",
+                                                var))
+        }
+        Some(second) => {
+            match expr_to_string(cx, second, "expected string literal") {
+                None => return DummyResult::expr(sp),
+                Some((s, _style)) => s
+            }
+        }
+    };
+
+    match exprs.next() {
+        None => {}
+        Some(_) => {
+            cx.span_err(sp, "env! takes 1 or 2 arguments");
+            return DummyResult::expr(sp);
+        }
+    }
+
+    let e = match env::var(&var[..]) {
+        Err(_) => {
+            cx.span_err(sp, &msg);
+            cx.expr_usize(sp, 0)
+        }
+        Ok(s) => cx.expr_str(sp, token::intern_and_get_ident(&s))
+    };
+    MacEager::expr(e)
+}
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
new file mode 100644
index 00000000000..24094f797e6
--- /dev/null
+++ b/src/libsyntax_ext/format.rs
@@ -0,0 +1,716 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use self::ArgumentType::*;
+use self::Position::*;
+
+use fmt_macros as parse;
+
+use syntax::ast;
+use syntax::codemap::{Span, respan};
+use syntax::ext::base::*;
+use syntax::ext::base;
+use syntax::ext::build::AstBuilder;
+use syntax::fold::Folder;
+use syntax::parse::token::special_idents;
+use syntax::parse::token;
+use syntax::ptr::P;
+
+use std::collections::HashMap;
+
+#[derive(PartialEq)]
+enum ArgumentType {
+    Known(String),
+    Unsigned
+}
+
+enum Position {
+    Exact(usize),
+    Named(String),
+}
+
+struct Context<'a, 'b:'a> {
+    ecx: &'a mut ExtCtxt<'b>,
+    /// The macro's call site. References to unstable formatting internals must
+    /// use this span to pass the stability checker.
+    macsp: Span,
+    /// The span of the format string literal.
+    fmtsp: Span,
+
+    /// Parsed argument expressions and the types that we've found so far for
+    /// them.
+    args: Vec<P<ast::Expr>>,
+    arg_types: Vec<Option<ArgumentType>>,
+    /// Parsed named expressions and the types that we've found for them so far.
+    /// Note that we keep a side-array of the ordering of the named arguments
+    /// found to be sure that we can translate them in the same order that they
+    /// were declared in.
+    names: HashMap<String, P<ast::Expr>>,
+    name_types: HashMap<String, ArgumentType>,
+    name_ordering: Vec<String>,
+
+    /// The latest consecutive literal strings, or empty if there weren't any.
+    literal: String,
+
+    /// Collection of the compiled `rt::Argument` structures
+    pieces: Vec<P<ast::Expr>>,
+    /// Collection of string literals
+    str_pieces: Vec<P<ast::Expr>>,
+    /// Stays `true` if all formatting parameters are default (as in "{}{}").
+    all_pieces_simple: bool,
+
+    name_positions: HashMap<String, usize>,
+
+    /// Updated as arguments are consumed or methods are entered
+    nest_level: usize,
+    next_arg: usize,
+}
+
+/// Parses the arguments from the given list of tokens, returning None
+/// if there's a parse error so we can continue parsing other format!
+/// expressions.
+///
+/// If parsing succeeds, the return value is:
+/// ```ignore
+/// Some((fmtstr, unnamed arguments, ordering of named arguments,
+///       named arguments))
+/// ```
+fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
+              -> Option<(P<ast::Expr>, Vec<P<ast::Expr>>, Vec<String>,
+                         HashMap<String, P<ast::Expr>>)> {
+    let mut args = Vec::new();
+    let mut names = HashMap::<String, P<ast::Expr>>::new();
+    let mut order = Vec::new();
+
+    let mut p = ecx.new_parser_from_tts(tts);
+
+    if p.token == token::Eof {
+        ecx.span_err(sp, "requires at least a format string argument");
+        return None;
+    }
+    let fmtstr = panictry!(p.parse_expr());
+    let mut named = false;
+    while p.token != token::Eof {
+        if !panictry!(p.eat(&token::Comma)) {
+            ecx.span_err(sp, "expected token: `,`");
+            return None;
+        }
+        if p.token == token::Eof { break } // accept trailing commas
+        if named || (p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq)) {
+            named = true;
+            let ident = match p.token {
+                token::Ident(i, _) => {
+                    panictry!(p.bump());
+                    i
+                }
+                _ if named => {
+                    ecx.span_err(p.span,
+                                 "expected ident, positional arguments \
+                                 cannot follow named arguments");
+                    return None;
+                }
+                _ => {
+                    ecx.span_err(p.span,
+                                 &format!("expected ident for named argument, found `{}`",
+                                         p.this_token_to_string()));
+                    return None;
+                }
+            };
+            let name: &str = &ident.name.as_str();
+
+            panictry!(p.expect(&token::Eq));
+            let e = panictry!(p.parse_expr());
+            match names.get(name) {
+                None => {}
+                Some(prev) => {
+                    ecx.span_err(e.span,
+                                 &format!("duplicate argument named `{}`",
+                                         name));
+                    ecx.parse_sess.span_diagnostic.span_note(prev.span, "previously here");
+                    continue
+                }
+            }
+            order.push(name.to_string());
+            names.insert(name.to_string(), e);
+        } else {
+            args.push(panictry!(p.parse_expr()));
+        }
+    }
+    Some((fmtstr, args, order, names))
+}
+
+impl<'a, 'b> Context<'a, 'b> {
+    /// Verifies one piece of a parse string. All errors are not emitted as
+    /// fatal so we can continue giving errors about this and possibly other
+    /// format strings.
+    fn verify_piece(&mut self, p: &parse::Piece) {
+        match *p {
+            parse::String(..) => {}
+            parse::NextArgument(ref arg) => {
+                // width/precision first, if they have implicit positional
+                // parameters it makes more sense to consume them first.
+                self.verify_count(arg.format.width);
+                self.verify_count(arg.format.precision);
+
+                // argument second, if it's an implicit positional parameter
+                // it's written second, so it should come after width/precision.
+                let pos = match arg.position {
+                    parse::ArgumentNext => {
+                        let i = self.next_arg;
+                        if self.check_positional_ok() {
+                            self.next_arg += 1;
+                        }
+                        Exact(i)
+                    }
+                    parse::ArgumentIs(i) => Exact(i),
+                    parse::ArgumentNamed(s) => Named(s.to_string()),
+                };
+
+                let ty = Known(arg.format.ty.to_string());
+                self.verify_arg_type(pos, ty);
+            }
+        }
+    }
+
+    fn verify_count(&mut self, c: parse::Count) {
+        match c {
+            parse::CountImplied | parse::CountIs(..) => {}
+            parse::CountIsParam(i) => {
+                self.verify_arg_type(Exact(i), Unsigned);
+            }
+            parse::CountIsName(s) => {
+                self.verify_arg_type(Named(s.to_string()), Unsigned);
+            }
+            parse::CountIsNextParam => {
+                if self.check_positional_ok() {
+                    let next_arg = self.next_arg;
+                    self.verify_arg_type(Exact(next_arg), Unsigned);
+                    self.next_arg += 1;
+                }
+            }
+        }
+    }
+
+    fn check_positional_ok(&mut self) -> bool {
+        if self.nest_level != 0 {
+            self.ecx.span_err(self.fmtsp, "cannot use implicit positional \
+                                           arguments nested inside methods");
+            false
+        } else {
+            true
+        }
+    }
+
+    fn describe_num_args(&self) -> String {
+        match self.args.len() {
+            0 => "no arguments given".to_string(),
+            1 => "there is 1 argument".to_string(),
+            x => format!("there are {} arguments", x),
+        }
+    }
+
+    fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
+        match arg {
+            Exact(arg) => {
+                if self.args.len() <= arg {
+                    let msg = format!("invalid reference to argument `{}` ({})",
+                                      arg, self.describe_num_args());
+
+                    self.ecx.span_err(self.fmtsp, &msg[..]);
+                    return;
+                }
+                {
+                    let arg_type = match self.arg_types[arg] {
+                        None => None,
+                        Some(ref x) => Some(x)
+                    };
+                    self.verify_same(self.args[arg].span, &ty, arg_type);
+                }
+                if self.arg_types[arg].is_none() {
+                    self.arg_types[arg] = Some(ty);
+                }
+            }
+
+            Named(name) => {
+                let span = match self.names.get(&name) {
+                    Some(e) => e.span,
+                    None => {
+                        let msg = format!("there is no argument named `{}`", name);
+                        self.ecx.span_err(self.fmtsp, &msg[..]);
+                        return;
+                    }
+                };
+                self.verify_same(span, &ty, self.name_types.get(&name));
+                if !self.name_types.contains_key(&name) {
+                    self.name_types.insert(name.clone(), ty);
+                }
+                // Assign this named argument a slot in the arguments array if
+                // it hasn't already been assigned a slot.
+                if !self.name_positions.contains_key(&name) {
+                    let slot = self.name_positions.len();
+                    self.name_positions.insert(name, slot);
+                }
+            }
+        }
+    }
+
+    /// When we're keeping track of the types that are declared for certain
+    /// arguments, we assume that `None` means we haven't seen this argument
+    /// yet, `Some(None)` means that we've seen the argument, but no format was
+    /// specified, and `Some(Some(x))` means that the argument was declared to
+    /// have type `x`.
+    ///
+    /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true
+    /// that: `Some(None) == Some(Some(x))`
+    fn verify_same(&self,
+                   sp: Span,
+                   ty: &ArgumentType,
+                   before: Option<&ArgumentType>) {
+        let cur = match before {
+            None => return,
+            Some(t) => t,
+        };
+        if *ty == *cur {
+            return
+        }
+        match (cur, ty) {
+            (&Known(ref cur), &Known(ref ty)) => {
+                self.ecx.span_err(sp,
+                                  &format!("argument redeclared with type `{}` when \
+                                           it was previously `{}`",
+                                          *ty,
+                                          *cur));
+            }
+            (&Known(ref cur), _) => {
+                self.ecx.span_err(sp,
+                                  &format!("argument used to format with `{}` was \
+                                           attempted to not be used for formatting",
+                                           *cur));
+            }
+            (_, &Known(ref ty)) => {
+                self.ecx.span_err(sp,
+                                  &format!("argument previously used as a format \
+                                           argument attempted to be used as `{}`",
+                                           *ty));
+            }
+            (_, _) => {
+                self.ecx.span_err(sp, "argument declared with multiple formats");
+            }
+        }
+    }
+
+    fn rtpath(ecx: &ExtCtxt, s: &str) -> Vec<ast::Ident> {
+        ecx.std_path(&["fmt", "rt", "v1", s])
+    }
+
+    fn trans_count(&self, c: parse::Count) -> P<ast::Expr> {
+        let sp = self.macsp;
+        let count = |c, arg| {
+            let mut path = Context::rtpath(self.ecx, "Count");
+            path.push(self.ecx.ident_of(c));
+            match arg {
+                Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]),
+                None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
+            }
+        };
+        match c {
+            parse::CountIs(i) => count("Is", Some(self.ecx.expr_usize(sp, i))),
+            parse::CountIsParam(i) => {
+                count("Param", Some(self.ecx.expr_usize(sp, i)))
+            }
+            parse::CountImplied => count("Implied", None),
+            parse::CountIsNextParam => count("NextParam", None),
+            parse::CountIsName(n) => {
+                let i = match self.name_positions.get(n) {
+                    Some(&i) => i,
+                    None => 0, // error already emitted elsewhere
+                };
+                let i = i + self.args.len();
+                count("Param", Some(self.ecx.expr_usize(sp, i)))
+            }
+        }
+    }
+
+    /// Translate the accumulated string literals to a literal expression
+    fn trans_literal_string(&mut self) -> P<ast::Expr> {
+        let sp = self.fmtsp;
+        let s = token::intern_and_get_ident(&self.literal);
+        self.literal.clear();
+        self.ecx.expr_str(sp, s)
+    }
+
+    /// Translate a `parse::Piece` to a static `rt::Argument` or append
+    /// to the `literal` string.
+    fn trans_piece(&mut self, piece: &parse::Piece) -> Option<P<ast::Expr>> {
+        let sp = self.macsp;
+        match *piece {
+            parse::String(s) => {
+                self.literal.push_str(s);
+                None
+            }
+            parse::NextArgument(ref arg) => {
+                // Translate the position
+                let pos = {
+                    let pos = |c, arg| {
+                        let mut path = Context::rtpath(self.ecx, "Position");
+                        path.push(self.ecx.ident_of(c));
+                        match arg {
+                            Some(i) => {
+                                let arg = self.ecx.expr_usize(sp, i);
+                                self.ecx.expr_call_global(sp, path, vec![arg])
+                            }
+                            None => {
+                                self.ecx.expr_path(self.ecx.path_global(sp, path))
+                            }
+                        }
+                    };
+                    match arg.position {
+                        // These two have a direct mapping
+                        parse::ArgumentNext => pos("Next", None),
+                        parse::ArgumentIs(i) => pos("At", Some(i)),
+
+                        // Named arguments are converted to positional arguments
+                        // at the end of the list of arguments
+                        parse::ArgumentNamed(n) => {
+                            let i = match self.name_positions.get(n) {
+                                Some(&i) => i,
+                                None => 0, // error already emitted elsewhere
+                            };
+                            let i = i + self.args.len();
+                            pos("At", Some(i))
+                        }
+                    }
+                };
+
+                let simple_arg = parse::Argument {
+                    position: parse::ArgumentNext,
+                    format: parse::FormatSpec {
+                        fill: arg.format.fill,
+                        align: parse::AlignUnknown,
+                        flags: 0,
+                        precision: parse::CountImplied,
+                        width: parse::CountImplied,
+                        ty: arg.format.ty
+                    }
+                };
+
+                let fill = match arg.format.fill { Some(c) => c, None => ' ' };
+
+                if *arg != simple_arg || fill != ' ' {
+                    self.all_pieces_simple = false;
+                }
+
+                // Translate the format
+                let fill = self.ecx.expr_lit(sp, ast::LitChar(fill));
+                let align = |name| {
+                    let mut p = Context::rtpath(self.ecx, "Alignment");
+                    p.push(self.ecx.ident_of(name));
+                    self.ecx.path_global(sp, p)
+                };
+                let align = match arg.format.align {
+                    parse::AlignLeft => align("Left"),
+                    parse::AlignRight => align("Right"),
+                    parse::AlignCenter => align("Center"),
+                    parse::AlignUnknown => align("Unknown"),
+                };
+                let align = self.ecx.expr_path(align);
+                let flags = self.ecx.expr_u32(sp, arg.format.flags);
+                let prec = self.trans_count(arg.format.precision);
+                let width = self.trans_count(arg.format.width);
+                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "FormatSpec"));
+                let fmt = self.ecx.expr_struct(sp, path, vec!(
+                    self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
+                    self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
+                    self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
+                    self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
+                    self.ecx.field_imm(sp, self.ecx.ident_of("width"), width)));
+
+                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "Argument"));
+                Some(self.ecx.expr_struct(sp, path, vec!(
+                    self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
+                    self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt))))
+            }
+        }
+    }
+
+    fn static_array(ecx: &mut ExtCtxt,
+                    name: &str,
+                    piece_ty: P<ast::Ty>,
+                    pieces: Vec<P<ast::Expr>>)
+                    -> P<ast::Expr> {
+        let sp = piece_ty.span;
+        let ty = ecx.ty_rptr(sp,
+            ecx.ty(sp, ast::TyVec(piece_ty)),
+            Some(ecx.lifetime(sp, special_idents::static_lifetime.name)),
+            ast::MutImmutable);
+        let slice = ecx.expr_vec_slice(sp, pieces);
+        // static instead of const to speed up codegen by not requiring this to be inlined
+        let st = ast::ItemStatic(ty, ast::MutImmutable, slice);
+
+        let name = ecx.ident_of(name);
+        let item = ecx.item(sp, name, vec![], st);
+        let decl = respan(sp, ast::DeclItem(item));
+
+        // Wrap the declaration in a block so that it forms a single expression.
+        ecx.expr_block(ecx.block(sp,
+            vec![P(respan(sp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)))],
+            Some(ecx.expr_ident(sp, name))))
+    }
+
+    /// Actually builds the expression which the iformat! block will be expanded
+    /// to
+    fn into_expr(mut self) -> P<ast::Expr> {
+        let mut locals = Vec::new();
+        let mut names = vec![None; self.name_positions.len()];
+        let mut pats = Vec::new();
+        let mut heads = Vec::new();
+
+        // First, build up the static array which will become our precompiled
+        // format "string"
+        let static_lifetime = self.ecx.lifetime(self.fmtsp, special_idents::static_lifetime.name);
+        let piece_ty = self.ecx.ty_rptr(
+                self.fmtsp,
+                self.ecx.ty_ident(self.fmtsp, self.ecx.ident_of("str")),
+                Some(static_lifetime),
+                ast::MutImmutable);
+        let pieces = Context::static_array(self.ecx,
+                                           "__STATIC_FMTSTR",
+                                           piece_ty,
+                                           self.str_pieces);
+
+
+        // Right now there is a bug such that for the expression:
+        //      foo(bar(&1))
+        // the lifetime of `1` doesn't outlast the call to `bar`, so it's not
+        // valid for the call to `foo`. To work around this all arguments to the
+        // format! string are shoved into locals. Furthermore, we shove the address
+        // of each variable because we don't want to move out of the arguments
+        // passed to this function.
+        for (i, e) in self.args.into_iter().enumerate() {
+            let arg_ty = match self.arg_types[i].as_ref() {
+                Some(ty) => ty,
+                None => continue // error already generated
+            };
+
+            let name = self.ecx.ident_of(&format!("__arg{}", i));
+            pats.push(self.ecx.pat_ident(e.span, name));
+            locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty,
+                                            self.ecx.expr_ident(e.span, name)));
+            heads.push(self.ecx.expr_addr_of(e.span, e));
+        }
+        for name in &self.name_ordering {
+            let e = match self.names.remove(name) {
+                Some(e) => e,
+                None => continue
+            };
+            let arg_ty = match self.name_types.get(name) {
+                Some(ty) => ty,
+                None => continue
+            };
+
+            let lname = self.ecx.ident_of(&format!("__arg{}",
+                                                  *name));
+            pats.push(self.ecx.pat_ident(e.span, lname));
+            names[*self.name_positions.get(name).unwrap()] =
+                Some(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty,
+                                         self.ecx.expr_ident(e.span, lname)));
+            heads.push(self.ecx.expr_addr_of(e.span, e));
+        }
+
+        // Now create a vector containing all the arguments
+        let args = locals.into_iter().chain(names.into_iter().map(|a| a.unwrap()));
+
+        let args_array = self.ecx.expr_vec(self.fmtsp, args.collect());
+
+        // Constructs an AST equivalent to:
+        //
+        //      match (&arg0, &arg1) {
+        //          (tmp0, tmp1) => args_array
+        //      }
+        //
+        // It was:
+        //
+        //      let tmp0 = &arg0;
+        //      let tmp1 = &arg1;
+        //      args_array
+        //
+        // Because of #11585 the new temporary lifetime rule, the enclosing
+        // statements for these temporaries become the let's themselves.
+        // If one or more of them are RefCell's, RefCell borrow() will also
+        // end there; they don't last long enough for args_array to use them.
+        // The match expression solves the scope problem.
+        //
+        // Note, it may also very well be transformed to:
+        //
+        //      match arg0 {
+        //          ref tmp0 => {
+        //              match arg1 => {
+        //                  ref tmp1 => args_array } } }
+        //
+        // But the nested match expression is proved to perform not as well
+        // as series of let's; the first approach does.
+        let pat = self.ecx.pat_tuple(self.fmtsp, pats);
+        let arm = self.ecx.arm(self.fmtsp, vec!(pat), args_array);
+        let head = self.ecx.expr(self.fmtsp, ast::ExprTup(heads));
+        let result = self.ecx.expr_match(self.fmtsp, head, vec!(arm));
+
+        let args_slice = self.ecx.expr_addr_of(self.fmtsp, result);
+
+        // Now create the fmt::Arguments struct with all our locals we created.
+        let (fn_name, fn_args) = if self.all_pieces_simple {
+            ("new_v1", vec![pieces, args_slice])
+        } else {
+            // Build up the static array which will store our precompiled
+            // nonstandard placeholders, if there are any.
+            let piece_ty = self.ecx.ty_path(self.ecx.path_global(
+                    self.macsp,
+                    Context::rtpath(self.ecx, "Argument")));
+            let fmt = Context::static_array(self.ecx,
+                                            "__STATIC_FMTARGS",
+                                            piece_ty,
+                                            self.pieces);
+
+            ("new_v1_formatted", vec![pieces, args_slice, fmt])
+        };
+
+        let path = self.ecx.std_path(&["fmt", "Arguments", fn_name]);
+        self.ecx.expr_call_global(self.macsp, path, fn_args)
+    }
+
+    fn format_arg(ecx: &ExtCtxt, macsp: Span, sp: Span,
+                  ty: &ArgumentType, arg: P<ast::Expr>)
+                  -> P<ast::Expr> {
+        let trait_ = match *ty {
+            Known(ref tyname) => {
+                match &tyname[..] {
+                    ""  => "Display",
+                    "?" => "Debug",
+                    "e" => "LowerExp",
+                    "E" => "UpperExp",
+                    "o" => "Octal",
+                    "p" => "Pointer",
+                    "b" => "Binary",
+                    "x" => "LowerHex",
+                    "X" => "UpperHex",
+                    _ => {
+                        ecx.span_err(sp,
+                                     &format!("unknown format trait `{}`",
+                                             *tyname));
+                        "Dummy"
+                    }
+                }
+            }
+            Unsigned => {
+                let path = ecx.std_path(&["fmt", "ArgumentV1", "from_usize"]);
+                return ecx.expr_call_global(macsp, path, vec![arg])
+            }
+        };
+
+        let path = ecx.std_path(&["fmt", trait_, "fmt"]);
+        let format_fn = ecx.path_global(sp, path);
+        let path = ecx.std_path(&["fmt", "ArgumentV1", "new"]);
+        ecx.expr_call_global(macsp, path, vec![arg, ecx.expr_path(format_fn)])
+    }
+}
+
+pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span,
+                               tts: &[ast::TokenTree])
+                               -> Box<base::MacResult+'cx> {
+
+    match parse_args(ecx, sp, tts) {
+        Some((efmt, args, order, names)) => {
+            MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt,
+                                                      args, order, names))
+        }
+        None => DummyResult::expr(sp)
+    }
+}
+
+/// Take the various parts of `format_args!(efmt, args..., name=names...)`
+/// and construct the appropriate formatting expression.
+pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
+                                    efmt: P<ast::Expr>,
+                                    args: Vec<P<ast::Expr>>,
+                                    name_ordering: Vec<String>,
+                                    names: HashMap<String, P<ast::Expr>>)
+                                    -> P<ast::Expr> {
+    let arg_types: Vec<_> = (0..args.len()).map(|_| None).collect();
+    let macsp = ecx.call_site();
+    // Expand the format literal so that efmt.span will have a backtrace. This
+    // is essential for locating a bug when the format literal is generated in
+    // a macro. (e.g. println!("{}"), which uses concat!($fmt, "\n")).
+    let efmt = ecx.expander().fold_expr(efmt);
+    let mut cx = Context {
+        ecx: ecx,
+        args: args,
+        arg_types: arg_types,
+        names: names,
+        name_positions: HashMap::new(),
+        name_types: HashMap::new(),
+        name_ordering: name_ordering,
+        nest_level: 0,
+        next_arg: 0,
+        literal: String::new(),
+        pieces: Vec::new(),
+        str_pieces: Vec::new(),
+        all_pieces_simple: true,
+        macsp: macsp,
+        fmtsp: efmt.span,
+    };
+    let fmt = match expr_to_string(cx.ecx,
+                                   efmt,
+                                   "format argument must be a string literal.") {
+        Some((fmt, _)) => fmt,
+        None => return DummyResult::raw_expr(sp)
+    };
+
+    let mut parser = parse::Parser::new(&fmt);
+
+    loop {
+        match parser.next() {
+            Some(piece) => {
+                if !parser.errors.is_empty() { break }
+                cx.verify_piece(&piece);
+                match cx.trans_piece(&piece) {
+                    Some(piece) => {
+                        let s = cx.trans_literal_string();
+                        cx.str_pieces.push(s);
+                        cx.pieces.push(piece);
+                    }
+                    None => {}
+                }
+            }
+            None => break
+        }
+    }
+    if !parser.errors.is_empty() {
+        cx.ecx.span_err(cx.fmtsp, &format!("invalid format string: {}",
+                                          parser.errors.remove(0)));
+        return DummyResult::raw_expr(sp);
+    }
+    if !cx.literal.is_empty() {
+        let s = cx.trans_literal_string();
+        cx.str_pieces.push(s);
+    }
+
+    // Make sure that all arguments were used and all arguments have types.
+    for (i, ty) in cx.arg_types.iter().enumerate() {
+        if ty.is_none() {
+            cx.ecx.span_err(cx.args[i].span, "argument never used");
+        }
+    }
+    for (name, e) in &cx.names {
+        if !cx.name_types.contains_key(name) {
+            cx.ecx.span_err(e.span, "named argument never used");
+        }
+    }
+
+    cx.into_expr()
+}
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
new file mode 100644
index 00000000000..49c2618d51b
--- /dev/null
+++ b/src/libsyntax_ext/lib.rs
@@ -0,0 +1,82 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Syntax extensions in the Rust compiler.
+
+#![crate_name = "syntax_ext"]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+       html_root_url = "https://doc.rust-lang.org/nightly/")]
+
+#![feature(rustc_private)]
+#![feature(str_char)]
+
+extern crate fmt_macros;
+extern crate syntax;
+
+use syntax::ext::base::{MacroExpanderFn, NormalTT};
+use syntax::ext::base::{SyntaxEnv, SyntaxExtension};
+use syntax::parse::token::intern;
+
+// A variant of 'try!' that panics on Err(FatalError). This is used as a
+// crutch on the way towards a non-panic!-prone parser. It should be used
+// for fatal parsing errors; eventually we plan to convert all code using
+// panictry to just use normal try
+macro_rules! panictry {
+    ($e:expr) => ({
+        use std::result::Result::{Ok, Err};
+        use syntax::diagnostic::FatalError;
+        match $e {
+            Ok(e) => e,
+            Err(FatalError) => panic!(FatalError)
+        }
+    })
+}
+
+mod asm;
+mod cfg;
+mod concat;
+mod concat_idents;
+mod deriving;
+mod env;
+mod format;
+mod log_syntax;
+mod trace_macros;
+
+pub fn register_builtins(env: &mut SyntaxEnv) {
+    // utility function to simplify creating NormalTT syntax extensions
+    fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
+        NormalTT(Box::new(f), None, false)
+    }
+
+    env.insert(intern("asm"),
+               builtin_normal_expander(asm::expand_asm));
+    env.insert(intern("cfg"),
+               builtin_normal_expander(cfg::expand_cfg));
+    env.insert(intern("concat"),
+               builtin_normal_expander(concat::expand_syntax_ext));
+    env.insert(intern("concat_idents"),
+               builtin_normal_expander(concat_idents::expand_syntax_ext));
+    env.insert(intern("env"),
+               builtin_normal_expander(env::expand_env));
+    env.insert(intern("option_env"),
+               builtin_normal_expander(env::expand_option_env));
+    env.insert(intern("format_args"),
+               // format_args uses `unstable` things internally.
+               NormalTT(Box::new(format::expand_format_args), None, true));
+    env.insert(intern("log_syntax"),
+               builtin_normal_expander(log_syntax::expand_syntax_ext));
+    env.insert(intern("trace_macros"),
+               builtin_normal_expander(trace_macros::expand_trace_macros));
+
+    deriving::register_all(env);
+}
diff --git a/src/libsyntax_ext/log_syntax.rs b/src/libsyntax_ext/log_syntax.rs
new file mode 100644
index 00000000000..ee944abb645
--- /dev/null
+++ b/src/libsyntax_ext/log_syntax.rs
@@ -0,0 +1,34 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use syntax::ast;
+use syntax::codemap;
+use syntax::ext::base;
+use syntax::feature_gate;
+use syntax::print;
+
+pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt,
+                              sp: codemap::Span,
+                              tts: &[ast::TokenTree])
+                              -> Box<base::MacResult+'cx> {
+    if !cx.ecfg.enable_log_syntax() {
+        feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
+                                       "log_syntax",
+                                       sp,
+                                       feature_gate::GateIssue::Language,
+                                       feature_gate::EXPLAIN_LOG_SYNTAX);
+        return base::DummyResult::any(sp);
+    }
+
+    println!("{}", print::pprust::tts_to_string(tts));
+
+    // any so that `log_syntax` can be invoked as an expression and item.
+    base::DummyResult::any(sp)
+}
diff --git a/src/libsyntax_ext/trace_macros.rs b/src/libsyntax_ext/trace_macros.rs
new file mode 100644
index 00000000000..7b1e985442a
--- /dev/null
+++ b/src/libsyntax_ext/trace_macros.rs
@@ -0,0 +1,43 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use syntax::ast::TokenTree;
+use syntax::codemap::Span;
+use syntax::ext::base::ExtCtxt;
+use syntax::ext::base;
+use syntax::feature_gate;
+use syntax::parse::token::keywords;
+
+
+pub fn expand_trace_macros(cx: &mut ExtCtxt,
+                           sp: Span,
+                           tt: &[TokenTree])
+                           -> Box<base::MacResult+'static> {
+    if !cx.ecfg.enable_trace_macros() {
+        feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
+                                       "trace_macros",
+                                       sp,
+                                       feature_gate::GateIssue::Language,
+                                       feature_gate::EXPLAIN_TRACE_MACROS);
+        return base::DummyResult::any(sp);
+    }
+
+    match (tt.len(), tt.first()) {
+        (1, Some(&TokenTree::Token(_, ref tok))) if tok.is_keyword(keywords::True) => {
+            cx.set_trace_macros(true);
+        }
+        (1, Some(&TokenTree::Token(_, ref tok))) if tok.is_keyword(keywords::False) => {
+            cx.set_trace_macros(false);
+        }
+        _ => cx.span_err(sp, "trace_macros! accepts only `true` or `false`"),
+    }
+
+    base::DummyResult::any(sp)
+}