about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/metadata/encoder.rs2
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs60
-rw-r--r--src/librustc/middle/borrowck/doc.rs68
-rw-r--r--src/librustc/middle/borrowck/gather_loans/mod.rs57
-rw-r--r--src/librustc/middle/borrowck/gather_loans/restrictions.rs34
-rw-r--r--src/librustc/middle/borrowck/mod.rs26
-rw-r--r--src/librustc/middle/mem_categorization.rs40
-rw-r--r--src/libsyntax/ext/deriving/clone.rs10
-rw-r--r--src/libsyntax/ext/deriving/cmp/eq.rs5
-rw-r--r--src/libsyntax/ext/deriving/cmp/ord.rs5
-rw-r--r--src/libsyntax/ext/deriving/cmp/totaleq.rs5
-rw-r--r--src/libsyntax/ext/deriving/cmp/totalord.rs5
-rw-r--r--src/libsyntax/ext/deriving/decodable.rs5
-rw-r--r--src/libsyntax/ext/deriving/default.rs7
-rw-r--r--src/libsyntax/ext/deriving/encodable.rs5
-rw-r--r--src/libsyntax/ext/deriving/generic.rs204
-rw-r--r--src/libsyntax/ext/deriving/iter_bytes.rs5
-rw-r--r--src/libsyntax/ext/deriving/primitive.rs5
-rw-r--r--src/libsyntax/ext/deriving/rand.rs7
-rw-r--r--src/libsyntax/ext/deriving/show.rs7
-rw-r--r--src/libsyntax/ext/deriving/to_str.rs7
-rw-r--r--src/libsyntax/ext/deriving/zero.rs7
-rw-r--r--src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs5
23 files changed, 317 insertions, 264 deletions
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 07997577a9f..4abfedb8722 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -681,7 +681,7 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::Explic
 
     ebml_w.end_tag();
 
