about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-06-25 01:59:05 -0700
committerbors <bors@rust-lang.org>2013-06-25 01:59:05 -0700
commitb11346bb5d2659313eb96f3108137f01239785c9 (patch)
tree22512167bcef6503c310e87ca74c40a43fcef07c /src
parent5a089c252e1645c1b321c8b6811f89ae3fea4bd2 (diff)
parentb94f89fffc0c31a2e9048a824a66ff121c908818 (diff)
auto merge of #7291 : alexcrichton/rust/static-mut, r=huonw
This adds both `static mut` items and `static mut` foreign items. This involved changing far less code than I thought it was going to, but the tests seem to pass and the variables seem functional.

I'm more than willing to write more tests, so suggestions are welcome!

Closes #553
Diffstat (limited to 'src')
-rw-r--r--src/librustc/metadata/decoder.rs16
-rw-r--r--src/librustc/metadata/encoder.rs18
-rw-r--r--src/librustc/middle/astencode.rs2
-rw-r--r--src/librustc/middle/check_const.rs6
-rw-r--r--src/librustc/middle/check_match.rs10
-rw-r--r--src/librustc/middle/const_eval.rs6
-rw-r--r--src/librustc/middle/effect.rs10
-rw-r--r--src/librustc/middle/lint.rs48
-rw-r--r--src/librustc/middle/mem_categorization.rs28
-rw-r--r--src/librustc/middle/pat_util.rs2
-rw-r--r--src/librustc/middle/resolve.rs21
-rw-r--r--src/librustc/middle/trans/_match.rs9
-rw-r--r--src/librustc/middle/trans/base.rs14
-rw-r--r--src/librustc/middle/trans/callee.rs2
-rw-r--r--src/librustc/middle/trans/consts.rs12
-rw-r--r--src/librustc/middle/trans/expr.rs2
-rw-r--r--src/librustc/middle/trans/foreign.rs2
-rw-r--r--src/librustc/middle/trans/reachable.rs2
-rw-r--r--src/librustc/middle/ty.rs2
-rw-r--r--src/librustc/middle/typeck/check/mod.rs4
-rw-r--r--src/librustc/middle/typeck/collect.rs4
-rw-r--r--src/librustdoc/extract.rs4
-rw-r--r--src/librustdoc/tystr_pass.rs2
-rw-r--r--src/libsyntax/ast.rs6
-rw-r--r--src/libsyntax/ast_map.rs2
-rw-r--r--src/libsyntax/ast_util.rs2
-rw-r--r--src/libsyntax/fold.rs6
-rw-r--r--src/libsyntax/parse/parser.rs10
-rw-r--r--src/libsyntax/print/pprust.rs10
-rw-r--r--src/libsyntax/visit.rs4
-rw-r--r--src/rt/rust_builtin.cpp10
-rw-r--r--src/rt/rustrt.def.in4
-rw-r--r--src/test/auxiliary/static_mut_xc.rs1
-rw-r--r--src/test/compile-fail/static-mut-bad-types.rs17
-rw-r--r--src/test/compile-fail/static-mut-foreign-requires-unsafe.rs21
-rw-r--r--src/test/compile-fail/static-mut-not-constant.rs13
-rw-r--r--src/test/compile-fail/static-mut-not-pat.rs26
-rw-r--r--src/test/compile-fail/static-mut-requires-unsafe.rs17
-rw-r--r--src/test/run-pass/static-mut-foreign.rs46
-rw-r--r--src/test/run-pass/static-mut-xc.rs46
40 files changed, 358 insertions, 109 deletions
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index db44ac5e442..714164d6a12 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -96,7 +96,8 @@ fn lookup_item(item_id: int, data: @~[u8]) -> ebml::Doc {
 
 #[deriving(Eq)]
 enum Family {
-    Const,                 // c
+    ImmStatic,             // c
+    MutStatic,             // b
     Fn,                    // f
     UnsafeFn,              // u
     PureFn,                // p
@@ -121,7 +122,8 @@ enum Family {
 fn item_family(item: ebml::Doc) -> Family {
     let fam = reader::get_doc(item, tag_items_data_item_family);
     match reader::doc_as_u8(fam) as char {
-      'c' => Const,
+      'c' => ImmStatic,
+      'b' => MutStatic,
       'f' => Fn,
       'u' => UnsafeFn,
       'p' => PureFn,
@@ -320,7 +322,8 @@ fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num)
     -> def_like {
     let fam = item_family(item);
     match fam {
-        Const     => dl_def(ast::def_const(did)),
+        ImmStatic => dl_def(ast::def_static(did, false)),
+        MutStatic => dl_def(ast::def_static(did, true)),
         Struct    => dl_def(ast::def_struct(did)),
         UnsafeFn  => dl_def(ast::def_fn(did, ast::unsafe_fn)),
         Fn        => dl_def(ast::def_fn(did, ast::impure_fn)),
@@ -899,8 +902,8 @@ pub fn get_item_visibility(cdata: cmd, id: ast::node_id)
 
 fn family_has_type_params(fam: Family) -> bool {
     match fam {
-      Const | ForeignType | Mod | ForeignMod | PublicField | PrivateField
-      | ForeignFn => false,
+      ImmStatic | ForeignType | Mod | ForeignMod | PublicField | PrivateField
+      | ForeignFn | MutStatic => false,
       _           => true
     }
 }
@@ -930,7 +933,8 @@ fn describe_def(items: ebml::Doc, id: ast::def_id) -> ~str {
 
 fn item_family_to_str(fam: Family) -> ~str {
     match fam {
-      Const => ~"const",
+      ImmStatic => ~"static",
+      MutStatic => ~"static mut",
       Fn => ~"fn",
       UnsafeFn => ~"unsafe fn",
       PureFn => ~"pure fn",
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 1f2ede670fa..d08342d8687 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -785,7 +785,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
     let must_write =
         match item.node {
           item_enum(_, _) | item_impl(*) | item_trait(*) | item_struct(*) |
-          item_mod(*) | item_foreign_mod(*) | item_const(*) => true,
+          item_mod(*) | item_foreign_mod(*) | item_static(*) => true,
           _ => false
         };
     if !must_write && !reachable(ecx, item.id) { return; }
@@ -800,11 +800,15 @@ fn encode_info_for_item(ecx: &EncodeContext,
            ecx.tcx.sess.codemap.span_to_str(item.span));
 
     match item.node {
-      item_const(_, _) => {
+      item_static(_, m, _) => {
         add_to_index();
         ebml_w.start_tag(tag_items_data_item);
         encode_def_id(ebml_w, local_def(item.id));
-        encode_family(ebml_w, 'c');
+        if m == ast::m_mutbl {
+            encode_family(ebml_w, 'b');
+        } else {
+            encode_family(ebml_w, 'c');
+        }
         encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
         encode_symbol(ecx, ebml_w, item.id);
         encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
@@ -1107,9 +1111,13 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
         }
         encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident));
       }
-      foreign_item_const(*) => {
+      foreign_item_static(_, mutbl) => {
         encode_def_id(ebml_w, local_def(nitem.id));
-        encode_family(ebml_w, 'c');
+        if mutbl {
+            encode_family(ebml_w, 'b');
+        } else {
+            encode_family(ebml_w, 'c');
+        }
         encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
         encode_symbol(ecx, ebml_w, nitem.id);
         encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident));
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 925b1f506d7..5aad0d894da 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -384,7 +384,7 @@ impl tr for ast::def {
           ast::def_self(nid, i) => { ast::def_self(xcx.tr_id(nid), i) }
           ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) }
           ast::def_foreign_mod(did) => { ast::def_foreign_mod(did.tr(xcx)) }
-          ast::def_const(did) => { ast::def_const(did.tr(xcx)) }
+          ast::def_static(did, m) => { ast::def_static(did.tr(xcx), m) }
           ast::def_arg(nid, b) => { ast::def_arg(xcx.tr_id(nid), b) }
           ast::def_local(nid, b) => { ast::def_local(xcx.tr_id(nid), b) }
           ast::def_variant(e_did, v_did) => {
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 126d2db6879..c1906820883 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -43,7 +43,7 @@ pub fn check_item(sess: Session,
                   (_is_const, v): (bool,
                                    visit::vt<bool>)) {
     match it.node {
-      item_const(_, ex) => {
+      item_static(_, _, ex) => {
         (v.visit_expr)(ex, (true, v));
         check_item_recursion(sess, ast_map, def_map, it);
       }
@@ -124,7 +124,7 @@ pub fn check_expr(sess: Session,
                              items without type parameters");
             }
             match def_map.find(&e.id) {
-              Some(&def_const(_)) |
+              Some(&def_static(*)) |
               Some(&def_fn(_, _)) |
               Some(&def_variant(_, _)) |
               Some(&def_struct(_)) => { }
@@ -237,7 +237,7 @@ pub fn check_item_recursion(sess: Session,
         match e.node {
           expr_path(*) => {
             match env.def_map.find(&e.id) {
-              Some(&def_const(def_id)) => {
+              Some(&def_static(def_id, _)) => {
                 if ast_util::is_local(def_id) {
                   match env.ast_map.get_copy(&def_id.node) {
                     ast_map::node_item(it, _) => {
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index a2532405870..b4c8a6b19c2 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -304,7 +304,7 @@ pub fn pat_ctor_id(cx: @MatchCheckCtxt, p: @pat) -> Option<ctor> {
       pat_ident(_, _, _) | pat_enum(_, _) => {
         match cx.tcx.def_map.find(&pat.id) {
           Some(&def_variant(_, id)) => Some(variant(id)),
-          Some(&def_const(did)) => {
+          Some(&def_static(did, false)) => {
             let const_expr = lookup_const_by_id(cx.tcx, did).get();
             Some(val(eval_const_expr(cx.tcx, const_expr)))
           }
@@ -339,7 +339,7 @@ pub fn is_wild(cx: @MatchCheckCtxt, p: @pat) -> bool {
       pat_wild => { true }
       pat_ident(_, _, _) => {
         match cx.tcx.def_map.find(&pat.id) {
-          Some(&def_variant(_, _)) | Some(&def_const(*)) => { false }
+          Some(&def_variant(_, _)) | Some(&def_static(*)) => { false }
           _ => { true }
         }
       }
@@ -499,7 +499,7 @@ pub fn specialize(cx: @MatchCheckCtxt,
                             None
                         }
                     }
-                    Some(&def_const(did)) => {
+                    Some(&def_static(did, _)) => {
                         let const_expr =
                             lookup_const_by_id(cx.tcx, did).get();
                         let e_v = eval_const_expr(cx.tcx, const_expr);
@@ -549,7 +549,7 @@ pub fn specialize(cx: @MatchCheckCtxt,
             }
             pat_enum(_, args) => {
                 match cx.tcx.def_map.get_copy(&pat_id) {
-                    def_const(did) => {
+                    def_static(did, _) => {
                         let const_expr =
                             lookup_const_by_id(cx.tcx, did).get();
                         let e_v = eval_const_expr(cx.tcx, const_expr);
@@ -790,7 +790,7 @@ pub fn is_refutable(cx: @MatchCheckCtxt, pat: &pat) -> bool {
             return true;
         }
       }
-      Some(&def_const(*)) => return true,
+      Some(&def_static(*)) => return true,
       _ => ()
     }
 
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 988ad519f42..1a7cd856bed 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -166,7 +166,7 @@ pub fn classify(e: @expr,
 
 pub fn lookup_const(tcx: ty::ctxt, e: @expr) -> Option<@expr> {
     match tcx.def_map.find(&e.id) {
-        Some(&ast::def_const(def_id)) => lookup_const_by_id(tcx, def_id),
+        Some(&ast::def_static(def_id, false)) => lookup_const_by_id(tcx, def_id),
         _ => None
     }
 }
@@ -178,7 +178,7 @@ pub fn lookup_const_by_id(tcx: ty::ctxt,
         match tcx.items.find(&def_id.node) {
             None => None,
             Some(&ast_map::node_item(it, _)) => match it.node {
-                item_const(_, const_expr) => Some(const_expr),
+                item_static(_, ast::m_imm, const_expr) => Some(const_expr),
                 _ => None
             },
             Some(_) => None
@@ -195,7 +195,7 @@ pub fn lookup_const_by_id(tcx: ty::ctxt,
         match csearch::maybe_get_item_ast(tcx, def_id,
             |a, b, c, d| astencode::decode_inlined_item(a, b, maps, /*bar*/ copy c, d)) {
             csearch::found(ast::ii_item(item)) => match item.node {
-                item_const(_, const_expr) => Some(const_expr),
+                item_static(_, ast::m_imm, const_expr) => Some(const_expr),
                 _ => None
             },
             _ => None
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index d9481c26dad..513b2015a83 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -17,7 +17,7 @@ use middle::typeck::method_map;
 use util::ppaux;
 
 use syntax::ast::{deref, expr_call, expr_inline_asm, expr_method_call};
-use syntax::ast::{expr_unary, node_id, unsafe_blk, unsafe_fn};
+use syntax::ast::{expr_unary, node_id, unsafe_blk, unsafe_fn, expr_path};
 use syntax::ast;
 use syntax::codemap::span;
 use syntax::visit::{fk_item_fn, fk_method};
@@ -143,6 +143,14 @@ pub fn check_crate(tcx: ty::ctxt,
                 expr_inline_asm(*) => {
                     require_unsafe(expr.span, "use of inline assembly")
                 }
+                expr_path(*) => {
+                    match ty::resolve_expr(tcx, expr) {
+                        ast::def_static(_, true) => {
+                            require_unsafe(expr.span, "use of mutable static")
+                        }
+                        _ => {}
+                    }
+                }
                 _ => {}
             }
 
diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs
index 821aed731c2..17ff5930078 100644
--- a/src/librustc/middle/lint.rs
+++ b/src/librustc/middle/lint.rs
@@ -709,28 +709,31 @@ fn check_item_default_methods(cx: &Context, item: @ast::item) {
 }
 
 fn check_item_ctypes(cx: &Context, it: @ast::item) {
+    fn check_ty(cx: &Context, ty: @ast::Ty) {
+        match ty.node {
+            ast::ty_path(_, _, id) => {
+                match cx.tcx.def_map.get_copy(&id) {
+                    ast::def_prim_ty(ast::ty_int(ast::ty_i)) => {
+                        cx.span_lint(ctypes, ty.span,
+                                "found rust type `int` in foreign module, while \
+                                libc::c_int or libc::c_long should be used");
+                    }
+                    ast::def_prim_ty(ast::ty_uint(ast::ty_u)) => {
+                        cx.span_lint(ctypes, ty.span,
+                                "found rust type `uint` in foreign module, while \
+                                libc::c_uint or libc::c_ulong should be used");
+                    }
+                    _ => ()
+                }
+            }
+            _ => ()
+        }
+    }
 
     fn check_foreign_fn(cx: &Context, decl: &ast::fn_decl) {
         let tys = vec::map(decl.inputs, |a| a.ty );
         for vec::each(vec::append_one(tys, decl.output)) |ty| {
-            match ty.node {
-              ast::ty_path(_, _, id) => {
-                match cx.tcx.def_map.get_copy(&id) {
-                  ast::def_prim_ty(ast::ty_int(ast::ty_i)) => {
-                    cx.span_lint(ctypes, ty.span,
-                        "found rust type `int` in foreign module, while \
-                         libc::c_int or libc::c_long should be used");
-                  }
-                  ast::def_prim_ty(ast::ty_uint(ast::ty_u)) => {
-                    cx.span_lint(ctypes, ty.span,
-                        "found rust type `uint` in foreign module, while \
-                         libc::c_uint or libc::c_ulong should be used");
-                  }
-                  _ => ()
-                }
-              }
-              _ => ()
-            }
+            check_ty(cx, *ty);
         }
     }
 
@@ -738,11 +741,10 @@ fn check_item_ctypes(cx: &Context, it: @ast::item) {
       ast::item_foreign_mod(ref nmod) if !nmod.abis.is_intrinsic() => {
         for nmod.items.iter().advance |ni| {
             match ni.node {
-              ast::foreign_item_fn(ref decl, _, _) => {
-                check_foreign_fn(cx, decl);
-              }
-              // FIXME #4622: Not implemented.
-              ast::foreign_item_const(*) => {}
+                ast::foreign_item_fn(ref decl, _, _) => {
+                    check_foreign_fn(cx, decl);
+                }
+                ast::foreign_item_static(t, _) => { check_ty(cx, t); }
             }
         }
       }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 2ced57dc885..f93cb265d78 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -447,19 +447,29 @@ impl mem_categorization_ctxt {
                    -> cmt {
         match def {
           ast::def_fn(*) | ast::def_static_method(*) | ast::def_mod(_) |
-          ast::def_foreign_mod(_) | ast::def_const(_) |
+          ast::def_foreign_mod(_) | ast::def_static(_, false) |
           ast::def_use(_) | ast::def_variant(*) |
           ast::def_trait(_) | ast::def_ty(_) | ast::def_prim_ty(_) |
           ast::def_ty_param(*) | ast::def_struct(*) |
           ast::def_typaram_binder(*) | ast::def_region(_) |
           ast::def_label(_) | ast::def_self_ty(*) => {
-            @cmt_ {
-                id:id,
-                span:span,
-                cat:cat_static_item,
-                mutbl: McImmutable,
-                ty:expr_ty
-            }
+              @cmt_ {
+                  id:id,
+                  span:span,
+                  cat:cat_static_item,
+                  mutbl: McImmutable,
+                  ty:expr_ty
+              }
+          }
+
+          ast::def_static(_, true) => {
+              @cmt_ {
+                  id:id,
+                  span:span,
+                  cat:cat_static_item,
+                  mutbl: McDeclared,
+                  ty:expr_ty
+              }
           }
 
           ast::def_arg(vid, mutbl) => {
@@ -894,7 +904,7 @@ impl mem_categorization_ctxt {
                         self.cat_pattern(cmt_field, subpat, op);
                     }
                 }
-                Some(&ast::def_const(*)) => {
+                Some(&ast::def_static(*)) => {
                     for subpats.iter().advance |&subpat| {
                         self.cat_pattern(cmt, subpat, op);
                     }
diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs
index 1237e9fb4a2..5bd39e85863 100644
--- a/src/librustc/middle/pat_util.rs
+++ b/src/librustc/middle/pat_util.rs
@@ -45,7 +45,7 @@ pub fn pat_is_const(dm: resolve::DefMap, pat: &pat) -> bool {
     match pat.node {
         pat_ident(_, _, None) | pat_enum(*) => {
             match dm.find(&pat.id) {
-                Some(&def_const(*)) => true,
+                Some(&def_static(_, false)) => true,
                 _ => false
             }
         }
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 562bbca6929..a8b837d869d 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -1146,12 +1146,13 @@ impl Resolver {
             }
 
             // These items live in the value namespace.
-            item_const(*) => {
+            item_static(_, m, _) => {
                 let (name_bindings, _) =
                     self.add_child(ident, parent, ForbidDuplicateValues, sp);
+                let mutbl = m == ast::m_mutbl;
 
                 name_bindings.define_value
-                    (privacy, def_const(local_def(item.id)), sp);
+                    (privacy, def_static(local_def(item.id), mutbl), sp);
             }
             item_fn(_, purity, _, _, _) => {
               let (name_bindings, new_parent) =
@@ -1565,8 +1566,8 @@ impl Resolver {
                     visit_foreign_item(foreign_item, (new_parent, visitor));
                 }
             }
-            foreign_item_const(*) => {
-                let def = def_const(local_def(foreign_item.id));
+            foreign_item_static(_, m) => {
+                let def = def_static(local_def(foreign_item.id), m);
                 name_bindings.define_value(Public, def, foreign_item.span);
 
                 visit_foreign_item(foreign_item, (new_parent, visitor));
@@ -1673,7 +1674,7 @@ impl Resolver {
             let privacy = variant_visibility_to_privacy(visibility, true);
             child_name_bindings.define_value(privacy, def, dummy_sp());
           }
-          def_fn(*) | def_static_method(*) | def_const(*) => {
+          def_fn(*) | def_static_method(*) | def_static(*) => {
             debug!("(building reduced graph for external \
                     crate) building value %s", final_ident);
             child_name_bindings.define_value(privacy, def, dummy_sp());
@@ -3664,7 +3665,7 @@ impl Resolver {
                                     || visit_foreign_item(*foreign_item,
                                                           ((), visitor)));
                             }
-                            foreign_item_const(_) => {
+                            foreign_item_static(*) => {
                                 visit_foreign_item(*foreign_item,
                                                    ((), visitor));
                             }
@@ -3686,7 +3687,7 @@ impl Resolver {
                                       visitor);
             }
 
-            item_const(*) => {
+            item_static(*) => {
                 self.with_constant_rib(|| {
                     visit_item(item, ((), visitor));
                 });
@@ -4344,7 +4345,7 @@ impl Resolver {
                                 Some(def @ def_struct(*)) => {
                             self.record_def(pattern.id, def);
                         }
-                        Some(def @ def_const(*)) => {
+                        Some(def @ def_static(*)) => {
                             self.enforce_default_binding_mode(
                                 pattern,
                                 binding_mode,
@@ -4376,7 +4377,7 @@ impl Resolver {
                         Some(def @ def_fn(*))      |
                         Some(def @ def_variant(*)) |
                         Some(def @ def_struct(*))  |
-                        Some(def @ def_const(*)) => {
+                        Some(def @ def_static(*)) => {
                             self.record_def(pattern.id, def);
                         }
                         Some(_) => {
@@ -4459,7 +4460,7 @@ impl Resolver {
                             def @ def_variant(*) | def @ def_struct(*) => {
                                 return FoundStructOrEnumVariant(def);
                             }
-                            def @ def_const(*) => {
+                            def @ def_static(_, false) => {
                                 return FoundConst(def);
                             }
                             _ => {
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index ab2f0c84d02..71b416ffe85 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -820,7 +820,7 @@ pub fn get_options(bcx: block, m: &[@Match], col: uint) -> ~[Opt] {
                         add_to_set(ccx.tcx, &mut found,
                                    lit(UnitLikeStructLit(cur.id)));
                     }
-                    Some(&ast::def_const(const_did)) => {
+                    Some(&ast::def_static(const_did, false)) => {
                         add_to_set(ccx.tcx, &mut found,
                                    lit(ConstLit(const_did)));
                     }
@@ -836,7 +836,7 @@ pub fn get_options(bcx: block, m: &[@Match], col: uint) -> ~[Opt] {
                         add_to_set(ccx.tcx, &mut found,
                                    variant_opt(bcx, cur.id));
                     }
-                    Some(&ast::def_const(const_did)) => {
+                    Some(&ast::def_static(const_did, false)) => {
                         add_to_set(ccx.tcx, &mut found,
                                    lit(ConstLit(const_did)));
                     }
@@ -1831,8 +1831,9 @@ pub fn bind_irrefutable_pat(bcx: block,
                         }
                     }
                 }
-                Some(&ast::def_const(*)) => {
-                    bcx = bind_irrefutable_pat(bcx, pat, val, make_copy, binding_mode);
+                Some(&ast::def_static(_, false)) => {
+                    bcx = bind_irrefutable_pat(bcx, pat, val, make_copy,
+                                               binding_mode);
                 }
                 _ => {
                     // Nothing to do here.
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index ec77fe359b5..0e322c187af 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2122,14 +2122,19 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
             trans_enum_def(ccx, enum_definition, item.id, vi, &mut i);
         }
       }
-      ast::item_const(_, expr) => {
-          consts::trans_const(ccx, expr, item.id);
+      ast::item_static(_, m, expr) => {
+          consts::trans_const(ccx, m, item.id);
           // Do static_assert checking. It can't really be done much earlier because we need to get
           // the value of the bool out of LLVM
           for item.attrs.iter().advance |attr| {
               match attr.node.value.node {
                   ast::meta_word(x) => {
                       if x.slice(0, x.len()) == "static_assert" {
+                          if m == ast::m_mutbl {
+                              ccx.sess.span_fatal(expr.span,
+                                                  "cannot have static_assert \
+                                                   on a mutable static");
+                          }
                           let v = ccx.const_values.get_copy(&item.id);
                           unsafe {
                               if !(llvm::LLVMConstIntGetZExtValue(v) as bool) {
@@ -2398,13 +2403,14 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef {
             let my_path = vec::append(/*bad*/copy *pth,
                                       [path_name(i.ident)]);
             match i.node {
-              ast::item_const(_, expr) => {
+              ast::item_static(_, m, expr) => {
                 let typ = ty::node_id_to_type(ccx.tcx, i.id);
                 let s = mangle_exported_name(ccx, my_path, typ);
                 // We need the translated value here, because for enums the
                 // LLVM type is not fully determined by the Rust type.
                 let v = consts::const_expr(ccx, expr);
                 ccx.const_values.insert(id, v);
+                exprt = m == ast::m_mutbl;
                 unsafe {
                     let llty = llvm::LLVMTypeOf(v);
                     let g = str::as_c_str(s, |buf| {
@@ -2457,7 +2463,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef {
                                 ni.id,
                                 ni.attrs)
                 }
-                ast::foreign_item_const(*) => {
+                ast::foreign_item_static(*) => {
                     let typ = ty::node_id_to_type(ccx.tcx, ni.id);
                     let ident = token::ident_to_str(&ni.ident);
                     let g = do str::as_c_str(ident) |buf| {
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index 6120e1e6581..593d0beb88c 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -143,7 +143,7 @@ pub fn trans(bcx: block, expr: @ast::expr) -> Callee {
                 datum_callee(bcx, ref_expr)
             }
             ast::def_mod(*) | ast::def_foreign_mod(*) | ast::def_trait(*) |
-            ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) |
+            ast::def_static(*) | ast::def_ty(*) | ast::def_prim_ty(*) |
             ast::def_use(*) | ast::def_typaram_binder(*) |
             ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) |
             ast::def_self_ty(*) => {
diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs
index e40534773c2..98eb858be55 100644
--- a/src/librustc/middle/trans/consts.rs
+++ b/src/librustc/middle/trans/consts.rs
@@ -164,9 +164,9 @@ pub fn get_const_val(cx: @mut CrateContext, mut def_id: ast::def_id) -> ValueRef
         }
         match cx.tcx.items.get_copy(&def_id.node) {
             ast_map::node_item(@ast::item {
-                node: ast::item_const(_, subexpr), _
+                node: ast::item_static(_, ast::m_imm, _), _
             }, _) => {
-                trans_const(cx, subexpr, def_id.node);
+                trans_const(cx, ast::m_imm, def_id.node);
             }
             _ => cx.tcx.sess.bug("expected a const to be an item")
         }
@@ -538,7 +538,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: @ast::expr) -> ValueRef {
                         base::get_item_val(cx, def_id.node)
                     }
                 }
-                Some(&ast::def_const(def_id)) => {
+                Some(&ast::def_static(def_id, false)) => {
                     get_const_val(cx, def_id)
                 }
                 Some(&ast::def_variant(enum_did, variant_did)) => {
@@ -587,7 +587,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: @ast::expr) -> ValueRef {
     }
 }
 
-pub fn trans_const(ccx: @mut CrateContext, _e: @ast::expr, id: ast::node_id) {
+pub fn trans_const(ccx: @mut CrateContext, m: ast::mutability, id: ast::node_id) {
     unsafe {
         let _icx = push_ctxt("trans_const");
         let g = base::get_item_val(ccx, id);
@@ -595,6 +595,8 @@ pub fn trans_const(ccx: @mut CrateContext, _e: @ast::expr, id: ast::node_id) {
         // constant's initializer to determine its LLVM type.
         let v = ccx.const_values.get_copy(&id);
         llvm::LLVMSetInitializer(g, v);
-        llvm::LLVMSetGlobalConstant(g, True);
+        if m != ast::m_mutbl {
+            llvm::LLVMSetGlobalConstant(g, True);
+        }
     }
 }
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 7d86f743a8e..1aebf73b81a 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -945,7 +945,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
         let _icx = push_ctxt("trans_def_lvalue");
         let ccx = bcx.ccx();
         match def {
-            ast::def_const(did) => {
+            ast::def_static(did, _) => {
                 let const_ty = expr_ty(bcx, ref_expr);
 
                 fn get_did(ccx: @mut CrateContext, did: ast::def_id)
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 10e63e6af77..54bfc25244f 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -332,7 +332,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
                     }
                 }
             }
-            ast::foreign_item_const(*) => {
+            ast::foreign_item_static(*) => {
                 let ident = token::ident_to_str(&foreign_item.ident);
                 ccx.item_symbols.insert(foreign_item.id, /* bad */ident.to_owned());
             }
diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs
index 6a40c1f75e9..e950c24c49e 100644
--- a/src/librustc/middle/trans/reachable.rs
+++ b/src/librustc/middle/trans/reachable.rs
@@ -146,7 +146,7 @@ fn traverse_public_item(cx: @mut ctx, item: @item) {
                         visit::mk_vt(@visit::Visitor {visit_ty: traverse_ty,
                                                       ..*visit::default_visitor()})))
       }
-      item_const(*) |
+      item_static(*) |
       item_enum(*) | item_trait(*) => (),
       item_mac(*) => fail!("item macros unimplemented")
     }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 632874025e7..bc163f4a725 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3269,7 +3269,7 @@ pub fn expr_kind(tcx: ctxt,
                 // Note: there is actually a good case to be made that
                 // def_args, particularly those of immediate type, ought to
                 // considered rvalues.
-                ast::def_const(*) |
+                ast::def_static(*) |
                 ast::def_binding(*) |
                 ast::def_upvar(*) |
                 ast::def_arg(*) |
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 76b7e651ff1..1c032466ca6 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -585,7 +585,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
     let _indenter = indenter();
 
     match it.node {
-      ast::item_const(_, e) => check_const(ccx, it.span, e, it.id),
+      ast::item_static(_, _, e) => check_const(ccx, it.span, e, it.id),
       ast::item_enum(ref enum_definition, _) => {
         check_enum_variants(ccx,
                             it.span,
@@ -3216,7 +3216,7 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt,
       }
 
       ast::def_fn(id, _) | ast::def_static_method(id, _, _) |
-      ast::def_const(id) | ast::def_variant(_, id) |
+      ast::def_static(id, _) | ast::def_variant(_, id) |
       ast::def_struct(id) => {
         return ty::lookup_item_type(fcx.ccx.tcx, id);
       }
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index 7f820d11ac6..33e483e552a 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -1060,7 +1060,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item)
     }
     let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x);
     match it.node {
-      ast::item_const(t, _) => {
+      ast::item_static(t, _, _) => {
         let typ = ccx.to_ty(&empty_rscope, t);
         let tpt = no_params(typ);
         tcx.tcache.insert(local_def(it.id), tpt);
@@ -1153,7 +1153,7 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt,
                                   generics,
                                   abis)
         }
-        ast::foreign_item_const(t) => {
+        ast::foreign_item_static(t, _) => {
             ty::ty_param_bounds_and_ty {
                 generics: ty::Generics {
                     type_param_defs: @~[],
diff --git a/src/librustdoc/extract.rs b/src/librustdoc/extract.rs
index b6131dce9c8..b7b2b70769b 100644
--- a/src/librustdoc/extract.rs
+++ b/src/librustdoc/extract.rs
@@ -102,7 +102,7 @@ fn moddoc_from_mod(
                     fndoc_from_fn(ItemDoc)
                 ))
               }
-              ast::item_const(_, _) => {
+              ast::item_static(*) => {
                 Some(doc::ConstTag(
                     constdoc_from_const(ItemDoc)
                 ))
@@ -150,7 +150,7 @@ fn nmoddoc_from_mod(
           ast::foreign_item_fn(*) => {
             fns.push(fndoc_from_fn(ItemDoc));
           }
-          ast::foreign_item_const(*) => {} // XXX: Not implemented.
+          ast::foreign_item_static(*) => {} // XXX: Not implemented.
         }
     }
     doc::NmodDoc {
diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs
index e3abe6e926a..459daaa468f 100644
--- a/src/librustdoc/tystr_pass.rs
+++ b/src/librustdoc/tystr_pass.rs
@@ -96,7 +96,7 @@ fn fold_const(
             do astsrv::exec(srv) |ctxt| {
                 match ctxt.ast_map.get_copy(&doc.id()) {
                     ast_map::node_item(@ast::item {
-                        node: ast::item_const(ty, _), _
+                        node: ast::item_static(ty, _, _), _
                     }, _) => {
                         pprust::ty_to_str(ty, extract::interner())
                     }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 2e3d557daa9..c7f3b41475f 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -190,7 +190,7 @@ pub enum def {
     def_self_ty(/* trait id */ node_id),
     def_mod(def_id),
     def_foreign_mod(def_id),
-    def_const(def_id),
+    def_static(def_id, bool /* is_mutbl */),
     def_arg(node_id, bool /* is_mutbl */),
     def_local(node_id, bool /* is_mutbl */),
     def_variant(def_id /* enum */, def_id /* variant */),
@@ -1095,7 +1095,7 @@ pub struct item {
 
 #[deriving(Eq, Encodable, Decodable)]
 pub enum item_ {
-    item_const(@Ty, @expr),
+    item_static(@Ty, mutability, @expr),
     item_fn(fn_decl, purity, AbiSet, Generics, blk),
     item_mod(_mod),
     item_foreign_mod(foreign_mod),
@@ -1124,7 +1124,7 @@ pub struct foreign_item {
 #[deriving(Eq, Encodable, Decodable)]
 pub enum foreign_item_ {
     foreign_item_fn(fn_decl, purity, Generics),
-    foreign_item_const(@Ty)
+    foreign_item_static(@Ty, /* is_mutbl */ bool),
 }
 
 // The data we save and restore about an inlined item or method.  This is not
diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs
index a0e1ec69350..421c4c566b5 100644
--- a/src/libsyntax/ast_map.rs
+++ b/src/libsyntax/ast_map.rs
@@ -339,7 +339,7 @@ pub fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str {
       Some(&node_item(item, path)) => {
         let path_str = path_ident_to_str(path, item.ident, itr);
         let item_str = match item.node {
-          item_const(*) => ~"const",
+          item_static(*) => ~"static",
           item_fn(*) => ~"fn",
           item_mod(*) => ~"mod",
           item_foreign_mod(*) => ~"foreign mod",
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 24cf5662a36..227d700452b 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -59,7 +59,7 @@ pub fn variant_def_ids(d: def) -> Option<(def_id, def_id)> {
 pub fn def_id_of_def(d: def) -> def_id {
     match d {
       def_fn(id, _) | def_static_method(id, _, _) | def_mod(id) |
-      def_foreign_mod(id) | def_const(id) |
+      def_foreign_mod(id) | def_static(id, _) |
       def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
       def_use(id) | def_struct(id) | def_trait(id) => {
         id
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 4bd2c0a3de1..25839fb4633 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -236,8 +236,8 @@ fn noop_fold_foreign_item(ni: @foreign_item, fld: @ast_fold)
                         purity,
                         fold_generics(generics, fld))
                 }
-                foreign_item_const(t) => {
-                    foreign_item_const(fld.fold_ty(t))
+                foreign_item_static(t, m) => {
+                    foreign_item_static(fld.fold_ty(t), m)
                 }
             },
         id: fld.new_id(ni.id),
@@ -270,7 +270,7 @@ fn noop_fold_struct_field(sf: @struct_field, fld: @ast_fold)
 
 pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ {
     match *i {
-        item_const(t, e) => item_const(fld.fold_ty(t), fld.fold_expr(e)),
+        item_static(t, m, e) => item_static(fld.fold_ty(t), m, fld.fold_expr(e)),
         item_fn(ref decl, purity, abi, ref generics, ref body) => {
             item_fn(
                 fold_fn_decl(decl, fld),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c9ef1a7a33c..d8aab1f68ee 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -33,8 +33,8 @@ use ast::{expr_vec, expr_vstore, expr_vstore_mut_box};
 use ast::{expr_vstore_slice, expr_vstore_box};
 use ast::{expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl};
 use ast::{expr_vstore_uniq, Onceness, Once, Many};
-use ast::{foreign_item, foreign_item_const, foreign_item_fn, foreign_mod};
-use ast::{ident, impure_fn, inherited, item, item_, item_const};
+use ast::{foreign_item, foreign_item_static, foreign_item_fn, foreign_mod};
+use ast::{ident, impure_fn, inherited, item, item_, item_static};
 use ast::{item_enum, item_fn, item_foreign_mod, item_impl};
 use ast::{item_mac, item_mod, item_struct, item_trait, item_ty, lit, lit_};
 use ast::{lit_bool, lit_float, lit_float_unsuffixed, lit_int};
@@ -3556,13 +3556,14 @@ impl Parser {
     }
 
     fn parse_item_const(&self) -> item_info {
+        let m = if self.eat_keyword(keywords::Mut) {m_mutbl} else {m_imm};
         let id = self.parse_ident();
         self.expect(&token::COLON);
         let ty = self.parse_ty(false);
         self.expect(&token::EQ);
         let e = self.parse_expr();
         self.expect(&token::SEMI);
-        (id, item_const(ty, e), None)
+        (id, item_static(ty, m, e), None)
     }
 
     // parse a mod { ...}  item
@@ -3683,6 +3684,7 @@ impl Parser {
         } else {
             self.expect_keyword(keywords::Static);
         }
+        let mutbl = self.eat_keyword(keywords::Mut);
 
         let ident = self.parse_ident();
         self.expect(&token::COLON);
@@ -3691,7 +3693,7 @@ impl Parser {
         self.expect(&token::SEMI);
         @ast::foreign_item { ident: ident,
                              attrs: attrs,
-                             node: foreign_item_const(ty),
+                             node: foreign_item_static(ty, mutbl),
                              id: self.get_id(),
                              span: mk_sp(lo, hi),
                              vis: vis }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index fa22b7ceb71..1a3155337a5 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -458,8 +458,11 @@ pub fn print_foreign_item(s: @ps, item: @ast::foreign_item) {
         word(s.s, ";");
         end(s); // end the outer fn box
       }
-      ast::foreign_item_const(t) => {
+      ast::foreign_item_static(t, m) => {
         head(s, "static");
+        if m {
+            word_space(s, "mut");
+        }
         print_ident(s, item.ident);
         word_space(s, ":");
         print_type(s, t);
@@ -477,8 +480,11 @@ pub fn print_item(s: @ps, item: @ast::item) {
     let ann_node = node_item(s, item);
     (s.ann.pre)(ann_node);
     match item.node {
-      ast::item_const(ty, expr) => {
+      ast::item_static(ty, m, expr) => {
         head(s, visibility_qualified(item.vis, "static"));
+        if m == ast::m_mutbl {
+            word_space(s, "mut");
+        }
         print_ident(s, item.ident);
         word_space(s, ":");
         print_type(s, ty);
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 5aa38c0348c..d7914832835 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -148,7 +148,7 @@ fn visit_trait_ref<E: Copy>(tref: @ast::trait_ref, (e, v): (E, vt<E>)) {
 
 pub fn visit_item<E: Copy>(i: @item, (e, v): (E, vt<E>)) {
     match i.node {
-        item_const(t, ex) => {
+        item_static(t, _, ex) => {
             (v.visit_ty)(t, (copy e, v));
             (v.visit_expr)(ex, (copy e, v));
         }
@@ -326,7 +326,7 @@ pub fn visit_foreign_item<E: Copy>(ni: @foreign_item, (e, v): (E, vt<E>)) {
             visit_fn_decl(fd, (copy e, v));
             (v.visit_generics)(generics, (e, v));
         }
-        foreign_item_const(t) => {
+        foreign_item_static(t, _) => {
             (v.visit_ty)(t, (e, v));
         }
     }
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index e476fa0ad5e..6ae5e978106 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -154,6 +154,16 @@ debug_abi_2(floats f) {
     return ff;
 }
 
+extern "C" int
+debug_static_mut;
+
+int debug_static_mut = 3;
+
+extern "C" void
+debug_static_mut_check_four() {
+    assert(debug_static_mut == 4);
+}
+
 /* Debug builtins for std::dbg. */
 
 static void
diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in
index ba7ada04a27..505de6e20b7 100644
--- a/src/rt/rustrt.def.in
+++ b/src/rt/rustrt.def.in
@@ -7,6 +7,8 @@ debug_tydesc
 debug_get_stk_seg
 debug_abi_1
 debug_abi_2
+debug_static_mut
+debug_static_mut_check_four
 get_task_id
 get_time
 rust_tzset
@@ -239,4 +241,4 @@ rust_valgrind_stack_deregister
 rust_take_env_lock
 rust_drop_env_lock
 rust_update_log_settings
-rust_running_on_valgrind
\ No newline at end of file
+rust_running_on_valgrind
diff --git a/src/test/auxiliary/static_mut_xc.rs b/src/test/auxiliary/static_mut_xc.rs
new file mode 100644
index 00000000000..8dc45c681bf
--- /dev/null
+++ b/src/test/auxiliary/static_mut_xc.rs
@@ -0,0 +1 @@
+pub static mut a: int = 3;
diff --git a/src/test/compile-fail/static-mut-bad-types.rs b/src/test/compile-fail/static-mut-bad-types.rs
new file mode 100644
index 00000000000..7aed3ce30bc
--- /dev/null
+++ b/src/test/compile-fail/static-mut-bad-types.rs
@@ -0,0 +1,17 @@
+// 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.
+
+static mut a: int = 3;
+
+fn main() {
+    unsafe {
+        a = true; //~ ERROR: mismatched types
+    }
+}
diff --git a/src/test/compile-fail/static-mut-foreign-requires-unsafe.rs b/src/test/compile-fail/static-mut-foreign-requires-unsafe.rs
new file mode 100644
index 00000000000..7b371cf708d
--- /dev/null
+++ b/src/test/compile-fail/static-mut-foreign-requires-unsafe.rs
@@ -0,0 +1,21 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::libc;
+
+extern {
+    static mut a: libc::c_int;
+}
+
+fn main() {
+    a += 3;     //~ ERROR: requires unsafe
+    a = 4;      //~ ERROR: requires unsafe
+    let _b = a; //~ ERROR: requires unsafe
+}
diff --git a/src/test/compile-fail/static-mut-not-constant.rs b/src/test/compile-fail/static-mut-not-constant.rs
new file mode 100644
index 00000000000..61d3ed7fd18
--- /dev/null
+++ b/src/test/compile-fail/static-mut-not-constant.rs
@@ -0,0 +1,13 @@
+// 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.
+
+static mut a: ~int = ~3; //~ ERROR: disallowed operator in constant
+
+fn main() {}
diff --git a/src/test/compile-fail/static-mut-not-pat.rs b/src/test/compile-fail/static-mut-not-pat.rs
new file mode 100644
index 00000000000..997003a28d4
--- /dev/null
+++ b/src/test/compile-fail/static-mut-not-pat.rs
@@ -0,0 +1,26 @@
+// 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.
+
+// Constants (static variables) can be used to match in patterns, but mutable
+// statics cannot. This ensures that there's some form of error if this is
+// attempted.
+
+static mut a: int = 3;
+
+fn main() {
+    // If they can't be matched against, then it's possible to capture the same
+    // name as a variable, hence this should be an unreachable pattern situation
+    // instead of spitting out a custom error about some identifier collisions
+    // (we should allow shadowing)
+    match 4 {
+        a => {}
+        _ => {} //~ ERROR: unreachable pattern
+    }
+}
diff --git a/src/test/compile-fail/static-mut-requires-unsafe.rs b/src/test/compile-fail/static-mut-requires-unsafe.rs
new file mode 100644
index 00000000000..7337920cce6
--- /dev/null
+++ b/src/test/compile-fail/static-mut-requires-unsafe.rs
@@ -0,0 +1,17 @@
+// 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.
+
+static mut a: int = 3;
+
+fn main() {
+    a += 3;         //~ ERROR: requires unsafe
+    a = 4;          //~ ERROR: requires unsafe
+    let _b = a;     //~ ERROR: requires unsafe
+}
diff --git a/src/test/run-pass/static-mut-foreign.rs b/src/test/run-pass/static-mut-foreign.rs
new file mode 100644
index 00000000000..7af143a1529
--- /dev/null
+++ b/src/test/run-pass/static-mut-foreign.rs
@@ -0,0 +1,46 @@
+// 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.
+
+// Constants (static variables) can be used to match in patterns, but mutable
+// statics cannot. This ensures that there's some form of error if this is
+// attempted.
+
+use std::libc;
+
+#[nolink]
+extern {
+    static mut debug_static_mut: libc::c_int;
+    pub fn debug_static_mut_check_four();
+}
+
+unsafe fn static_bound(_: &'static libc::c_int) {}
+
+fn static_bound_set(a: &'static mut libc::c_int) {
+    *a = 3;
+}
+
+unsafe fn run() {
+    assert!(debug_static_mut == 3);
+    debug_static_mut = 4;
+    assert!(debug_static_mut == 4);
+    debug_static_mut_check_four();
+    debug_static_mut += 1;
+    assert!(debug_static_mut == 5);
+    debug_static_mut *= 3;
+    assert!(debug_static_mut == 15);
+    debug_static_mut = -3;
+    assert!(debug_static_mut == -3);
+    static_bound(&debug_static_mut);
+    static_bound_set(&mut debug_static_mut);
+}
+
+pub fn main() {
+    unsafe { run() }
+}
diff --git a/src/test/run-pass/static-mut-xc.rs b/src/test/run-pass/static-mut-xc.rs
new file mode 100644
index 00000000000..ab6bdc20c49
--- /dev/null
+++ b/src/test/run-pass/static-mut-xc.rs
@@ -0,0 +1,46 @@
+// 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.
+
+// Constants (static variables) can be used to match in patterns, but mutable
+// statics cannot. This ensures that there's some form of error if this is
+// attempted.
+
+// xfail-fast
+// aux-build:static_mut_xc.rs
+
+extern mod static_mut_xc;
+
+unsafe fn static_bound(_: &'static int) {}
+
+fn static_bound_set(a: &'static mut int) {
+    *a = 3;
+}
+
+unsafe fn run() {
+    assert!(static_mut_xc::a == 3);
+    static_mut_xc::a = 4;
+    assert!(static_mut_xc::a == 4);
+    static_mut_xc::a += 1;
+    assert!(static_mut_xc::a == 5);
+    static_mut_xc::a *= 3;
+    assert!(static_mut_xc::a == 15);
+    static_mut_xc::a = -3;
+    assert!(static_mut_xc::a == -3);
+    static_bound(&static_mut_xc::a);
+    static_bound_set(&mut static_mut_xc::a);
+}
+
+pub fn main() {
+    unsafe { run() }
+}
+
+pub mod inner {
+    pub static mut a: int = 4;
+}