about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-05-31 23:10:36 -0700
committerbors <bors@rust-lang.org>2013-05-31 23:10:36 -0700
commit2bf053c0a349a5968820780314c942ef4555b47e (patch)
treef56b06e74a72c6a034aec68960efab5f334ba351
parentc23843c4471dcacb203d4439ef7c19bb2c3238b0 (diff)
parente694e5fc592491097470e996fb41bd25104252fc (diff)
downloadrust-2bf053c0a349a5968820780314c942ef4555b47e.tar.gz
rust-2bf053c0a349a5968820780314c942ef4555b47e.zip
auto merge of #6851 : alexcrichton/rust/bugfixes, r=pcwalton
Closes #5090 by using the excellent new generic deriving code

Promotes the unreachable code attribute to a lint attribute (instead of always being a warning)

Fixes some edge cases when creating hashmaps/hashsets and also when consuming them. (fixes #5998)
-rw-r--r--src/librustc/middle/lint.rs8
-rw-r--r--src/librustc/middle/typeck/check/mod.rs7
-rw-r--r--src/libstd/hashmap.rs22
-rw-r--r--src/libsyntax/ext/deriving/decodable.rs526
-rw-r--r--src/libsyntax/ext/deriving/encodable.rs663
-rw-r--r--src/test/compile-fail/dead-code-ret.rs10
-rw-r--r--src/test/compile-fail/issue-2150.rs9
-rw-r--r--src/test/compile-fail/issue-897-2.rs6
-rw-r--r--src/test/compile-fail/issue-897.rs6
-rw-r--r--src/test/compile-fail/liveness-break-uninit-2.rs2
-rw-r--r--src/test/compile-fail/liveness-break-uninit.rs2
-rw-r--r--src/test/compile-fail/unreachable-code.rs8
-rw-r--r--src/test/run-pass/deriving-encodable-decodable.rs77
13 files changed, 365 insertions, 981 deletions
diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs
index 6dd911e8ef3..c460ec89e4e 100644
--- a/src/librustc/middle/lint.rs
+++ b/src/librustc/middle/lint.rs
@@ -96,6 +96,7 @@ pub enum lint {
     unnecessary_allocation,
 
     missing_doc,
+    unreachable_code,
 }
 
 pub fn level_to_str(lv: level) -> &'static str {
@@ -273,6 +274,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
         desc: "detects missing documentation for public members",
         default: allow
     }),
+
+    ("unreachable_code",
+     LintSpec {
+        lint: unreachable_code,
+        desc: "detects unreachable code",
+        default: warn
+    }),
 ];
 
 /*
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 61da263e843..f8481d4cf90 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -81,6 +81,7 @@ use core::prelude::*;
 use middle::const_eval;
 use middle::pat_util::pat_id_map;
 use middle::pat_util;
+use middle::lint::unreachable_code;
 use middle::ty::{FnSig, VariantInfo_};
 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
 use middle::ty::{substs, param_ty};
@@ -2937,7 +2938,8 @@ pub fn check_block_with_expected(fcx: @mut FnCtxt,
         let mut any_err = false;
         for blk.node.stmts.each |s| {
             check_stmt(fcx, *s);
-            let s_ty = fcx.node_ty(ast_util::stmt_id(*s));
+            let s_id = ast_util::stmt_id(*s);
+            let s_ty = fcx.node_ty(s_id);
             if last_was_bot && !warned && match s.node {
                   ast::stmt_decl(@codemap::spanned { node: ast::decl_local(_),
                                                  _}, _) |
@@ -2946,7 +2948,8 @@ pub fn check_block_with_expected(fcx: @mut FnCtxt,
                   }
                   _ => false
                 } {
-                fcx.ccx.tcx.sess.span_warn(s.span, "unreachable statement");
+                fcx.ccx.tcx.sess.add_lint(unreachable_code, s_id, s.span,
+                                          ~"unreachable statement");
                 warned = true;
             }
             if ty::type_is_bot(s_ty) {
diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs
index 72f92bc1522..4826af20c69 100644
--- a/src/libstd/hashmap.rs
+++ b/src/libstd/hashmap.rs
@@ -72,11 +72,12 @@ pub fn linear_map_with_capacity<K:Eq + Hash,V>(
 fn linear_map_with_capacity_and_keys<K:Eq + Hash,V>(
     k0: u64, k1: u64,
     initial_capacity: uint) -> HashMap<K, V> {
+    let cap = uint::max(INITIAL_CAPACITY, initial_capacity);
     HashMap {
         k0: k0, k1: k1,
-        resize_at: resize_at(initial_capacity),
+        resize_at: resize_at(cap),
         size: 0,
-        buckets: vec::from_fn(initial_capacity, |_| None)
+        buckets: vec::from_fn(cap, |_| None)
     }
 }
 
@@ -480,7 +481,8 @@ pub impl<K: Hash + Eq, V> HashMap<K, V> {
     }
 
     fn consume(&mut self, f: &fn(K, V)) {
-        let buckets = replace(&mut self.buckets, ~[]);
+        let buckets = replace(&mut self.buckets,
+                              vec::from_fn(INITIAL_CAPACITY, |_| None));
         self.size = 0;
 
         do vec::consume(buckets) |_, bucket| {
@@ -665,6 +667,12 @@ mod test_map {
     use uint;
 
     #[test]
+    fn test_create_capacity_zero() {
+        let mut m = HashMap::with_capacity(0);
+        assert!(m.insert(1, 1));
+    }
+
+    #[test]
     fn test_insert() {
         let mut m = HashMap::new();
         assert!(m.insert(1, 2));
@@ -772,6 +780,14 @@ mod test_map {
     }
 
     #[test]
+    fn test_consume_still_usable() {
+        let mut m = HashMap::new();
+        assert!(m.insert(1, 2));
+        do m.consume |_, _| {}
+        assert!(m.insert(1, 2));
+    }
+
+    #[test]
     fn test_iterate() {
         let mut m = linear_map_with_capacity(4);
         for uint::range(0, 32) |i| {
diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs
index 4ae4533956e..1991b2456d9 100644
--- a/src/libsyntax/ext/deriving/decodable.rs
+++ b/src/libsyntax/ext/deriving/decodable.rs
@@ -14,410 +14,150 @@ encodable.rs for more.
 */
 
 use core::prelude::*;