-    fn encode_mutability(ebml_w: &writer::Encoder,
+    fn encode_mutability(ebml_w: &mut writer::Encoder,
                          m: ast::Mutability) {
         match m {
             MutImmutable => { ebml_w.writer.write(&[ 'i' as u8 ]); }
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index b280da31c45..cfd2c0719b0 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -22,7 +22,6 @@ use mc = middle::mem_categorization;
 use middle::borrowck::*;
 use middle::moves;
 use middle::ty;
-use syntax::ast::{MutImmutable, MutMutable};
 use syntax::ast;
 use syntax::ast_map;
 use syntax::ast_util;
@@ -220,9 +219,8 @@ impl<'a> CheckLoanCtxt<'a> {
 
         // Restrictions that would cause the new loan to be illegal:
         let illegal_if = match loan2.mutbl {
-            MutableMutability   => RESTR_ALIAS | RESTR_FREEZE | RESTR_CLAIM,
-            ImmutableMutability => RESTR_ALIAS | RESTR_FREEZE,
-            ConstMutability     => RESTR_ALIAS,
+            MutableMutability   => RESTR_FREEZE | RESTR_CLAIM,
+            ImmutableMutability => RESTR_FREEZE,
         };
         debug!("illegal_if={:?}", illegal_if);
 
@@ -424,7 +422,7 @@ impl<'a> CheckLoanCtxt<'a> {
             debug!("check_for_aliasable_mutable_writes(cmt={}, guarantor={})",
                    cmt.repr(this.tcx()), guarantor.repr(this.tcx()));
             match guarantor.cat {
-                mc::cat_deref(b, _, mc::region_ptr(MutMutable, _)) => {
+                mc::cat_deref(b, _, mc::region_ptr(ast::MutMutable, _)) => {
                     // Statically prohibit writes to `&mut` when aliasable
 
                     check_for_aliasability_violation(this, expr, b);
@@ -438,43 +436,18 @@ impl<'a> CheckLoanCtxt<'a> {
 
         fn check_for_aliasability_violation(this: &CheckLoanCtxt,
                                             expr: &ast::Expr,
-                                            cmt: mc::cmt) -> bool {
-            let mut cmt = cmt;
-
-            loop {
-                match cmt.cat {
-                    mc::cat_deref(b, _, mc::region_ptr(MutMutable, _)) |
-                    mc::cat_downcast(b) |
-                    mc::cat_stack_upvar(b) |
-                    mc::cat_deref(b, _, mc::uniq_ptr) |
-                    mc::cat_interior(b, _) |
-                    mc::cat_discr(b, _) => {
-                        // Aliasability depends on base cmt
-                        cmt = b;
-                    }
-
-                    mc::cat_copied_upvar(_) |
-                    mc::cat_rvalue(..) |
-                    mc::cat_local(..) |
-                    mc::cat_arg(_) |
-                    mc::cat_deref(_, _, mc::unsafe_ptr(..)) |
-                    mc::cat_static_item(..) |
-                    mc::cat_deref(_, _, mc::gc_ptr) |
-                    mc::cat_deref(_, _, mc::region_ptr(MutImmutable, _)) => {
-                        // Aliasability is independent of base cmt
-                        match cmt.freely_aliasable() {
-                            None => {
-                                return true;
-                            }
-                            Some(cause) => {
-                                this.bccx.report_aliasability_violation(
-                                    expr.span,
-                                    MutabilityViolation,
-                                    cause);
-                                return false;
-                            }
-                        }
-                    }
+                                            cmt: mc::cmt)
+                                            -> bool {
+            match cmt.freely_aliasable() {
+                None => {
+                    return true;
+                }
+                Some(cause) => {
+                    this.bccx.report_aliasability_violation(
+                        expr.span,
+                        MutabilityViolation,
+                        cause);
+                    return false;
                 }
             }
         }
@@ -598,8 +571,7 @@ impl<'a> CheckLoanCtxt<'a> {
 
                 // Check for a non-const loan of `loan_path`
                 let cont = this.each_in_scope_loan(expr.id, |loan| {
-                    if loan.loan_path == loan_path &&
-                            loan.mutbl != ConstMutability {
+                    if loan.loan_path == loan_path {
                         this.report_illegal_mutation(expr,
                                                      full_loan_path,
                                                      loan);
diff --git a/src/librustc/middle/borrowck/doc.rs b/src/librustc/middle/borrowck/doc.rs
index 04ce2b5846c..ffc269f8cc8 100644
--- a/src/librustc/middle/borrowck/doc.rs
+++ b/src/librustc/middle/borrowck/doc.rs
@@ -151,14 +151,13 @@ that the value `(*x).f` may be mutated via the newly created reference
 restrictions `RS` that accompany the loan.
 
 The first restriction `((*x).f, [MUTATE, CLAIM, FREEZE])` states that
-the lender may not mutate nor freeze `(*x).f`. Mutation is illegal
-because `(*x).f` is only supposed to be mutated via the new reference,
-not by mutating the original path `(*x).f`. Freezing is
+the lender may not mutate, freeze, nor alias `(*x).f`. Mutation is
+illegal because `(*x).f` is only supposed to be mutated via the new
+reference, not by mutating the original path `(*x).f`. Freezing is
 illegal because the path now has an `&mut` alias; so even if we the
 lender were to consider `(*x).f` to be immutable, it might be mutated
-via this alias. Both of these restrictions are temporary. They will be
-enforced for the lifetime `'a` of the loan. After the loan expires,
-the restrictions no longer apply.
+via this alias. They will be enforced for the lifetime `'a` of the
+loan. After the loan expires, the restrictions no longer apply.
 
 The second restriction on `*x` is interesting because it does not
 apply to the path that was lent (`(*x).f`) but rather to a prefix of
@@ -188,11 +187,9 @@ The kinds of expressions which in-scope loans can render illegal are:
   against mutating `lv`;
 - *moves*: illegal if there is any in-scope restriction on `lv` at all;
 - *mutable borrows* (`&mut lv`): illegal there is an in-scope restriction
-  against mutating `lv` or aliasing `lv`;
+  against claiming `lv`;
 - *immutable borrows* (`&lv`): illegal there is an in-scope restriction
-  against freezing `lv` or aliasing `lv`;
-- *read-only borrows* (`&const lv`): illegal there is an in-scope restriction
-  against aliasing `lv`.
+  against freezing `lv`.
 
 ## Formal rules
 
@@ -238,19 +235,23 @@ live. (This is done via restrictions, read on.)
 We start with the `gather_loans` pass, which walks the AST looking for
 borrows.  For each borrow, there are three bits of information: the
 lvalue `LV` being borrowed and the mutability `MQ` and lifetime `LT`
-of the resulting pointer. Given those, `gather_loans` applies three
+of the resulting pointer. Given those, `gather_loans` applies four
 validity tests:
 
 1. `MUTABILITY(LV, MQ)`: The mutability of the reference is
 compatible with the mutability of `LV` (i.e., not borrowing immutable
 data as mutable).
 
-2. `LIFETIME(LV, LT, MQ)`: The lifetime of the borrow does not exceed
+2. `ALIASABLE(LV, MQ)`: The aliasability of the reference is
+compatible with the aliasability of `LV`. The goal is to prevent
+`&mut` borrows of aliasability data.
+
+3. `LIFETIME(LV, LT, MQ)`: The lifetime of the borrow does not exceed
 the lifetime of the value being borrowed. This pass is also
 responsible for inserting root annotations to keep managed values
 alive.
 
-3. `RESTRICTIONS(LV, LT, ACTIONS) = RS`: This pass checks and computes the
+4. `RESTRICTIONS(LV, LT, ACTIONS) = RS`: This pass checks and computes the
 restrictions to maintain memory safety. These are the restrictions
 that will go into the final loan. We'll discuss in more detail below.
 
@@ -313,6 +314,47 @@ be borrowed if MQ is immutable or const:
     MUTABILITY(*LV, MQ)                 // M-Deref-Borrowed-Mut
       TYPE(LV) = &mut Ty
 
+## Checking aliasability
+
+The goal of the aliasability check is to ensure that we never permit
+`&mut` borrows of aliasable data. Formally we define a predicate
+`ALIASABLE(LV, MQ)` which if defined means that
+"borrowing `LV` with mutability `MQ` is ok". The
+Rust code corresponding to this predicate is the function
+`check_aliasability()` in `middle::borrowck::gather_loans`.
+
+### Checking aliasability of variables
+
+Local variables are never aliasable as they are accessible only within
+the stack frame.
+
+    ALIASABLE(X, MQ)                   // M-Var-Mut
+
+### Checking aliasable of owned content
+
+Owned content is aliasable if it is found in an aliasable location:
+
+    ALIASABLE(LV.f, MQ)                // M-Field
+      ALIASABLE(LV, MQ)
+
+    ALIASABLE(*LV, MQ)                 // M-Deref-Unique
+      ALIASABLE(LV, MQ)
+
+### Checking mutability of immutable pointer types
+
+Immutable pointer types like `&T` are aliasable, and hence can only be
+borrowed immutably:
+
+    ALIASABLE(*LV, imm)                // M-Deref-Borrowed-Imm
+      TYPE(LV) = &Ty
+
+### Checking mutability of mutable pointer types
+
+`&mut T` can be frozen, so it is acceptable to borrow it as either imm or mut:
+
+    ALIASABLE(*LV, MQ)                 // M-Deref-Borrowed-Mut
+      TYPE(LV) = &mut Ty
+
 ## Checking lifetime
 
 These rules aim to ensure that no data is borrowed for a scope that exceeds
diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs
index 173120e32f5..957073ac392 100644
--- a/src/librustc/middle/borrowck/gather_loans/mod.rs
+++ b/src/librustc/middle/borrowck/gather_loans/mod.rs
@@ -460,6 +460,11 @@ impl<'a> GatherLoanCtxt<'a> {
             return; // reported an error, no sense in reporting more.
         }
 
+        // Check that we don't allow mutable borrows of aliasable data.
+        if check_aliasability(self.bccx, borrow_span, cmt, req_mutbl).is_err() {
+            return; // reported an error, no sense in reporting more.
+        }
+
         // Compute the restrictions that are required to enforce the
         // loan is safe.
         let restr = restrictions::compute_restrictions(
@@ -568,11 +573,6 @@ impl<'a> GatherLoanCtxt<'a> {
             //! Implements the M-* rules in doc.rs.
 
             match req_mutbl {
-                ConstMutability => {
-                    // Data of any mutability can be lent as const.
-                    Ok(())
-                }
-
                 ImmutableMutability => {
                     // both imm and mut data can be lent as imm;
                     // for mutable data, this is a freeze
@@ -591,16 +591,53 @@ impl<'a> GatherLoanCtxt<'a> {
                 }
             }
         }
+
+        fn check_aliasability(bccx: &BorrowckCtxt,
+                              borrow_span: Span,
+                              cmt: mc::cmt,
+                              req_mutbl: LoanMutability) -> Result<(),()> {
+            //! Implements the A-* rules in doc.rs.
+
+            match req_mutbl {
+                ImmutableMutability => {
+                    // both imm and mut data can be lent as imm;
+                    // for mutable data, this is a freeze
+                    Ok(())
+                }
+
+                MutableMutability => {
+                    // Check for those cases where we cannot control
+                    // the aliasing and make sure that we are not
+                    // being asked to.
+                    match cmt.freely_aliasable() {
+                        None => {
+                            Ok(())
+                        }
+                        Some(mc::AliasableStaticMut) => {
+                            // This is nasty, but we ignore the
+                            // aliasing rules if the data is based in
+                            // a `static mut`, since those are always
+                            // unsafe. At your own peril and all that.
+                            Ok(())
+                        }
+                        Some(cause) => {
+                            bccx.report_aliasability_violation(
+                                borrow_span,
+                                BorrowViolation,
+                                cause);
+                            Err(())
+                        }
+                    }
+                }
+            }
+        }
     }
 
     pub fn restriction_set(&self, req_mutbl: LoanMutability)
                            -> RestrictionSet {
         match req_mutbl {
-            ConstMutability => RESTR_EMPTY,
-            ImmutableMutability => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM,
-            MutableMutability => {
-                RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM | RESTR_FREEZE
-            }
+            ImmutableMutability => RESTR_MUTATE | RESTR_CLAIM,
+            MutableMutability => RESTR_MUTATE | RESTR_CLAIM | RESTR_FREEZE,
         }
     }
 
diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs
index 22e64064c9c..60e0baa3534 100644
--- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs
+++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs
@@ -53,16 +53,6 @@ impl<'a> RestrictionsContext<'a> {
     fn restrict(&self,
                 cmt: mc::cmt,
                 restrictions: RestrictionSet) -> RestrictionResult {
-
-        // Check for those cases where we cannot control the aliasing
-        // and make sure that we are not being asked to.
-        match cmt.freely_aliasable() {
-            None => {}
-            Some(cause) => {
-                self.check_aliasing_permitted(cause, restrictions);
-            }
-        }
-
         match cmt.cat {
             mc::cat_rvalue(..) => {
                 // Effectively, rvalues are stored into a
@@ -179,28 +169,4 @@ impl<'a> RestrictionsContext<'a> {
             }
         }
     }
-
-    fn check_aliasing_permitted(&self,
-                                cause: mc::AliasableReason,
-                                restrictions: RestrictionSet) {
-        //! This method is invoked when the current `cmt` is something
-        //! where aliasing cannot be controlled. It reports an error if
-        //! the restrictions required that it not be aliased; currently
-        //! this only occurs when re-borrowing an `&mut` pointer.
-        //!
-        //! NB: To be 100% consistent, we should report an error if
-        //! RESTR_FREEZE is found, because we cannot prevent freezing,
-        //! nor would we want to. However, we do not report such an
-        //! error, because this restriction only occurs when the user
-        //! is creating an `&mut` pointer to immutable or read-only
-        //! data, and there is already another piece of code that
-        //! checks for this condition.
-
-        if restrictions.intersects(RESTR_ALIAS) {
-            self.bccx.report_aliasability_violation(
-                self.span,
-                BorrowViolation,
-                cause);
-        }
-    }
 }
diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs
index 6f3578f667d..6a3e2fc63b0 100644
--- a/src/librustc/middle/borrowck/mod.rs
+++ b/src/librustc/middle/borrowck/mod.rs
@@ -214,7 +214,6 @@ pub enum PartialTotal {
 #[deriving(Clone, Eq)]
 pub enum LoanMutability {
     ImmutableMutability,
-    ConstMutability,
     MutableMutability,
 }
 
@@ -232,7 +231,6 @@ impl ToStr for LoanMutability {
     fn to_str(&self) -> ~str {
         match *self {
             ImmutableMutability => ~"immutable",
-            ConstMutability => ~"read-only",
             MutableMutability => ~"mutable",
         }
     }
@@ -318,7 +316,6 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
 // - `RESTR_MUTATE`: The lvalue may not be modified.
 // - `RESTR_CLAIM`: `&mut` borrows of the lvalue are forbidden.
 // - `RESTR_FREEZE`: `&` borrows of the lvalue are forbidden.
-// - `RESTR_ALIAS`: All borrows of the lvalue are forbidden.
 //
 // In addition, no value which is restricted may be moved. Therefore,
 // restrictions are meaningful even if the RestrictionSet is empty,
@@ -338,7 +335,6 @@ pub static RESTR_EMPTY: RestrictionSet  = RestrictionSet {bits: 0b0000};
 pub static RESTR_MUTATE: RestrictionSet = RestrictionSet {bits: 0b0001};
 pub static RESTR_CLAIM: RestrictionSet  = RestrictionSet {bits: 0b0010};
 pub static RESTR_FREEZE: RestrictionSet = RestrictionSet {bits: 0b0100};
-pub static RESTR_ALIAS: RestrictionSet  = RestrictionSet {bits: 0b1000};
 
 impl RestrictionSet {
     pub fn intersects(&self, restr: RestrictionSet) -> bool {
@@ -663,8 +659,8 @@ impl BorrowckCtxt {
                                          kind: AliasableViolationKind,
                                          cause: mc::AliasableReason) {
         let prefix = match kind {
-            MutabilityViolation => "cannot assign to an `&mut`",
-            BorrowViolation => "cannot borrow an `&mut`"
+            MutabilityViolation => "cannot assign to data",
+            BorrowViolation => "cannot borrow data mutably"
         };
 
         match cause {
@@ -673,17 +669,21 @@ impl BorrowckCtxt {
                     span,
                     format!("{} in an aliasable location", prefix));
             }
+            mc::AliasableStatic |
+            mc::AliasableStaticMut => {
+                self.tcx.sess.span_err(
+                    span,
+                    format!("{} in a static location", prefix));
+            }
             mc::AliasableManaged => {
-                self.tcx.sess.span_err(span, format!("{} in a `@` pointer",
-                                                     prefix))
+                self.tcx.sess.span_err(
+                    span,
+                    format!("{} in a `@` pointer", prefix));
             }
-            mc::AliasableBorrowed(m) => {
+            mc::AliasableBorrowed(_) => {
                 self.tcx.sess.span_err(
                     span,
-                    format!("{} in a `&{}` pointer; \
-                          try an `&mut` instead",
-                         prefix,
-                         self.mut_to_keyword(m)));
+                    format!("{} in a `&` reference", prefix));
             }
         }
     }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index f5e3ff5db34..93f439b653c 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -1100,7 +1100,9 @@ pub fn field_mutbl(tcx: ty::ctxt,
 pub enum AliasableReason {
     AliasableManaged,
     AliasableBorrowed(ast::Mutability),
-    AliasableOther
+    AliasableOther,
+    AliasableStatic,
+    AliasableStaticMut,
 }
 
 impl cmt_ {
@@ -1130,10 +1132,6 @@ impl cmt_ {
         }
     }
 
-    pub fn is_freely_aliasable(&self) -> bool {
-        self.freely_aliasable().is_some()
-    }
-
     pub fn freely_aliasable(&self) -> Option<AliasableReason> {
         /*!
          * Returns `Some(_)` if this lvalue represents a freely aliasable
@@ -1145,20 +1143,36 @@ impl cmt_ {
         // aliased and eventually recused.
 
         match self.cat {
+            cat_deref(b, _, region_ptr(MutMutable, _)) |
+            cat_downcast(b) |
+            cat_stack_upvar(b) |
+            cat_deref(b, _, uniq_ptr) |
+            cat_interior(b, _) |
+            cat_discr(b, _) => {
+                // Aliasability depends on base cmt
+                b.freely_aliasable()
+            }
+
             cat_copied_upvar(CopiedUpvar {onceness: ast::Once, ..}) |
             cat_rvalue(..) |
             cat_local(..) |
             cat_arg(_) |
-            cat_deref(_, _, unsafe_ptr(..)) | // of course it is aliasable, but...
-            cat_deref(_, _, region_ptr(MutMutable, _)) => {
+            cat_deref(_, _, unsafe_ptr(..)) => { // yes, it's aliasable, but...
                 None
             }
 
-            cat_copied_upvar(CopiedUpvar {onceness: ast::Many, ..}) |
-            cat_static_item(..) => {
+            cat_copied_upvar(CopiedUpvar {onceness: ast::Many, ..}) => {
                 Some(AliasableOther)
             }
 
+            cat_static_item(..) => {
+                if self.mutbl.is_mutable() {
+                    Some(AliasableStaticMut)
+                } else {
+                    Some(AliasableStatic)
+                }
+            }
+
             cat_deref(_, _, gc_ptr) => {
                 Some(AliasableManaged)
             }
@@ -1166,14 +1180,6 @@ impl cmt_ {
             cat_deref(_, _, region_ptr(m @ MutImmutable, _)) => {
                 Some(AliasableBorrowed(m))
             }
-
-            cat_downcast(..) |
-            cat_stack_upvar(..) |
-            cat_deref(_, _, uniq_ptr) |
-            cat_interior(..) |
-            cat_discr(..) => {
-                None
-            }
         }
     }
 }
diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs
index d911208e7de..76cf5997aee 100644
--- a/src/libsyntax/ext/deriving/clone.rs
+++ b/src/libsyntax/ext/deriving/clone.rs
@@ -20,8 +20,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
                              in_items: ~[@Item])
                           -> ~[@Item] {
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "clone", "Clone"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -39,7 +38,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
         ]
     };
 
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 pub fn expand_deriving_deep_clone(cx: &mut ExtCtxt,
@@ -48,8 +47,7 @@ pub fn expand_deriving_deep_clone(cx: &mut ExtCtxt,
                                   in_items: ~[@Item])
     -> ~[@Item] {
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "clone", "DeepClone"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -69,7 +67,7 @@ pub fn expand_deriving_deep_clone(cx: &mut ExtCtxt,
         ]
     };
 
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 fn cs_clone(
diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs
index a469c4a960b..4672f1a8db6 100644
--- a/src/libsyntax/ext/deriving/cmp/eq.rs
+++ b/src/libsyntax/ext/deriving/cmp/eq.rs
@@ -45,8 +45,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
     );
 
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "cmp", "Eq"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -55,5 +54,5 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
             md!("ne", cs_ne)
         ]
     };
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs
index c06b4e30e07..1a8ace69307 100644
--- a/src/libsyntax/ext/deriving/cmp/ord.rs
+++ b/src/libsyntax/ext/deriving/cmp/ord.rs
@@ -35,8 +35,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt,
     );
 
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "cmp", "Ord"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -47,7 +46,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt,
             md!("ge", false, true)
         ]
     };
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 /// Strict inequality.
diff --git a/src/libsyntax/ext/deriving/cmp/totaleq.rs b/src/libsyntax/ext/deriving/cmp/totaleq.rs
index 0a38a2ce30d..7b7c1afa4d5 100644
--- a/src/libsyntax/ext/deriving/cmp/totaleq.rs
+++ b/src/libsyntax/ext/deriving/cmp/totaleq.rs
@@ -24,8 +24,7 @@ pub fn expand_deriving_totaleq(cx: &mut ExtCtxt,
     }
 
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "cmp", "TotalEq"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -42,5 +41,5 @@ pub fn expand_deriving_totaleq(cx: &mut ExtCtxt,
             }
         ]
     };
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs
index 68de158e9e7..157b6dc7521 100644
--- a/src/libsyntax/ext/deriving/cmp/totalord.rs
+++ b/src/libsyntax/ext/deriving/cmp/totalord.rs
@@ -21,8 +21,7 @@ pub fn expand_deriving_totalord(cx: &mut ExtCtxt,
                                 mitem: @MetaItem,
                                 in_items: ~[@Item]) -> ~[@Item] {
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "cmp", "TotalOrd"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -40,7 +39,7 @@ pub fn expand_deriving_totalord(cx: &mut ExtCtxt,
         ]
     };
 
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 
diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs
index 7324500a8a0..fdf1ef17d53 100644
--- a/src/libsyntax/ext/deriving/decodable.rs
+++ b/src/libsyntax/ext/deriving/decodable.rs
@@ -26,8 +26,7 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
                                  mitem: @MetaItem,
                                  in_items: ~[@Item]) -> ~[@Item] {
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new_(~["serialize", "Decodable"], None,
                          ~[~Literal(Path::new_local("__D"))], true),
         additional_bounds: ~[],
@@ -50,7 +49,7 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
         ]
     };
 
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs
index 922ee164353..7b87152b711 100644
--- a/src/libsyntax/ext/deriving/default.rs
+++ b/src/libsyntax/ext/deriving/default.rs
@@ -18,10 +18,9 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt,
                             span: Span,
                             mitem: @MetaItem,
                             in_items: ~[@Item])
-    -> ~[@Item] {
+                               -> ~[@Item] {
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "default", "Default"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -38,7 +37,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt,
             },
         ]
     };
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs
index 4de31adc7f2..43edf6006b4 100644
--- a/src/libsyntax/ext/deriving/encodable.rs
+++ b/src/libsyntax/ext/deriving/encodable.rs
@@ -87,8 +87,7 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
                                  mitem: @MetaItem,
                                  in_items: ~[@Item]) -> ~[@Item] {
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new_(~["serialize", "Encodable"], None,
                          ~[~Literal(Path::new_local("__E"))], true),
         additional_bounds: ~[],
@@ -111,7 +110,7 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
         ]
     };
 
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs
index 01006a0c15d..47be3067284 100644
--- a/src/libsyntax/ext/deriving/generic.rs
+++ b/src/libsyntax/ext/deriving/generic.rs
@@ -193,13 +193,12 @@ pub use self::ty::*;
 mod ty;
 
 pub struct TraitDef<'a> {
-    /// The extension context
-    cx: &'a mut ExtCtxt<'a>,
     /// The span for the current #[deriving(Foo)] header.
     span: Span,
 
     /// Path of the trait, including any type parameters
     path: Path<'a>,
+
     /// Additional bounds required of any type parameters of the type,
     /// other than the current trait
     additional_bounds: ~[Ty<'a>],
@@ -321,6 +320,7 @@ pub type EnumNonMatchFunc<'a> =
 
 impl<'a> TraitDef<'a> {
     pub fn expand(&self,
+                  cx: &mut ExtCtxt,
                   _mitem: @ast::MetaItem,
                   in_items: ~[@ast::Item]) -> ~[@ast::Item] {
         let mut result = ~[];
@@ -328,12 +328,14 @@ impl<'a> TraitDef<'a> {
             result.push(*item);
             match item.node {
                 ast::ItemStruct(struct_def, ref generics) => {
-                    result.push(self.expand_struct_def(struct_def,
+                    result.push(self.expand_struct_def(cx,
+                                                       struct_def,
                                                        item.ident,
                                                        generics));
                 }
                 ast::ItemEnum(ref enum_def, ref generics) => {
-                    result.push(self.expand_enum_def(enum_def,
+                    result.push(self.expand_enum_def(cx,
+                                                     enum_def,
                                                      item.ident,
                                                      generics));
                 }
@@ -354,9 +356,9 @@ impl<'a> TraitDef<'a> {
      *
      */
     fn create_derived_impl(&self,
+                           cx: &mut ExtCtxt,
                            type_ident: Ident, generics: &Generics,
                            methods: ~[@ast::Method]) -> @ast::Item {
-        let cx = &*self.cx;
         let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
 
         let mut trait_generics = self.generics.to_generics(cx, self.span,
@@ -372,7 +374,8 @@ impl<'a> TraitDef<'a> {
             let mut bounds = opt_vec::from(
                 // extra restrictions on the generics parameters to the type being derived upon
                 self.additional_bounds.map(|p| {
-                    cx.typarambound(p.to_path(cx, self.span, type_ident, generics))
+                    cx.typarambound(p.to_path(cx, self.span,
+                                                  type_ident, generics))
                 }));
             // require the current trait
             bounds.push(cx.typarambound(trait_path.clone()));
@@ -393,15 +396,15 @@ impl<'a> TraitDef<'a> {
         // Create the type of `self`.
         let self_type = cx.ty_path(
             cx.path_all(self.span, false, ~[ type_ident ], self_lifetimes,
-                             opt_vec::take_vec(self_ty_params)), None);
+                        opt_vec::take_vec(self_ty_params)), None);
 
         let doc_attr = cx.attribute(
             self.span,
             cx.meta_name_value(self.span,
                                InternedString::new("doc"),
                                ast::LitStr(token::intern_and_get_ident(
-                                       "Automatically derived."),
-                                       ast::CookedStr)));
+                                               "Automatically derived."),
+                                           ast::CookedStr)));
         cx.item(
             self.span,
             ::parse::token::special_idents::clownshoes_extensions,
@@ -411,68 +414,77 @@ impl<'a> TraitDef<'a> {
     }
 
     fn expand_struct_def(&self,
+                         cx: &mut ExtCtxt,
                          struct_def: &StructDef,
                          type_ident: Ident,
                          generics: &Generics) -> @ast::Item {
         let methods = self.methods.map(|method_def| {
             let (explicit_self, self_args, nonself_args, tys) =
-                method_def.split_self_nonself_args(self, type_ident, generics);
+                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(self,
+                method_def.expand_struct_method_body(cx,
+                                                     self,
                                                      struct_def,
                                                      type_ident,
                                                      self_args, nonself_args)
             };
 
-            method_def.create_method(self,
+            method_def.create_method(cx, self,
                                      type_ident, generics,
                                      explicit_self, tys,
                                      body)
         });
 
-        self.create_derived_impl(type_ident, generics, methods)
+        self.create_derived_impl(cx, type_ident, generics, methods)
     }
 
     fn expand_enum_def(&self,
+                       cx: &mut ExtCtxt,
                        enum_def: &EnumDef,
                        type_ident: Ident,
                        generics: &Generics) -> @ast::Item {
         let methods = self.methods.map(|method_def| {
             let (explicit_self, self_args, nonself_args, tys) =
-                method_def.split_self_nonself_args(self, type_ident, generics);
+                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(self,
+                method_def.expand_enum_method_body(cx,
+                                                   self,
                                                    enum_def,
                                                    type_ident,
                                                    self_args, nonself_args)
             };
 
-            method_def.create_method(self,
+            method_def.create_method(cx, self,
                                      type_ident, generics,
                                      explicit_self, tys,
                                      body)
         });
 
-        self.create_derived_impl(type_ident, generics, methods)
+        self.create_derived_impl(cx, type_ident, generics, methods)
     }
 }
 
 impl<'a> MethodDef<'a> {
     fn call_substructure_method(&self,
+                                cx: &mut ExtCtxt,
                                 trait_: &TraitDef,
                                 type_ident: Ident,
                                 self_args: &[@Expr],
@@ -481,26 +493,33 @@ impl<'a> MethodDef<'a> {
         -> @Expr {
         let substructure = Substructure {
             type_ident: type_ident,
-            method_ident: trait_.cx.ident_of(self.name),
+            method_ident: cx.ident_of(self.name),
             self_args: self_args,
             nonself_args: nonself_args,
             fields: fields
         };
-        (self.combine_substructure)(trait_.cx, trait_.span,
+        (self.combine_substructure)(cx, trait_.span,
                                     &substructure)
     }
 
-    fn get_ret_ty(&self, trait_: &TraitDef,
-                  generics: &Generics, type_ident: Ident) -> P<ast::Ty> {
-        self.ret_ty.to_ty(trait_.cx, trait_.span, type_ident, generics)
+    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, trait_: &TraitDef,
-                               type_ident: Ident, generics: &Generics)
+    fn split_self_nonself_args(&self,
+                               cx: &mut ExtCtxt,
+                               trait_: &TraitDef,
+                               type_ident: Ident,
+                               generics: &Generics)
         -> (ast::ExplicitSelf, ~[@Expr], ~[@Expr], ~[(Ident, P<ast::Ty>)]) {
 
         let mut self_args = ~[];
@@ -511,7 +530,7 @@ impl<'a> MethodDef<'a> {
         let ast_explicit_self = match self.explicit_self {
             Some(ref self_ptr) => {
                 let (self_expr, explicit_self) =
-                    ty::get_explicit_self(trait_.cx, trait_.span, self_ptr);
+                    ty::get_explicit_self(cx, trait_.span, self_ptr);
 
                 self_args.push(self_expr);
                 nonstatic = true;
@@ -522,11 +541,11 @@ impl<'a> MethodDef<'a> {
         };
 
         for (i, ty) in self.args.iter().enumerate() {
-            let ast_ty = ty.to_ty(trait_.cx, trait_.span, type_ident, generics);
-            let ident = trait_.cx.ident_of(format!("__arg_{}", i));
+            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 = trait_.cx.expr_ident(trait_.span, ident);
+            let arg_expr = cx.expr_ident(trait_.span, ident);
 
             match *ty {
                 // for static methods, just treat any Self
@@ -535,7 +554,7 @@ impl<'a> MethodDef<'a> {
                     self_args.push(arg_expr);
                 }
                 Ptr(~Self, _) if nonstatic => {
-                    self_args.push(trait_.cx.expr_deref(trait_.span, arg_expr))
+                    self_args.push(cx.expr_deref(trait_.span, arg_expr))
                 }
                 _ => {
                     nonself_args.push(arg_expr);
@@ -546,35 +565,37 @@ impl<'a> MethodDef<'a> {
         (ast_explicit_self, self_args, nonself_args, arg_tys)
     }
 
-    fn create_method(&self, trait_: &TraitDef,
+    fn create_method(&self,
+                     cx: &mut ExtCtxt,
+                     trait_: &TraitDef,
                      type_ident: Ident,
                      generics: &Generics,
                      explicit_self: ast::ExplicitSelf,
                      arg_types: ~[(Ident, P<ast::Ty>)],
                      body: @Expr) -> @ast::Method {
         // create the generics that aren't for Self
-        let fn_generics = self.generics.to_generics(trait_.cx, trait_.span, type_ident, generics);
+        let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
 
         let self_arg = match explicit_self.node {
             ast::SelfStatic => None,
             _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable))
         };
         let args = arg_types.move_iter().map(|(name, ty)| {
-            trait_.cx.arg(trait_.span, name, ty)
+            cx.arg(trait_.span, name, ty)
         });
         let args = self_arg.move_iter().chain(args).collect();
 
-        let ret_type = self.get_ret_ty(trait_, generics, type_ident);
+        let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
 
-        let method_ident = trait_.cx.ident_of(self.name);
-        let fn_decl = trait_.cx.fn_decl(args, ret_type);
-        let body_block = trait_.cx.block_expr(body);
+        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 attrs = if self.inline {
             ~[
-                trait_.cx
+                cx
                       .attribute(trait_.span,
-                                 trait_.cx
+                                 cx
                                        .meta_word(trait_.span,
                                                   InternedString::new(
                                                       "inline")))
@@ -620,6 +641,7 @@ impl<'a> MethodDef<'a> {
    ~~~
     */
     fn expand_struct_method_body(&self,
+                                 cx: &mut ExtCtxt,
                                  trait_: &TraitDef,
                                  struct_def: &StructDef,
                                  type_ident: Ident,
@@ -631,7 +653,7 @@ impl<'a> MethodDef<'a> {
                                  // [fields of next Self arg], [etc]]
         let mut patterns = ~[];
         for i in range(0u, self_args.len()) {
-            let (pat, ident_expr) = trait_.create_struct_pattern(type_ident, struct_def,
+            let (pat, ident_expr) = trait_.create_struct_pattern(cx, type_ident, struct_def,
                                                                  format!("__self_{}", i),
                                                                  ast::MutImmutable);
             patterns.push(pat);
@@ -655,13 +677,14 @@ impl<'a> MethodDef<'a> {
                     }
                 }).collect()
             }
-            [] => { trait_.cx.span_bug(trait_.span,
-                                       "no self arguments to non-static method \
-                                       in generic `deriving`") }
+            [] => { cx.span_bug(trait_.span,
+                                "no self arguments to non-static method \
+                                in generic `deriving`") }
         };
 
         // body of the inner most destructuring match
         let mut body = self.call_substructure_method(
+            cx,
             trait_,
             type_ident,
             self_args,
@@ -672,22 +695,24 @@ impl<'a> MethodDef<'a> {
         // structs. This is actually right-to-left, but it shoudn't
         // matter.
         for (&arg_expr, &pat) in self_args.iter().zip(patterns.iter()) {
-            body = trait_.cx.expr_match(trait_.span, arg_expr,
-                                        ~[ trait_.cx.arm(trait_.span, ~[pat], body) ])
+            body = cx.expr_match(trait_.span, arg_expr,
+                                     ~[ cx.arm(trait_.span, ~[pat], body) ])
         }
         body
     }
 
     fn expand_static_struct_method_body(&self,
+                                        cx: &mut ExtCtxt,
                                         trait_: &TraitDef,
                                         struct_def: &StructDef,
                                         type_ident: Ident,
                                         self_args: &[@Expr],
                                         nonself_args: &[@Expr])
         -> @Expr {
-        let summary = trait_.summarise_struct(struct_def);
+        let summary = trait_.summarise_struct(cx, struct_def);
 
-        self.call_substructure_method(trait_,
+        self.call_substructure_method(cx,
+                                      trait_,
                                       type_ident,
                                       self_args, nonself_args,
                                       &StaticStruct(struct_def, summary))
@@ -720,14 +745,15 @@ impl<'a> MethodDef<'a> {
    ~~~
     */
     fn expand_enum_method_body(&self,
+                               cx: &mut ExtCtxt,
                                trait_: &TraitDef,
                                enum_def: &EnumDef,
                                type_ident: Ident,
                                self_args: &[@Expr],
                                nonself_args: &[@Expr])
-        -> @Expr {
+                               -> @Expr {
         let mut matches = ~[];
-        self.build_enum_match(trait_, enum_def, type_ident,
+        self.build_enum_match(cx, trait_, enum_def, type_ident,
                               self_args, nonself_args,
                               None, &mut matches, 0)
     }
@@ -755,6 +781,7 @@ impl<'a> MethodDef<'a> {
     the first call).
     */
     fn build_enum_match(&self,
+                        cx: &mut ExtCtxt,
                         trait_: &TraitDef,
                         enum_def: &EnumDef,
                         type_ident: Ident,
@@ -764,13 +791,13 @@ impl<'a> MethodDef<'a> {
                         matches_so_far: &mut ~[(uint, P<ast::Variant>,
                                               ~[(Span, Option<Ident>, @Expr)])],
                         match_count: uint) -> @Expr {
-        let cx = &trait_.cx;
         if match_count == self_args.len() {
             // we've matched against all arguments, so make the final
             // expression at the bottom of the match tree
             if matches_so_far.len() == 0 {
                 cx.span_bug(trait_.span,
-                            "no self match on an enum in generic `deriving`");
+                                "no self match on an enum in \
+                                generic `deriving`");
             }
             // we currently have a vec of vecs, where each
             // subvec is the fields of one of the arguments,
@@ -820,7 +847,7 @@ impl<'a> MethodDef<'a> {
                     substructure = EnumNonMatching(*matches_so_far);
                 }
             }
-            self.call_substructure_method(trait_, type_ident,
+            self.call_substructure_method(cx, trait_, type_ident,
                                           self_args, nonself_args,
                                           &substructure)
 
@@ -846,12 +873,14 @@ impl<'a> MethodDef<'a> {
 
                 // matching-variant match
                 let variant = enum_def.variants[index];
-                let (pattern, idents) = trait_.create_enum_variant_pattern(variant,
+                let (pattern, idents) = trait_.create_enum_variant_pattern(cx,
+                                                                           variant,
                                                                            current_match_str,
                                                                            ast::MutImmutable);
 
                 matches_so_far.push((index, variant, idents));
-                let arm_expr = self.build_enum_match(trait_,
+                let arm_expr = self.build_enum_match(cx,
+                                                     trait_,
                                                      enum_def,
                                                      type_ident,
                                                      self_args, nonself_args,
@@ -863,18 +892,20 @@ impl<'a> MethodDef<'a> {
 
                 if enum_def.variants.len() > 1 {
                     let e = &EnumNonMatching(&[]);
-                    let wild_expr = self.call_substructure_method(trait_, type_ident,
+                    let wild_expr = self.call_substructure_method(cx, trait_, type_ident,
                                                                   self_args, nonself_args,
                                                                   e);
-                    let wild_arm = cx.arm(trait_.span,
-                                          ~[ cx.pat_wild(trait_.span) ],
-                                          wild_expr);
+                    let wild_arm = cx.arm(
+                        trait_.span,
+                        ~[ cx.pat_wild(trait_.span) ],
+                        wild_expr);
                     arms.push(wild_arm);
                 }
             } else {
                 // create an arm matching on each variant
                 for (index, &variant) in enum_def.variants.iter().enumerate() {
-                    let (pattern, idents) = trait_.create_enum_variant_pattern(variant,
+                    let (pattern, idents) = trait_.create_enum_variant_pattern(cx,
+                                                                               variant,
                                                                                current_match_str,
                                                                                ast::MutImmutable);
 
@@ -885,7 +916,8 @@ impl<'a> MethodDef<'a> {
                             Some(i) if index == i => Some(i),
                             _ => None
                         };
-                    let arm_expr = self.build_enum_match(trait_,
+                    let arm_expr = self.build_enum_match(cx,
+                                                         trait_,
                                                          enum_def,
                                                          type_ident,
                                                          self_args, nonself_args,
@@ -905,6 +937,7 @@ impl<'a> MethodDef<'a> {
     }
 
     fn expand_static_enum_method_body(&self,
+                                      cx: &mut ExtCtxt,
                                       trait_: &TraitDef,
                                       enum_def: &EnumDef,
                                       type_ident: Ident,
@@ -915,15 +948,15 @@ impl<'a> MethodDef<'a> {
             let ident = v.node.name;
             let summary = match v.node.kind {
                 ast::TupleVariantKind(ref args) => {
-                    Unnamed(args.map(|va| trait_.set_expn_info(va.ty.span)))
+                    Unnamed(args.map(|va| trait_.set_expn_info(cx, va.ty.span)))
                 }
                 ast::StructVariantKind(struct_def) => {
-                    trait_.summarise_struct(struct_def)
+                    trait_.summarise_struct(cx, struct_def)
                 }
             };
             (ident, v.span, summary)
         });
-        self.call_substructure_method(trait_, type_ident,
+        self.call_substructure_method(cx, trait_, type_ident,
                                       self_args, nonself_args,
                                       &StaticEnum(enum_def, summary))
     }
@@ -936,9 +969,11 @@ enum StructType {
 
 // general helper methods.
 impl<'a> TraitDef<'a> {
-    fn set_expn_info(&self, mut to_set: Span) -> Span {
+    fn set_expn_info(&self,
+                     cx: &mut ExtCtxt,
+                     mut to_set: Span) -> Span {
         let trait_name = match self.path.path.last() {
-            None => self.cx.span_bug(self.span, "trait with empty path in generic `deriving`"),
+            None => cx.span_bug(self.span, "trait with empty path in generic `deriving`"),
             Some(name) => *name
         };
         to_set.expn_info = Some(@codemap::ExpnInfo {
@@ -952,11 +987,13 @@ impl<'a> TraitDef<'a> {
         to_set
     }
 
-    fn summarise_struct(&self, struct_def: &StructDef) -> StaticFields {
+    fn summarise_struct(&self,
+                        cx: &mut ExtCtxt,
+                        struct_def: &StructDef) -> StaticFields {
         let mut named_idents = ~[];
         let mut just_spans = ~[];
         for field in struct_def.fields.iter(){
-            let sp = self.set_expn_info(field.span);
+            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),
@@ -964,9 +1001,9 @@ impl<'a> TraitDef<'a> {
         }
 
         match (just_spans.is_empty(), named_idents.is_empty()) {
-            (false, false) => self.cx.span_bug(self.span,
-                                               "a struct with named and unnamed \
-                                               fields in generic `deriving`"),
+            (false, false) => cx.span_bug(self.span,
+                                          "a struct with named and unnamed \
+                                          fields in generic `deriving`"),
             // named fields
             (_, false) => Named(named_idents),
             // tuple structs (includes empty structs)
@@ -975,23 +1012,23 @@ impl<'a> TraitDef<'a> {
     }
 
     fn create_subpatterns(&self,
+                          cx: &mut ExtCtxt,
                           field_paths: ~[ast::Path],
                           mutbl: ast::Mutability)
                           -> ~[@ast::Pat] {
         field_paths.map(|path| {
-            self.cx.pat(path.span,
+            cx.pat(path.span,
                         ast::PatIdent(ast::BindByRef(mutbl), (*path).clone(), None))
             })
     }
 
     fn create_struct_pattern(&self,
+                             cx: &mut ExtCtxt,
                              struct_ident: Ident,
                              struct_def: &StructDef,
                              prefix: &str,
                              mutbl: ast::Mutability)
-        -> (@ast::Pat, ~[(Span, Option<Ident>, @Expr)]) {
-        let cx = &self.cx;
-
+                             -> (@ast::Pat, ~[(Span, Option<Ident>, @Expr)]) {
         if struct_def.fields.is_empty() {
             return (
                 cx.pat_ident_binding_mode(
@@ -1006,7 +1043,7 @@ impl<'a> TraitDef<'a> {
         let mut struct_type = Unknown;
 
         for (i, struct_field) in struct_def.fields.iter().enumerate() {
-            let sp = self.set_expn_info(struct_field.span);
+            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) => {
@@ -1024,11 +1061,13 @@ impl<'a> TraitDef<'a> {
             };
             let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i)));
             paths.push(path.clone());
-            let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(path))));
+            let val = cx.expr(
+                sp, ast::ExprParen(
+                    cx.expr_deref(sp, cx.expr_path(path))));
             ident_expr.push((sp, opt_id, val));
         }
 
-        let subpats = self.create_subpatterns(paths, mutbl);
+        let subpats = self.create_subpatterns(cx, paths, mutbl);
 
         // struct_type is definitely not Unknown, since struct_def.fields
         // must be nonempty to reach here
@@ -1046,17 +1085,17 @@ impl<'a> TraitDef<'a> {
     }
 
     fn create_enum_variant_pattern(&self,
+                                   cx: &mut ExtCtxt,
                                    variant: &ast::Variant,
                                    prefix: &str,
                                    mutbl: ast::Mutability)
         -> (@ast::Pat, ~[(Span, Option<Ident>, @Expr)]) {
-        let cx = &*self.cx;
         let variant_ident = variant.node.name;
         match variant.node.kind {
             ast::TupleVariantKind(ref variant_args) => {
                 if variant_args.is_empty() {
                     return (cx.pat_ident_binding_mode(variant.span, variant_ident,
-                                                      ast::BindByValue(ast::MutImmutable)),
+                                                          ast::BindByValue(ast::MutImmutable)),
                             ~[]);
                 }
 
@@ -1065,21 +1104,22 @@ impl<'a> TraitDef<'a> {
                 let mut paths = ~[];
                 let mut ident_expr = ~[];
                 for (i, va) in variant_args.iter().enumerate() {
-                    let sp = self.set_expn_info(va.ty.span);
+                    let sp = self.set_expn_info(cx, va.ty.span);
                     let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i)));
 
                     paths.push(path.clone());
-                    let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(path))));
+                    let val = cx.expr(
+                        sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(path))));
                     ident_expr.push((sp, None, val));
                 }
 
-                let subpats = self.create_subpatterns(paths, mutbl);
+                let subpats = self.create_subpatterns(cx, paths, mutbl);
 
                 (cx.pat_enum(variant.span, matching_path, subpats),
                  ident_expr)
             }
             ast::StructVariantKind(struct_def) => {
-                self.create_struct_pattern(variant_ident, struct_def,
+                self.create_struct_pattern(cx, variant_ident, struct_def,
                                            prefix, mutbl)
             }
         }
diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs
index 5f680745ea7..19e81b81df6 100644
--- a/src/libsyntax/ext/deriving/iter_bytes.rs
+++ b/src/libsyntax/ext/deriving/iter_bytes.rs
@@ -20,8 +20,7 @@ pub fn expand_deriving_iter_bytes(cx: &mut ExtCtxt,
                                   mitem: @MetaItem,
                                   in_items: ~[@Item]) -> ~[@Item] {
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "to_bytes", "IterBytes"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -42,7 +41,7 @@ pub fn expand_deriving_iter_bytes(cx: &mut ExtCtxt,
         ]
     };
 
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 fn iter_bytes_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs
index f74b807bae6..1b356667b6b 100644
--- a/src/libsyntax/ext/deriving/primitive.rs
+++ b/src/libsyntax/ext/deriving/primitive.rs
@@ -21,8 +21,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
                                       mitem: @MetaItem,
                                       in_items: ~[@Item]) -> ~[@Item] {
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "num", "FromPrimitive"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -62,7 +61,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
         ]
     };
 
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs
index 15595f6eddc..a40317286c9 100644
--- a/src/libsyntax/ext/deriving/rand.rs
+++ b/src/libsyntax/ext/deriving/rand.rs
@@ -20,10 +20,9 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt,
                             span: Span,
                             mitem: @MetaItem,
                             in_items: ~[@Item])
-    -> ~[@Item] {
+                            -> ~[@Item] {
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "rand", "Rand"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -47,7 +46,7 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt,
             }
         ]
     };
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
diff --git a/src/libsyntax/ext/deriving/show.rs b/src/libsyntax/ext/deriving/show.rs
index 67cfd151f62..e2d507f3035 100644
--- a/src/libsyntax/ext/deriving/show.rs
+++ b/src/libsyntax/ext/deriving/show.rs
@@ -24,14 +24,13 @@ pub fn expand_deriving_show(cx: &mut ExtCtxt,
                             span: Span,
                             mitem: @MetaItem,
                             in_items: ~[@Item])
-    -> ~[@Item] {
+                            -> ~[@Item] {
     // &mut ::std::fmt::Formatter
     let fmtr = Ptr(~Literal(Path::new(~["std", "fmt", "Formatter"])),
                    Borrowed(None, ast::MutMutable));
 
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "fmt", "Show"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -48,7 +47,7 @@ pub fn expand_deriving_show(cx: &mut ExtCtxt,
             }
         ]
     };
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 // we construct a format string and then defer to std::fmt, since that
diff --git a/src/libsyntax/ext/deriving/to_str.rs b/src/libsyntax/ext/deriving/to_str.rs
index 2f50d5ad121..186f1254493 100644
--- a/src/libsyntax/ext/deriving/to_str.rs
+++ b/src/libsyntax/ext/deriving/to_str.rs
@@ -21,10 +21,9 @@ pub fn expand_deriving_to_str(cx: &mut ExtCtxt,
                               span: Span,
                               mitem: @MetaItem,
                               in_items: ~[@Item])
-    -> ~[@Item] {
+                              -> ~[@Item] {
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "to_str", "ToStr"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -41,7 +40,7 @@ pub fn expand_deriving_to_str(cx: &mut ExtCtxt,
             }
         ]
     };
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 // It used to be the case that this deriving implementation invoked
diff --git a/src/libsyntax/ext/deriving/zero.rs b/src/libsyntax/ext/deriving/zero.rs
index ecd06b3f49e..ca5c1543d88 100644
--- a/src/libsyntax/ext/deriving/zero.rs
+++ b/src/libsyntax/ext/deriving/zero.rs
@@ -18,10 +18,9 @@ pub fn expand_deriving_zero(cx: &mut ExtCtxt,
                             span: Span,
                             mitem: @MetaItem,
                             in_items: ~[@Item])
-    -> ~[@Item] {
+                            -> ~[@Item] {
     let trait_def = TraitDef {
-        cx: cx, span: span,
-
+        span: span,
         path: Path::new(~["std", "num", "Zero"]),
         additional_bounds: ~[],
         generics: LifetimeBounds::empty(),
@@ -54,7 +53,7 @@ pub fn expand_deriving_zero(cx: &mut ExtCtxt,
             }
         ]
     };
-    trait_def.expand(mitem, in_items)
+    trait_def.expand(cx, mitem, in_items)
 }
 
 fn zero_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
diff --git a/src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs b/src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs
index f72dacc2d81..d19538c5d36 100644
--- a/src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs
+++ b/src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs
@@ -27,5 +27,10 @@ fn foo3(t0: &mut &mut int) {
     **t1 = 22;
 }
 
+fn foo4(t0: & &mut int) {
+    let x:  &mut int = &mut **t0; //~ ERROR cannot borrow
+    *x += 1;
+}
+
 fn main() {
 }