+use core::vec;
+use core::uint;
 
-use ast::*;
-use ast;
-use ast_util;
-use codemap::{span, spanned};
+use ast::{meta_item, item, expr, m_mutbl};
+use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
-use ext::deriving::*;
-use opt_vec;
-
-use core::uint;
-
-pub fn expand_deriving_decodable(
-    cx: @ExtCtxt,
-    span: span,
-    _mitem: @meta_item,
-    in_items: ~[@item]
-) -> ~[@item] {
-    expand_deriving(
-        cx,
-        span,
-        in_items,
-        expand_deriving_decodable_struct_def,
-        expand_deriving_decodable_enum_def
-    )
-}
-
-fn create_derived_decodable_impl(
-    cx: @ExtCtxt,
-    span: span,
-    type_ident: ident,
-    generics: &Generics,
-    method: @method
-) -> @item {
-    let decoder_ty_param = cx.typaram(
-        cx.ident_of("__D"),
-        @opt_vec::with(
-            cx.typarambound(
-                cx.path_global(
-                    span,
-                    ~[
-                        cx.ident_of("extra"),
-                        cx.ident_of("serialize"),
-                        cx.ident_of("Decoder"),
-                    ]))));
-
-    // All the type parameters need to bound to the trait.
-    let generic_ty_params = opt_vec::with(decoder_ty_param);
-
-    let methods = [method];
-    let trait_path = cx.path_all(
-        span,
-        true,
-        ~[
-            cx.ident_of("extra"),
-            cx.ident_of("serialize"),
-            cx.ident_of("Decodable")
-        ],
-        None,
-        ~[
-            cx.ty_ident(span, cx.ident_of("__D"))
+use ext::deriving::generic::*;
+
+pub fn expand_deriving_decodable(cx: @ExtCtxt,
+                                 span: span,
+                                 mitem: @meta_item,
+                                 in_items: ~[@item]) -> ~[@item] {
+    let trait_def = TraitDef {
+        path: Path::new_(~["extra", "serialize", "Decodable"], None,
+                         ~[~Literal(Path::new_local("__D"))], true),
+        additional_bounds: ~[],
+        generics: LifetimeBounds {
+            lifetimes: ~[],
+            bounds: ~[("__D", ~[Path::new(~["extra", "serialize", "Decoder"])])],
+        },
+        methods: ~[
+            MethodDef {
+                name: "decode",
+                generics: LifetimeBounds::empty(),
+                explicit_self: None,
+                args: ~[Ptr(~Literal(Path::new_local("__D")),
+                            Borrowed(None, m_mutbl))],
+                ret_ty: Self,
+                const_nonmatching: true,
+                combine_substructure: decodable_substructure,
+            },
         ]
-    );
-    create_derived_impl(
-        cx,
-        span,
-        type_ident,
-        generics,
-        methods,
-        trait_path,
-        Generics { ty_params: generic_ty_params, lifetimes: opt_vec::Empty },
-        opt_vec::Empty
-    )
-}
-
-// Creates a method from the given set of statements conforming to the
-// signature of the `decodable` method.
-fn create_decode_method(
-    cx: @ExtCtxt,
-    span: span,
-    type_ident: ast::ident,
-    generics: &Generics,
-    expr: @ast::expr
-) -> @method {
-    // Create the `e` parameter.
-    let d_arg_type = cx.ty_rptr(
-        span,
-        cx.ty_ident(span, cx.ident_of("__D")),
-        None,
-        ast::m_mutbl
-    );
-    let d_ident = cx.ident_of("__d");
-    let d_arg = cx.arg(span, d_ident, d_arg_type);
-
-    // Create the type of the return value.
-    let output_type = create_self_type_with_params(
-        cx,
-        span,
-        type_ident,
-        generics
-    );
-
-    // Create the function declaration.
-    let inputs = ~[d_arg];
-    let fn_decl = cx.fn_decl(inputs, output_type);
-
-    // Create the body block.
-    let body_block = cx.blk_expr(expr);
+    };
 
-    // Create the method.
-    let explicit_self = spanned { node: sty_static, span: span };
-    let method_ident = cx.ident_of("decode");
-    @ast::method {
-        ident: method_ident,
-        attrs: ~[],
-        generics: ast_util::empty_generics(),
-        explicit_self: explicit_self,
-        purity: impure_fn,
-        decl: fn_decl,
-        body: body_block,
-        id: cx.next_id(),
-        span: span,
-        self_id: cx.next_id(),
-        vis: public
-    }
+    expand_deriving_generic(cx, span, mitem, in_items,
+                            &trait_def)
 }
 
-fn call_substructure_decode_method(
-    cx: @ExtCtxt,
-    span: span
-) -> @ast::expr {
-    // Call the substructure method.
-    cx.expr_call(
-        span,
-        cx.expr_path(
-            cx.path_global(
-                span,
-                ~[
-                    cx.ident_of("extra"),
+fn decodable_substructure(cx: @ExtCtxt, span: span,
+                          substr: &Substructure) -> @expr {
+    let decoder = substr.nonself_args[0];
+    let recurse = ~[cx.ident_of("extra"),
                     cx.ident_of("serialize"),
                     cx.ident_of("Decodable"),
-                    cx.ident_of("decode"),
-                ]
-            )
-        ),
-        ~[
-            cx.expr_ident(span, cx.ident_of("__d"))
-        ]
-    )
-}
-
-fn expand_deriving_decodable_struct_def(
-    cx: @ExtCtxt,
-    span: span,
-    struct_def: &struct_def,
-    type_ident: ident,
-    generics: &Generics
-) -> @item {
-    // Create the method.
-    let method = expand_deriving_decodable_struct_method(
-        cx,
-        span,
-        struct_def,
-        type_ident,
-        generics
-    );
-
-    // Create the implementation.
-    create_derived_decodable_impl(
-        cx,
-        span,
-        type_ident,
-        generics,
-        method
-    )
-}
-
-fn expand_deriving_decodable_enum_def(
-    cx: @ExtCtxt,
-    span: span,
-    enum_definition: &enum_def,
-    type_ident: ident,
-    generics: &Generics
-) -> @item {
-    // Create the method.
-    let method = expand_deriving_decodable_enum_method(
-        cx,
-        span,
-        enum_definition,
-        type_ident,
-        generics
-    );
-
-    // Create the implementation.
-    create_derived_decodable_impl(
-        cx,
-        span,
-        type_ident,
-        generics,
-        method
-    )
-}
-
-fn create_read_struct_field(
-    cx: @ExtCtxt,
-    span: span,
-    idx: uint,
-    ident: ident
-) -> ast::field {
-    // Call the substructure method.
-    let decode_expr = call_substructure_decode_method(cx, span);
-
-    let d_id = cx.ident_of("__d");
-
-    let call_expr = cx.expr_method_call(
-        span,
-        cx.expr_ident(span, d_id),
-        cx.ident_of("read_struct_field"),
-        ~[
-            cx.expr_str(span, cx.str_of(ident)),
-            cx.expr_uint(span, idx),
-            cx.lambda_expr_1(span, decode_expr, d_id)
-        ]
-    );
-
-    cx.field_imm(span, ident, call_expr)
-}
-
-fn create_read_struct_arg(
-    cx: @ExtCtxt,
-    span: span,
-    idx: uint,
-    ident: ident
-) -> ast::field {
-    // Call the substructure method.
-    let decode_expr = call_substructure_decode_method(cx, span);
-
-    let call_expr = cx.expr_method_call(
-        span,
-        cx.expr_ident(span, cx.ident_of("__d")),
-        cx.ident_of("read_struct_arg"),
-        ~[
-            cx.expr_uint(span, idx),
-            cx.lambda_expr_0(span, decode_expr),
-        ]
-    );
-
-    cx.field_imm(span, ident, call_expr)
-}
-
-fn expand_deriving_decodable_struct_method(
-    cx: @ExtCtxt,
-    span: span,
-    struct_def: &struct_def,
-    type_ident: ident,
-    generics: &Generics
-) -> @method {
-    // Create the body of the method.
-    let mut i = 0;
-    let mut fields = ~[];
-    for struct_def.fields.each |struct_field| {
-        match struct_field.node.kind {
-            named_field(ident, _) => {
-                fields.push(create_read_struct_field(cx, span, i, ident));
-            }
-            unnamed_field => {
-                cx.span_unimpl(
-                    span,
-                    "unnamed fields with `deriving(Decodable)`"
-                );
-            }
-        }
-        i += 1;
-    }
-
-    let d_id = cx.ident_of("__d");
-
-    let read_struct_expr = cx.expr_method_call(
-        span,
-        cx.expr_ident(span, d_id),
-        cx.ident_of("read_struct"),
-        ~[
-            cx.expr_str(span, cx.str_of(type_ident)),
-            cx.expr_uint(span, fields.len()),
-            cx.lambda_expr_1(
-                span,
-                cx.expr_struct_ident(span, type_ident, fields),
-                d_id)
-        ]
-    );
-
-    // Create the method itself.
-    create_decode_method(cx, span, type_ident, generics, read_struct_expr)
-}
-
-fn create_read_variant_arg(
-    cx: @ExtCtxt,
-    span: span,
-    idx: uint,
-    variant: &ast::variant
-) -> ast::arm {
-    // Create the matching pattern.
-    let pat = cx.pat_lit(span, cx.expr_uint(span, idx));
-
-    // Feed each argument in this variant to the decode function
-    // as well.
-    let variant_arg_len = variant_arg_count(cx, span, variant);
-
-    let expr = if variant_arg_len == 0 {
-        cx.expr_ident(span, variant.node.name)
-    } else {
-        // Feed the discriminant to the decode function.
-        let mut args = ~[];
-
-        for uint::range(0, variant_arg_len) |j| {
-            // Call the substructure method.
-            let expr = call_substructure_decode_method(cx, span);
-
-            let d_id = cx.ident_of("__d");
-
-            let call_expr = cx.expr_method_call(
-                span,
-                cx.expr_ident(span, d_id),
-                cx.ident_of("read_enum_variant_arg"),
-                ~[
-                    cx.expr_uint(span, j),
-                    cx.lambda_expr_1(span, expr, d_id),
-                ]
-            );
-
-            args.push(call_expr);
+                    cx.ident_of("decode")];
+    // throw an underscore in front to suppress unused variable warnings
+    let blkarg = cx.ident_of("_d");
+    let blkdecoder = cx.expr_ident(span, blkarg);
+    let calldecode = cx.expr_call_global(span, recurse, ~[blkdecoder]);
+    let lambdadecode = cx.lambda_expr_1(span, calldecode, blkarg);
+
+    return match *substr.fields {
+        StaticStruct(_, ref summary) => {
+            let nfields = match *summary {
+                Left(n) => n, Right(ref fields) => fields.len()
+            };
+            let read_struct_field = cx.ident_of("read_struct_field");
+
+            let getarg = |name: ~str, field: uint| {
+                cx.expr_method_call(span, blkdecoder, read_struct_field,
+                                    ~[cx.expr_str(span, name),
+                                      cx.expr_uint(span, field),
+                                      lambdadecode])
+            };
+
+            let result = match *summary {
+                Left(n) => {
+                    if n == 0 {
+                        cx.expr_ident(span, substr.type_ident)
+                    } else {
+                        let mut fields = vec::with_capacity(n);
+                        for uint::range(0, n) |i| {
+                            fields.push(getarg(fmt!("_field%u", i), i));
+                        }
+                        cx.expr_call_ident(span, substr.type_ident, fields)
+                    }
+                }
+                Right(ref fields) => {
+                    let fields = do fields.mapi |i, f| {
+                        cx.field_imm(span, *f, getarg(cx.str_of(*f), i))
+                    };
+                    cx.expr_struct_ident(span, substr.type_ident, fields)
+                }
+            };
+
+            cx.expr_method_call(span, decoder, cx.ident_of("read_struct"),
+                                ~[cx.expr_str(span, cx.str_of(substr.type_ident)),
+                                  cx.expr_uint(span, nfields),
+                                  cx.lambda_expr_1(span, result, blkarg)])
         }
+        StaticEnum(_, ref fields) => {
+            let variant = cx.ident_of("i");
+
+            let mut arms = ~[];
+            let mut variants = ~[];
+            let rvariant_arg = cx.ident_of("read_enum_variant_arg");
+
+            for fields.eachi |i, f| {
+                let (name, parts) = match *f { (i, ref p) => (i, p) };
+                variants.push(cx.expr_str(span, cx.str_of(name)));
+
+                let getarg = |field: uint| {
+                    cx.expr_method_call(span, blkdecoder, rvariant_arg,
+                                        ~[cx.expr_uint(span, field),
+                                          lambdadecode])
+                };
+
+                let decoded = match *parts {
+                    Left(n) => {
+                        if n == 0 {
+                            cx.expr_ident(span, name)
+                        } else {
+                            let mut fields = vec::with_capacity(n);
+                            for uint::range(0, n) |i| {
+                                fields.push(getarg(i));
+                            }
+                            cx.expr_call_ident(span, name, fields)
+                        }
+                    }
+                    Right(ref fields) => {
+                        let fields = do fields.mapi |i, f| {
+                            cx.field_imm(span, *f, getarg(i))
+                        };
+                        cx.expr_struct_ident(span, name, fields)
+                    }
+                };
+                arms.push(cx.arm(span,
+                                 ~[cx.pat_lit(span, cx.expr_uint(span, i))],
+                                 decoded));
+            }
 
-        cx.expr_call_ident(span, variant.node.name, args)
-    };
-
-    // Create the arm.
-    cx.arm(span, ~[pat], expr)
-}
-
-fn create_read_enum_variant(
-    cx: @ExtCtxt,
-    span: span,
-    enum_definition: &enum_def
-) -> @expr {
-    // Create a vector that contains all the variant names.
-    let expr_arm_names = cx.expr_vec(
-        span,
-        do enum_definition.variants.map |variant| {
-            cx.expr_str(
-                span,
-                cx.str_of(variant.node.name)
-            )
+            arms.push(cx.arm_unreachable(span));
+
+            let result = cx.expr_match(span, cx.expr_ident(span, variant), arms);
+            let lambda = cx.lambda_expr(span, ~[blkarg, variant], result);
+            let variant_vec = cx.expr_vec(span, variants);
+            let result = cx.expr_method_call(span, blkdecoder,
+                                             cx.ident_of("read_enum_variant"),
+                                             ~[variant_vec, lambda]);
+            cx.expr_method_call(span, decoder, cx.ident_of("read_enum"),
+                                ~[cx.expr_str(span, cx.str_of(substr.type_ident)),
+                                  cx.lambda_expr_1(span, result, blkarg)])
         }
-    );
-
-    // Create the arms of the match in the method body.
-    let mut arms = do enum_definition.variants.mapi |i, variant| {
-        create_read_variant_arg(cx, span, i, variant)
+        _ => cx.bug("expected StaticEnum or StaticStruct in deriving(Decodable)")
     };
-
-    // Add the impossible case arm.
-    arms.push(cx.arm_unreachable(span));
-
-    // Create the read_enum_variant expression.
-    cx.expr_method_call(
-        span,
-        cx.expr_ident(span, cx.ident_of("__d")),
-        cx.ident_of("read_enum_variant"),
-        ~[
-            expr_arm_names,
-            cx.lambda_expr(span,
-                           ~[cx.ident_of("__d"), cx.ident_of("__i")],
-                           cx.expr_match(span, cx.expr_ident(span, cx.ident_of("__i")), arms))
-        ]
-    )
-}
-
-fn expand_deriving_decodable_enum_method(
-    cx: @ExtCtxt,
-    span: span,
-    enum_definition: &enum_def,
-    type_ident: ast::ident,
-    generics: &Generics
-) -> @method {
-    let read_enum_variant_expr = create_read_enum_variant(
-        cx,
-        span,
-        enum_definition
-    );
-
-    let d_id = cx.ident_of("__d");
-
-    // Create the read_enum expression
-    let read_enum_expr = cx.expr_method_call(
-        span,
-        cx.expr_ident(span, d_id),
-        cx.ident_of("read_enum"),
-        ~[
-            cx.expr_str(span, cx.str_of(type_ident)),
-            cx.lambda_expr_1(span, read_enum_variant_expr, d_id)
-        ]
-    );
-
-    // Create the method.
-    create_decode_method(cx, span, type_ident, generics, read_enum_expr)
 }
diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs
index 6ca7d0b7b28..b9c4bf7bf26 100644
--- a/src/libsyntax/ext/deriving/encodable.rs
+++ b/src/libsyntax/ext/deriving/encodable.rs
@@ -77,578 +77,113 @@ would yield functions like:
 
 use core::prelude::*;
 
-use ast;
-use ast::*;
+use ast::{meta_item, item, expr, m_imm, m_mutbl};
+use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
-use ext::deriving::*;
-use codemap::{span, spanned};
-use ast_util;
-use opt_vec;
-
-pub fn expand_deriving_encodable(
-    cx: @ExtCtxt,
-    span: span,
-    _mitem: @meta_item,
-    in_items: ~[@item]
-) -> ~[@item] {
-    expand_deriving(
-        cx,
-        span,
-        in_items,
-        expand_deriving_encodable_struct_def,
-        expand_deriving_encodable_enum_def
-    )
-}
-
-fn create_derived_encodable_impl(
-    cx: @ExtCtxt,
-    span: span,
-    type_ident: ident,
-    generics: &Generics,
-    method: @method
-) -> @item {
-    let encoder_ty_param = cx.typaram(
-        cx.ident_of("__E"),
-        @opt_vec::with(
-            cx.typarambound(
-                cx.path_global(
-                    span,
-                    ~[
-                        cx.ident_of("extra"),
-                        cx.ident_of("serialize"),
-                        cx.ident_of("Encoder"),
-                    ]))));
-
-    // All the type parameters need to bound to the trait.
-    let generic_ty_params = opt_vec::with(encoder_ty_param);
-
-    let methods = [method];
-    let trait_path = cx.path_all(
-        span,
-        true,
-        ~[
-            cx.ident_of("extra"),
-            cx.ident_of("serialize"),
-            cx.ident_of("Encodable")
-        ],
-        None,
-        ~[
-            cx.ty_ident(span, cx.ident_of("__E"))
+use ext::deriving::generic::*;
+
+pub fn expand_deriving_encodable(cx: @ExtCtxt,
+                                 span: span,
+                                 mitem: @meta_item,
+                                 in_items: ~[@item]) -> ~[@item] {
+    let trait_def = TraitDef {
+        path: Path::new_(~["extra", "serialize", "Encodable"], None,
+                         ~[~Literal(Path::new_local("__E"))], true),
+        additional_bounds: ~[],
+        generics: LifetimeBounds {
+            lifetimes: ~[],
+            bounds: ~[("__E", ~[Path::new(~["extra", "serialize", "Encoder"])])],
+        },
+        methods: ~[
+            MethodDef {
+                name: "encode",
+                generics: LifetimeBounds::empty(),
+                explicit_self: Some(Some(Borrowed(None, m_imm))),
+                args: ~[Ptr(~Literal(Path::new_local("__E")),
+                            Borrowed(None, m_mutbl))],
+                ret_ty: nil_ty(),
+                const_nonmatching: true,
+                combine_substructure: encodable_substructure,
+            },
         ]
-    );
-    create_derived_impl(
-        cx,
-        span,
-        type_ident,
-        generics,
-        methods,
-        trait_path,
-        Generics { ty_params: generic_ty_params, lifetimes: opt_vec::Empty },
-        opt_vec::Empty
-    )
-}
-
-// Creates a method from the given set of statements conforming to the
-// signature of the `encodable` method.
-fn create_encode_method(
-    cx: @ExtCtxt,
-    span: span,
-    statements: ~[@stmt]
-) -> @method {
-    // Create the `e` parameter.
-    let e_arg_type = cx.ty_rptr(
-        span,
-        cx.ty_ident(span, cx.ident_of("__E")),
-        None,
-        ast::m_mutbl
-    );
-    let e_arg = cx.arg(span, cx.ident_of("__e"), e_arg_type);
-
-    // Create the type of the return value.
-    let output_type = cx.ty_nil();
-
-    // Create the function declaration.
-    let inputs = ~[e_arg];
-    let fn_decl = cx.fn_decl(inputs, output_type);
-
-    // Create the body block.
-    let body_block = cx.blk(span, statements, None);
-
-    // Create the method.
-    let explicit_self = spanned { node: sty_region(None, m_imm), span: span };
-    let method_ident = cx.ident_of("encode");
-    @ast::method {
-        ident: method_ident,
-        attrs: ~[],
-        generics: ast_util::empty_generics(),
-        explicit_self: explicit_self,
-        purity: impure_fn,
-        decl: fn_decl,
-        body: body_block,
-        id: cx.next_id(),
-        span: span,
-        self_id: cx.next_id(),
-        vis: public
-    }
-}
-
-fn call_substructure_encode_method(
-    cx: @ExtCtxt,
-    span: span,
-    self_field: @expr
-) -> @ast::expr {
-    // Gather up the parameters we want to chain along.
-    let e_ident = cx.ident_of("__e");
-    let e_expr = cx.expr_ident(span, e_ident);
-
-    // Call the substructure method.
-    let encode_ident = cx.ident_of("encode");
-    cx.expr_method_call(
-        span,
-        self_field,
-        encode_ident,
-        ~[e_expr]
-    )
-}
-
-fn expand_deriving_encodable_struct_def(
-    cx: @ExtCtxt,
-    span: span,
-    struct_def: &struct_def,
-    type_ident: ident,
-    generics: &Generics
-) -> @item {
-    // Create the method.
-    let method = expand_deriving_encodable_struct_method(
-        cx,
-        span,
-        type_ident,
-        struct_def
-    );
-
-    // Create the implementation.
-    create_derived_encodable_impl(
-        cx,
-        span,
-        type_ident,
-        generics,
-        method
-    )
-}
-
-fn expand_deriving_encodable_enum_def(
-    cx: @ExtCtxt,
-    span: span,
-    enum_definition: &enum_def,
-    type_ident: ident,
-    generics: &Generics
-) -> @item {
-    // Create the method.
-    let method = expand_deriving_encodable_enum_method(
-        cx,
-        span,
-        type_ident,
-        enum_definition
-    );
+    };
 
-    // Create the implementation.
-    create_derived_encodable_impl(
-        cx,
-        span,
-        type_ident,
-        generics,
-        method
-    )
+    expand_deriving_generic(cx, span, mitem, in_items,
+                            &trait_def)
 }
 
-fn expand_deriving_encodable_struct_method(
-    cx: @ExtCtxt,
-    span: span,
-    type_ident: ident,
-    struct_def: &struct_def
-) -> @method {
-    // Create the body of the method.
-    let mut idx = 0;
-    let mut statements = ~[];
-    for struct_def.fields.each |struct_field| {
-        match struct_field.node.kind {
-            named_field(ident, _) => {
-                // Create the accessor for this field.
-                let self_field = cx.expr_field_access(span,
-                                                      cx.expr_self(span),
-                                                      ident);
-
-                // Call the substructure method.
-                let encode_expr = call_substructure_encode_method(
-                    cx,
-                    span,
-                    self_field
-                );
-
-                let e_ident = cx.ident_of("__e");
-
-                let call_expr = cx.expr_method_call(
-                    span,
-                    cx.expr_ident(span, e_ident),
-                    cx.ident_of("emit_struct_field"),
-                    ~[
-                        cx.expr_str(span, cx.str_of(ident)),
-                        cx.expr_uint(span, idx),
-                        cx.lambda_expr_1(span, encode_expr, e_ident)
-                    ]
-                );
-
-                statements.push(cx.stmt_expr(call_expr));
+fn encodable_substructure(cx: @ExtCtxt, span: span,
+                          substr: &Substructure) -> @expr {
+    let encoder = substr.nonself_args[0];
+    // throw an underscore in front to suppress unused variable warnings
+    let blkarg = cx.ident_of("_e");
+    let blkencoder = cx.expr_ident(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 = ~[];
+            for fields.eachi |i, f| {
+                let (name, val) = match *f {
+                    (Some(id), e, _) => (cx.str_of(id), e),
+                    (None, e, _) => (fmt!("_field%u", i), e)
+                };
+                let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]);
+                let lambda = cx.lambda_expr_1(span, enc, blkarg);
+                let call = cx.expr_method_call(span, blkencoder,
+                                               emit_struct_field,
+                                               ~[cx.expr_str(span, name),
+                                                 cx.expr_uint(span, i),
+                                                 lambda]);
+                stmts.push(cx.stmt_expr(call));
             }
-            unnamed_field => {
-                cx.span_unimpl(
-                    span,
-                    "unnamed fields with `deriving(Encodable)`"
-                );
-            }
-        }
-        idx += 1;
-    }
 
-    let e_id = cx.ident_of("__e");
-    let emit_struct_stmt = cx.expr_method_call(
-        span,
-        cx.expr_ident(span, e_id),
-        cx.ident_of("emit_struct"),
-        ~[
-            cx.expr_str(span, cx.str_of(type_ident)),
-            cx.expr_uint(span, statements.len()),
-            cx.lambda_stmts_1(span, statements, e_id),
-        ]
-    );
-
-    let statements = ~[cx.stmt_expr(emit_struct_stmt)];
-
-    // Create the method itself.
-    return create_encode_method(cx, span, statements);
-}
-
-fn expand_deriving_encodable_enum_method(
-    cx: @ExtCtxt,
-    span: span,
-    type_ident: ast::ident,
-    enum_definition: &enum_def
-) -> @method {
-    // Create the arms of the match in the method body.
-    let arms = do enum_definition.variants.mapi |i, variant| {
-        // Create the matching pattern.
-        let (pat, fields) = create_enum_variant_pattern(cx, span, variant, "__self", ast::m_imm);
-
-        // Feed the discriminant to the encode function.
-        let mut stmts = ~[];
-
-        // Feed each argument in this variant to the encode function
-        // as well.
-        let variant_arg_len = variant_arg_count(cx, span, variant);
-        for fields.eachi |j, &(_, field)| {
-            // Call the substructure method.
-            let expr = call_substructure_encode_method(cx, span, field);
-
-            let e_ident = cx.ident_of("__e");
-            let call_expr = cx.expr_method_call(
-                span,
-                cx.expr_ident(span, e_ident),
-                cx.ident_of("emit_enum_variant_arg"),
-                ~[
-                    cx.expr_uint(span, j),
-                    cx.lambda_expr_1(span, expr, e_ident),
-                ]
-            );
-
-            stmts.push(cx.stmt_expr(call_expr));
-        }
-
-        // Create the pattern body.
-        let e_id = cx.ident_of("__e");
-
-        let call_expr = cx.expr_method_call(
-            span,
-            cx.expr_ident(span, e_id),
-            cx.ident_of("emit_enum_variant"),
-            ~[
-                cx.expr_str(span, cx.str_of(variant.node.name)),
-                cx.expr_uint(span, i),
-                cx.expr_uint(span, variant_arg_len),
-                cx.lambda_stmts_1(span, stmts, e_id)
-            ]
-        );
-
-        //let match_body_block = cx.blk_expr(call_expr);
+            let blk = cx.lambda_stmts_1(span, stmts, blkarg);
+            cx.expr_method_call(span, encoder, cx.ident_of("emit_struct"),
+                                ~[cx.expr_str(span, cx.str_of(substr.type_ident)),
+                                  cx.expr_uint(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(span, false, blkarg, encoder);
+            let encoder = cx.expr_ident(span, blkarg);
+            let emit_variant_arg = cx.ident_of("emit_enum_variant_arg");
+            let mut stmts = ~[];
+            for fields.eachi |i, f| {
+                let val = match *f { (_, e, _) => e };
+                let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]);
+                let lambda = cx.lambda_expr_1(span, enc, blkarg);
+                let call = cx.expr_method_call(span, blkencoder,
+                                               emit_variant_arg,
+                                               ~[cx.expr_uint(span, i),
+                                                 lambda]);
+                stmts.push(cx.stmt_expr(call));
+            }
 
-        // Create the arm.
-        cx.arm(span, ~[pat], call_expr) //match_body_block)
+            let blk = cx.lambda_stmts_1(span, stmts, blkarg);
+            let name = cx.expr_str(span, cx.str_of(variant.node.name));
+            let call = cx.expr_method_call(span, blkencoder,
+                                           cx.ident_of("emit_enum_variant"),
+                                           ~[name,
+                                             cx.expr_uint(span, idx),
+                                             cx.expr_uint(span, fields.len()),
+                                             blk]);
+            let blk = cx.lambda_expr_1(span, call, blkarg);
+            let ret = cx.expr_method_call(span, encoder,
+                                          cx.ident_of("emit_enum"),
+                                          ~[cx.expr_str(span,
+                                            cx.str_of(substr.type_ident)),
+                                            blk]);
+            cx.expr_blk(cx.blk(span, ~[me], Some(ret)))
+        }
+
+        _ => cx.bug("expected Struct or EnumMatching in deriving(Encodable)")
     };
-
-    let e_ident = cx.ident_of("__e");
-
-    // Create the method body.
-    let lambda_expr = cx.lambda_expr_1(
-        span,
-        expand_enum_or_struct_match(cx, span, arms),
-        e_ident);
-
-    let call_expr = cx.expr_method_call(
-        span,
-        cx.expr_ident(span, e_ident),
-        cx.ident_of("emit_enum"),
-        ~[
-            cx.expr_str(span, cx.str_of(type_ident)),
-            lambda_expr,
-        ]
-    );
-
-    let stmt = cx.stmt_expr(call_expr);
-
-    // Create the method.
-    create_encode_method(cx, span, ~[stmt])
-}
-
-#[cfg(test)]
-mod test {
-    extern mod extra;
-    use core::option::{None, Some};
-    use extra::serialize::Encodable;
-    use extra::serialize::Encoder;
-
-    // just adding the ones I want to test, for now:
-    #[deriving(Eq)]
-    pub enum call {
-        CallToEmitEnum(~str),
-        CallToEmitEnumVariant(~str, uint, uint),
-        CallToEmitEnumVariantArg(uint),
-        CallToEmitUint(uint),
-        CallToEmitNil,
-        CallToEmitStruct(~str,uint),
-        CallToEmitField(~str,uint),
-        CallToEmitOption,
-        CallToEmitOptionNone,
-        CallToEmitOptionSome,
-        // all of the ones I was too lazy to handle:
-        CallToOther
-    }
-    // using `@mut` rather than changing the
-    // type of self in every method of every encoder everywhere.
-    pub struct TestEncoder {call_log : @mut ~[call]}
-
-    pub impl TestEncoder {
-        // these self's should be &mut self's, as well....
-        fn add_to_log (&self, c : call) {
-            self.call_log.push(copy c);
-        }
-        fn add_unknown_to_log (&self) {
-            self.add_to_log (CallToOther)
-        }
-    }
-
-    impl Encoder for TestEncoder {
-        fn emit_nil(&mut self) { self.add_to_log(CallToEmitNil) }
-
-        fn emit_uint(&mut self, v: uint) {
-            self.add_to_log(CallToEmitUint(v));
-        }
-        fn emit_u64(&mut self, _v: u64) { self.add_unknown_to_log(); }
-        fn emit_u32(&mut self, _v: u32) { self.add_unknown_to_log(); }
-        fn emit_u16(&mut self, _v: u16) { self.add_unknown_to_log(); }
-        fn emit_u8(&mut self, _v: u8)   { self.add_unknown_to_log(); }
-
-        fn emit_int(&mut self, _v: int) { self.add_unknown_to_log(); }
-        fn emit_i64(&mut self, _v: i64) { self.add_unknown_to_log(); }
-        fn emit_i32(&mut self, _v: i32) { self.add_unknown_to_log(); }
-        fn emit_i16(&mut self, _v: i16) { self.add_unknown_to_log(); }
-        fn emit_i8(&mut self, _v: i8)   { self.add_unknown_to_log(); }
-
-        fn emit_bool(&mut self, _v: bool) { self.add_unknown_to_log(); }
-
-        fn emit_f64(&mut self, _v: f64) { self.add_unknown_to_log(); }
-        fn emit_f32(&mut self, _v: f32) { self.add_unknown_to_log(); }
-        fn emit_float(&mut self, _v: float) { self.add_unknown_to_log(); }
-
-        fn emit_char(&mut self, _v: char) { self.add_unknown_to_log(); }
-        fn emit_str(&mut self, _v: &str) { self.add_unknown_to_log(); }
-
-        fn emit_enum(&mut self, name: &str, f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitEnum(name.to_str()));
-            f(self);
-        }
-
-        fn emit_enum_variant(&mut self,
-                             name: &str,
-                             id: uint,
-                             cnt: uint,
-                             f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitEnumVariant(name.to_str(), id, cnt));
-            f(self);
-        }
-
-        fn emit_enum_variant_arg(&mut self,
-                                 idx: uint,
-                                 f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitEnumVariantArg(idx));
-            f(self);
-        }
-
-        fn emit_enum_struct_variant(&mut self,
-                                    name: &str,
-                                    id: uint,
-                                    cnt: uint,
-                                    f: &fn(&mut TestEncoder)) {
-            self.emit_enum_variant(name, id, cnt, f)
-        }
-
-        fn emit_enum_struct_variant_field(&mut self,
-                                          _name: &str,
-                                          idx: uint,
-                                          f: &fn(&mut TestEncoder)) {
-            self.emit_enum_variant_arg(idx, f)
-        }
-
-        fn emit_struct(&mut self,
-                       name: &str,
-                       len: uint,
-                       f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitStruct (name.to_str(),len));
-            f(self);
-        }
-        fn emit_struct_field(&mut self,
-                             name: &str,
-                             idx: uint,
-                             f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitField (name.to_str(),idx));
-            f(self);
-        }
-
-        fn emit_tuple(&mut self, _len: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-        fn emit_tuple_arg(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-
-        fn emit_tuple_struct(&mut self,
-                             _name: &str,
-                             _len: uint,
-                             f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-
-        fn emit_tuple_struct_arg(&mut self,
-                                 _idx: uint,
-                                 f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-
-        fn emit_option(&mut self, f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitOption);
-            f(self);
-        }
-        fn emit_option_none(&mut self) {
-            self.add_to_log(CallToEmitOptionNone);
-        }
-        fn emit_option_some(&mut self, f: &fn(&mut TestEncoder)) {
-            self.add_to_log(CallToEmitOptionSome);
-            f(self);
-        }
-
-        fn emit_seq(&mut self, _len: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-        fn emit_seq_elt(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-
-        fn emit_map(&mut self, _len: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-        fn emit_map_elt_key(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-        fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) {
-            self.add_unknown_to_log();
-            f(self);
-        }
-    }
-
-
-    fn to_call_log<E:Encodable<TestEncoder>>(val: E) -> ~[call] {
-        let mut te = TestEncoder {
-            call_log: @mut ~[]
-        };
-        val.encode(&mut te);
-        copy *te.call_log
-    }
-
-    #[deriving(Encodable)]
-    enum Written {
-        Book(uint,uint),
-        Magazine(~str)
-    }
-
-    #[test]
-    fn test_encode_enum() {
-        assert_eq!(
-            to_call_log(Book(34,44)),
-            ~[
-                CallToEmitEnum(~"Written"),
-                CallToEmitEnumVariant(~"Book",0,2),
-                CallToEmitEnumVariantArg(0),
-                CallToEmitUint(34),
-                CallToEmitEnumVariantArg(1),
-                CallToEmitUint(44),
-            ]
-        );
-    }
-
-    pub struct BPos(uint);
-
-    #[deriving(Encodable)]
-    pub struct HasPos { pos : BPos }
-
-    #[test]
-    fn test_encode_newtype() {
-        assert_eq!(
-            to_call_log(HasPos { pos:BPos(48) }),
-            ~[
-                CallToEmitStruct(~"HasPos",1),
-                CallToEmitField(~"pos",0),
-                CallToEmitUint(48),
-            ]
-        );
-    }
-
-    #[test]
-    fn test_encode_option() {
-        let mut v = None;
-
-        assert_eq!(
-            to_call_log(v),
-            ~[
-                CallToEmitOption,
-                CallToEmitOptionNone,
-            ]
-        );
-
-        v = Some(54u);
-        assert_eq!(
-            to_call_log(v),
-            ~[
-                CallToEmitOption,
-                CallToEmitOptionSome,
-                CallToEmitUint(54)
-            ]
-        );
-    }
 }
diff --git a/src/test/compile-fail/dead-code-ret.rs b/src/test/compile-fail/dead-code-ret.rs
index 5fa796db884..91b89a67ee3 100644
--- a/src/test/compile-fail/dead-code-ret.rs
+++ b/src/test/compile-fail/dead-code-ret.rs
@@ -9,13 +9,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
-fn f(caller: &str) {
-    debug!(caller);
-    let x: uint = 0u32; // induce type error //~ ERROR mismatched types
-}
+#[deny(unreachable_code)];
 
 fn main() {
-    return f("main");
-    debug!("Paul is dead"); //~ WARNING unreachable
+    return;
+    debug!("Paul is dead"); //~ ERROR: unreachable
 }
diff --git a/src/test/compile-fail/issue-2150.rs b/src/test/compile-fail/issue-2150.rs
index 9f2f9a855ed..0b35104841e 100644
--- a/src/test/compile-fail/issue-2150.rs
+++ b/src/test/compile-fail/issue-2150.rs
@@ -8,11 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#[deny(unreachable_code)];
+#[allow(unused_variable)];
+
 fn fail_len(v: ~[int]) -> uint {
-    let mut i = fail!();
+    let mut i = 3;
+    fail!();
     for v.each |x| { i += 1u; }
-    //~^ WARNING unreachable statement
-    //~^^ ERROR the type of this value must be known
+    //~^ ERROR: unreachable statement
     return i;
 }
 fn main() {}
diff --git a/src/test/compile-fail/issue-897-2.rs b/src/test/compile-fail/issue-897-2.rs
index 253563c1219..eb60e34df8f 100644
--- a/src/test/compile-fail/issue-897-2.rs
+++ b/src/test/compile-fail/issue-897-2.rs
@@ -8,9 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#[deny(unreachable_code)];
+
 fn g() -> ! { fail!(); }
 fn f() -> ! {
-    return 42i; //~ ERROR expected `!` but found `int`
-    g(); //~ WARNING unreachable statement
+    return g();
+    g(); //~ ERROR: unreachable statement
 }
 fn main() { }
diff --git a/src/test/compile-fail/issue-897.rs b/src/test/compile-fail/issue-897.rs
index 503574fce87..103156175a3 100644
--- a/src/test/compile-fail/issue-897.rs
+++ b/src/test/compile-fail/issue-897.rs
@@ -8,8 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#[deny(unreachable_code)];
+
 fn f() -> ! {
-    return 42i; //~ ERROR expected `!` but found `int`
-    fail!(); //~ WARNING unreachable statement
+    return fail!();
+    fail!(); //~ ERROR: unreachable statement
 }
 fn main() { }
diff --git a/src/test/compile-fail/liveness-break-uninit-2.rs b/src/test/compile-fail/liveness-break-uninit-2.rs
index c87439db617..2ed02e2cdd7 100644
--- a/src/test/compile-fail/liveness-break-uninit-2.rs
+++ b/src/test/compile-fail/liveness-break-uninit-2.rs
@@ -13,7 +13,7 @@ fn foo() -> int {
 
     while 1 != 2  {
         break;
-        x = 0; //~ WARNING unreachable statement
+        x = 0;
     }
 
     debug!(x); //~ ERROR use of possibly uninitialized variable: `x`
diff --git a/src/test/compile-fail/liveness-break-uninit.rs b/src/test/compile-fail/liveness-break-uninit.rs
index 07075e4ef63..2dcbad2804c 100644
--- a/src/test/compile-fail/liveness-break-uninit.rs
+++ b/src/test/compile-fail/liveness-break-uninit.rs
@@ -13,7 +13,7 @@ fn foo() -> int {
 
     loop {
         break;
-        x = 0;  //~ WARNING unreachable statement
+        x = 0;
     }
 
     debug!(x); //~ ERROR use of possibly uninitialized variable: `x`
diff --git a/src/test/compile-fail/unreachable-code.rs b/src/test/compile-fail/unreachable-code.rs
index f1fbc5b009e..a9365eeda1c 100644
--- a/src/test/compile-fail/unreachable-code.rs
+++ b/src/test/compile-fail/unreachable-code.rs
@@ -8,9 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern:unreachable statement
+#[deny(unreachable_code)];
+#[allow(unused_variable)];
+
 fn main() {
   loop{}
-             // red herring to make sure compilation fails
-  error!(42 == 'c');
+
+  let a = 3; //~ ERROR: unreachable statement
 }
diff --git a/src/test/run-pass/deriving-encodable-decodable.rs b/src/test/run-pass/deriving-encodable-decodable.rs
new file mode 100644
index 00000000000..fa672581238
--- /dev/null
+++ b/src/test/run-pass/deriving-encodable-decodable.rs
@@ -0,0 +1,77 @@
+// 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.
+
+// This actually tests a lot more than just encodable/decodable, but it gets the
+// job done at least
+
+// xfail-fast
+
+extern mod extra;
+
+use std::io;
+use std::rand::{random, Rand};
+use extra::serialize::*;
+use extra::ebml;
+use extra::ebml::writer::Encoder;
+use extra::ebml::reader::Decoder;
+
+#[deriving(Encodable, Decodable, Eq, Rand)]
+struct A;
+#[deriving(Encodable, Decodable, Eq, Rand)]
+struct B(int);
+#[deriving(Encodable, Decodable, Eq, Rand)]
+struct C(int, int, uint);
+
+#[deriving(Encodable, Decodable, Eq, Rand)]
+struct D {
+    a: int,
+    b: uint,
+}
+
+#[deriving(Encodable, Decodable, Eq, Rand)]
+enum E {
+    E1,
+    E2(uint),
+    E3(D),
+    E4{ x: uint },
+}
+
+#[deriving(Encodable, Decodable, Eq, Rand)]
+enum F { F1 }
+
+#[deriving(Encodable, Decodable, Eq, Rand)]
+struct G<T> {
+    t: T
+}
+
+fn roundtrip<T: Rand + Eq + Encodable<Encoder> + Decodable<Decoder>>() {
+    let obj: T = random();
+    let bytes = do io::with_bytes_writer |w| {
+        let mut e = Encoder(w);
+        obj.encode(&mut e);
+    };
+    let doc = ebml::reader::Doc(@bytes);
+    let mut dec = Decoder(doc);
+    let obj2 = Decodable::decode(&mut dec);
+    assert!(obj == obj2);
+}
+
+pub fn main() {
+    roundtrip::<A>();
+    roundtrip::<B>();
+    roundtrip::<C>();
+    roundtrip::<D>();
+
+    for 20.times {
+        roundtrip::<E>();
+        roundtrip::<F>();
+        roundtrip::<G<int>>();
+    }
+}