about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-07-01 23:00:27 +0000
committerbors <bors@rust-lang.org>2018-07-01 23:00:27 +0000
commitc697a56d01c650f65b4ca4a264db1ea3573d0565 (patch)
treee5e43f3bc9c0e880853ec6c6ab1639b35eba2896 /src
parenta7a60dc7f8e9a53feb70ee7aa05485345a045afb (diff)
parent1c342270424058847b3e348dea4038ff42ab75eb (diff)
downloadrust-c697a56d01c650f65b4ca4a264db1ea3573d0565.tar.gz
rust-c697a56d01c650f65b4ca4a264db1ea3573d0565.zip
Auto merge of #51110 - alexreg:new-static-eval-rules, r=eddyb
Loosened rules involving statics mentioning other statics

Before this PR, trying to mention a static in any way other than taking a reference to it caused a compile-time error. So, while

```rust
static A: u32 = 42;
static B: &u32 = &A;
```

compiles successfully,

```rust
static A: u32 = 42;
static B: u32 = A; // error
```

and

```rust
static A: u32 = 42;
static B: u32 = *&A; // error
```

are not possible to express in Rust. On the other hand, introducing an intermediate `const fn` can presently allow one to do just that:

```rust
static A: u32 = 42;
static B: u32 = foo(&A); // success!

const fn foo(a: &u32) -> u32 {
    *a
}
```

Preventing `const fn` from allowing to work around the ban on reading from statics would cripple `const fn` almost into uselessness.
Additionally, the limitation for reading from statics comes from the old const evaluator(s) and is not shared by `miri`.

This PR loosens the rules around use of statics to allow statics to evaluate other statics by value, allowing all of the above examples to compile and run successfully.
Reads from extern (foreign) statics are however still disallowed by miri, because there is no compile-time value to be read.

```rust
extern static A: u32;

static B: u32 = A; // error
```

This opens up a new avenue of potential issues, as a static can now not just refer to other statics or read from other statics, but even contain references that point into itself.
While it might seem like this could cause subtle bugs like allowing a static to be initialized by its own value, this is inherently impossible in miri.
Reading from a static causes the `const_eval` query for that static to be invoked. Calling the `const_eval` query for a static while already inside the `const_eval` query of said static will cause cycle errors.
It is not possible to accidentally create a bug in miri that would enable initializing a static with itself, because the memory of the static *does not exist* while being initialized.
The memory is not uninitialized, it is not there. Thus any change that would accidentally allow reading from a not yet initialized static would cause ICEs.

Tests have been modified according to the new rules, and new tests have been added for writing to `static mut`s within definitions of statics (which needs to fail), and incremental compilation with complex/interlinking static definitions.
Note that incremental compilation did not need to be adjusted, because all of this was already possible before with workarounds (like intermediate `const fn`s) and the encoding/decoding already supports all the possible cases.

r? @eddyb
Diffstat (limited to 'src')
-rw-r--r--src/librustc/ich/impls_ty.rs1
-rw-r--r--src/librustc/mir/interpret/error.rs3
-rw-r--r--src/librustc/ty/structural_impls.rs1
-rw-r--r--src/librustc_mir/diagnostics.rs55
-rw-r--r--src/librustc_mir/interpret/const_eval.rs4
-rw-r--r--src/librustc_mir/interpret/memory.rs6
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs146
-rw-r--r--src/test/compile-fail/const-fn-not-safe-for-const.rs4
-rw-r--r--src/test/compile-fail/issue-14227.rs6
-rw-r--r--src/test/compile-fail/issue-16538.rs1
-rw-r--r--src/test/compile-fail/issue-17718-references.rs7
-rw-r--r--src/test/compile-fail/issue-28324.rs5
-rw-r--r--src/test/compile-fail/recursive-static-definition.rs (renamed from src/test/ui/error-codes/E0494.rs)13
-rw-r--r--src/test/compile-fail/thread-local-in-ctfe.rs3
-rw-r--r--src/test/compile-fail/write-to-static-mut-in-static.rs22
-rw-r--r--src/test/incremental/static_refering_to_other_static3/issue.rs25
-rw-r--r--src/test/run-pass/auxiliary/pub_static_array.rs (renamed from src/test/compile-fail/auxiliary/pub_static_array.rs)0
-rw-r--r--src/test/run-pass/issue-17450.rs (renamed from src/test/compile-fail/issue-17450.rs)5
-rw-r--r--src/test/run-pass/issue-17718-borrow-interior.rs (renamed from src/test/compile-fail/issue-17718-borrow-interior.rs)16
-rw-r--r--src/test/run-pass/issue-34194.rs (renamed from src/test/compile-fail/issue-34194.rs)1
-rw-r--r--src/test/run-pass/issue-6991.rs (renamed from src/test/compile-fail/issue-6991.rs)3
-rw-r--r--src/test/run-pass/refer-to-other-statics-by-value.rs (renamed from src/test/ui/error-codes/E0394.rs)10
-rw-r--r--src/test/run-pass/static-array-across-crate.rs (renamed from src/test/compile-fail/static-array-across-crate.rs)6
-rw-r--r--src/test/ui/error-codes/E0394.stderr11
-rw-r--r--src/test/ui/error-codes/E0494.stderr9
25 files changed, 127 insertions, 236 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 8391cc6d9ba..5753557a102 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -521,6 +521,7 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
             InvalidNullPointerUsage |
             ReadPointerAsBytes |
             ReadBytesAsPointer |
+            ReadForeignStatic |
             InvalidPointerMath |
             ReadUndefBytes |
             DeadLocal |
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 86427bb2382..7e2c144e0a7 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -188,6 +188,7 @@ pub enum EvalErrorKind<'tcx, O> {
     InvalidNullPointerUsage,
     ReadPointerAsBytes,
     ReadBytesAsPointer,
+    ReadForeignStatic,
     InvalidPointerMath,
     ReadUndefBytes,
     DeadLocal,
@@ -304,6 +305,8 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
                 "a raw memory access tried to access part of a pointer value as raw bytes",
             ReadBytesAsPointer =>
                 "a memory access tried to interpret some bytes as a pointer",
+            ReadForeignStatic =>
+                "tried to read from foreign (extern) static",
             InvalidPointerMath =>
                 "attempted to do invalid arithmetic on pointers that would leak base addresses, e.g. comparing pointers into different allocations",
             ReadUndefBytes =>
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index a648dc6e7e7..c84999a7e59 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -506,6 +506,7 @@ impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> {
             InvalidNullPointerUsage => InvalidNullPointerUsage,
             ReadPointerAsBytes => ReadPointerAsBytes,
             ReadBytesAsPointer => ReadBytesAsPointer,
+            ReadForeignStatic => ReadForeignStatic,
             InvalidPointerMath => InvalidPointerMath,
             ReadUndefBytes => ReadUndefBytes,
             DeadLocal => DeadLocal,
diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs
index c2da1bee395..3c751d52b06 100644
--- a/src/librustc_mir/diagnostics.rs
+++ b/src/librustc_mir/diagnostics.rs
@@ -1145,33 +1145,6 @@ fn main() {
 ```
 "##,
 
-E0394: r##"
-A static was referred to by value by another static.
-
-Erroneous code examples:
-
-```compile_fail,E0394
-static A: u32 = 0;
-static B: u32 = A; // error: cannot refer to other statics by value, use the
-                   //        address-of operator or a constant instead
-```
-
-A static cannot be referred by value. To fix this issue, either use a
-constant:
-
-```
-const A: u32 = 0; // `A` is now a constant
-static B: u32 = A; // ok!
-```
-
-Or refer to `A` by reference:
-
-```
-static A: u32 = 0;
-static B: &'static u32 = &A; // ok!
-```
-"##,
-
 E0395: r##"
 The value assigned to a constant scalar must be known at compile time,
 which is not the case when comparing raw pointers.
@@ -1333,34 +1306,6 @@ Remember this solution is unsafe! You will have to ensure that accesses to the
 cell are synchronized.
 "##,
 
-E0494: r##"
-A reference of an interior static was assigned to another const/static.
-Erroneous code example:
-
-```compile_fail,E0494
-struct Foo {
-    a: u32
-}
-
-static S : Foo = Foo { a : 0 };
-static A : &'static u32 = &S.a;
-// error: cannot refer to the interior of another static, use a
-//        constant instead
-```
-
-The "base" variable has to be a const if you want another static/const variable
-to refer to one of its fields. Example:
-
-```
-struct Foo {
-    a: u32
-}
-
-const S : Foo = Foo { a : 0 };
-static A : &'static u32 = &S.a; // ok!
-```
-"##,
-
 E0499: r##"
 A variable was borrowed as mutable more than once. Erroneous code example:
 
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index 35422b11bd7..749c0d04ae9 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/interpret/const_eval.rs
@@ -374,7 +374,7 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
             Ok(None)
         } else {
             Err(
-                ConstEvalError::NeedsRfc("Pointer arithmetic or comparison".to_string()).into(),
+                ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
             )
         }
     }
@@ -404,7 +404,7 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
         _dest: Place,
     ) -> EvalResult<'tcx> {
         Err(
-            ConstEvalError::NeedsRfc("Heap allocations via `box` keyword".to_string()).into(),
+            ConstEvalError::NeedsRfc("heap allocations via `box` keyword".to_string()).into(),
         )
     }
 
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 3cd492c50ee..f5da65ae44d 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -279,6 +279,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 /// Allocation accessors
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     fn const_eval_static(&self, def_id: DefId) -> EvalResult<'tcx, &'tcx Allocation> {
+        if self.tcx.is_foreign_item(def_id) {
+            return err!(ReadForeignStatic);
+        }
         let instance = Instance::mono(self.tcx.tcx, def_id);
         let gid = GlobalId {
             instance,
@@ -302,7 +305,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
                 Some(alloc) => Ok(alloc),
                 None => {
                     // static alloc?
-                    match self.tcx.alloc_map.lock().get(id) {
+                    let alloc = self.tcx.alloc_map.lock().get(id);
+                    match alloc {
                         Some(AllocType::Memory(mem)) => Ok(mem),
                         Some(AllocType::Function(..)) => {
                             Err(EvalErrorKind::DerefFunctionPointer.into())
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 144ebce76e1..986957d5a82 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -56,19 +56,13 @@ bitflags! {
         // Function argument.
         const FN_ARGUMENT       = 1 << 2;
 
-        // Static place or move from a static.
-        const STATIC            = 1 << 3;
-
-        // Reference to a static.
-        const STATIC_REF        = 1 << 4;
-
         // Not constant at all - non-`const fn` calls, asm!,
         // pointer comparisons, ptr-to-int casts, etc.
-        const NOT_CONST         = 1 << 5;
+        const NOT_CONST         = 1 << 3;
 
         // Refers to temporaries which cannot be promoted as
         // promote_consts decided they weren't simple enough.
-        const NOT_PROMOTABLE    = 1 << 6;
+        const NOT_PROMOTABLE    = 1 << 4;
 
         // Const items can only have MUTABLE_INTERIOR
         // and NOT_PROMOTABLE without producing an error.
@@ -226,42 +220,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
         self.add(original);
     }
 
-    /// Check if a Local with the current qualifications is promotable.
-    fn can_promote(&self, qualif: Qualif) -> bool {
-        // References to statics are allowed, but only in other statics.
-        if self.mode == Mode::Static || self.mode == Mode::StaticMut {
-            (qualif - Qualif::STATIC_REF).is_empty()
-        } else {
-            qualif.is_empty()
-        }
-    }
-
-    /// Check if a Place with the current qualifications could
-    /// be consumed, by either an operand or a Deref projection.
-    fn try_consume(&mut self) -> bool {
-        if self.qualif.intersects(Qualif::STATIC) && self.mode != Mode::Fn {
-            let msg = if self.mode == Mode::Static ||
-                         self.mode == Mode::StaticMut {
-                "cannot refer to other statics by value, use the \
-                 address-of operator or a constant instead"
-            } else {
-                "cannot refer to statics by value, use a constant instead"
-            };
-            struct_span_err!(self.tcx.sess, self.span, E0394, "{}", msg)
-                .span_label(self.span, "referring to another static by value")
-                .note("use the address-of operator or a constant instead")
-                .emit();
-
-            // Replace STATIC with NOT_CONST to avoid further errors.
-            self.qualif = self.qualif - Qualif::STATIC;
-            self.add(Qualif::NOT_CONST);
-
-            false
-        } else {
-            true
-        }
-    }
-
     /// Assign the current qualification to the given destination.
     fn assign(&mut self, dest: &Place<'tcx>, location: Location) {
         trace!("assign: {:?}", dest);
@@ -305,7 +263,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
             }) if self.mir.local_kind(index) == LocalKind::Temp
                && self.mir.local_decls[index].ty.is_box()
                && self.local_qualif[index].map_or(false, |qualif| {
-                    qualif.intersects(Qualif::NOT_CONST)
+                    qualif.contains(Qualif::NOT_CONST)
                }) => {
                 // Part of `box expr`, we should've errored
                 // already for the Box allocation Rvalue.
@@ -492,21 +450,26 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
         match *place {
             Place::Local(ref local) => self.visit_local(local, context, location),
             Place::Static(ref global) => {
-                self.add(Qualif::STATIC);
-
-                if self.mode != Mode::Fn {
-                    for attr in &self.tcx.get_attrs(global.def_id)[..] {
-                        if attr.check_name("thread_local") {
-                            span_err!(self.tcx.sess, self.span, E0625,
-                                      "thread-local statics cannot be \
-                                       accessed at compile-time");
-                            self.add(Qualif::NOT_CONST);
-                            return;
-                        }
+                if self.tcx
+                       .get_attrs(global.def_id)
+                       .iter()
+                       .any(|attr| attr.check_name("thread_local")) {
+                    if self.mode != Mode::Fn {
+                        span_err!(self.tcx.sess, self.span, E0625,
+                                  "thread-local statics cannot be \
+                                   accessed at compile-time");
                     }
+                    self.add(Qualif::NOT_CONST);
+                    return;
+                }
+
+                // Only allow statics (not consts) to refer to other statics.
+                if self.mode == Mode::Static || self.mode == Mode::StaticMut {
+                    return;
                 }
+                self.add(Qualif::NOT_CONST);
 
-                if self.mode == Mode::Const || self.mode == Mode::ConstFn {
+                if self.mode != Mode::Fn {
                     let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
                                                    "{}s cannot refer to statics, use \
                                                     a constant instead", self.mode);
@@ -527,15 +490,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     this.super_place(place, context, location);
                     match proj.elem {
                         ProjectionElem::Deref => {
-                            if !this.try_consume() {
-                                return;
-                            }
-
-                            if this.qualif.intersects(Qualif::STATIC_REF) {
-                                this.qualif = this.qualif - Qualif::STATIC_REF;
-                                this.add(Qualif::STATIC);
-                            }
-
                             this.add(Qualif::NOT_CONST);
 
                             let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
@@ -573,11 +527,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                                         this.not_const();
                                     }
                                 }
-                            } else if this.qualif.intersects(Qualif::STATIC) {
-                                span_err!(this.tcx.sess, this.span, E0494,
-                                          "cannot refer to the interior of another \
-                                           static, use a constant instead");
                             }
+
                             let ty = place.ty(this.mir, this.tcx).to_ty(this.tcx);
                             this.qualif.restrict(ty, this.tcx, this.param_env);
                         }
@@ -594,14 +545,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
     }
 
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
+        self.super_operand(operand, location);
+
         match *operand {
             Operand::Copy(_) |
             Operand::Move(_) => {
-                self.nest(|this| {
-                    this.super_operand(operand, location);
-                    this.try_consume();
-                });
-
                 // Mark the consumed locals to indicate later drops are noops.
                 if let Operand::Move(Place::Local(local)) = *operand {
                     self.local_qualif[local] = self.local_qualif[local].map(|q|
@@ -646,20 +594,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
             }
 
             if is_reborrow {
-                self.nest(|this| {
-                    this.super_place(place, PlaceContext::Borrow {
-                        region,
-                        kind
-                    }, location);
-                    if !this.try_consume() {
-                        return;
-                    }
-
-                    if this.qualif.intersects(Qualif::STATIC_REF) {
-                        this.qualif = this.qualif - Qualif::STATIC_REF;
-                        this.add(Qualif::STATIC);
-                    }
-                });
+                self.super_place(place, PlaceContext::Borrow {
+                    region,
+                    kind
+                }, location);
             } else {
                 self.super_rvalue(rvalue, location);
             }
@@ -678,22 +616,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
             Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
             Rvalue::Cast(CastKind::ClosureFnPointer, ..) |
             Rvalue::Cast(CastKind::Unsize, ..) |
-            Rvalue::Discriminant(..) => {}
-
-            Rvalue::Len(_) => {
-                // Static places in consts would have errored already,
-                // don't treat length checks as reads from statics.
-                self.qualif = self.qualif - Qualif::STATIC;
-            }
+            Rvalue::Discriminant(..) |
+            Rvalue::Len(_) => {}
 
             Rvalue::Ref(_, kind, ref place) => {
-                // Static places in consts would have errored already,
-                // only keep track of references to them here.
-                if self.qualif.intersects(Qualif::STATIC) {
-                    self.qualif = self.qualif - Qualif::STATIC;
-                    self.add(Qualif::STATIC_REF);
-                }
-
                 let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
 
                 // Default to forbidding the borrow and/or its promotion,
@@ -744,7 +670,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     // Constants cannot be borrowed if they contain interior mutability as
                     // it means that our "silent insertion of statics" could change
                     // initializer values (very bad).
-                    if self.qualif.intersects(Qualif::MUTABLE_INTERIOR) {
+                    if self.qualif.contains(Qualif::MUTABLE_INTERIOR) {
                         // A reference of a MUTABLE_INTERIOR place is instead
                         // NOT_CONST (see `if forbidden_mut` below), to avoid
                         // duplicate errors (from reborrowing, for example).
@@ -781,7 +707,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                                 // This allows borrowing fields which don't have
                                 // `MUTABLE_INTERIOR`, from a type that does, e.g.:
                                 // `let _: &'static _ = &(Cell::new(1), 2).1;`
-                                if self.can_promote(qualif - Qualif::MUTABLE_INTERIOR) {
+                                if (qualif - Qualif::MUTABLE_INTERIOR).is_empty() {
                                     self.promotion_candidates.push(candidate);
                                 }
                             }
@@ -889,7 +815,7 @@ This does not pose a problem by itself because they can't be accessed directly."
                     if Some(def.did) == self.tcx.lang_items().unsafe_cell_type() {
                         let ty = rvalue.ty(self.mir, self.tcx);
                         self.add_type(ty);
-                        assert!(self.qualif.intersects(Qualif::MUTABLE_INTERIOR));
+                        assert!(self.qualif.contains(Qualif::MUTABLE_INTERIOR));
                     }
                 }
             }
@@ -949,7 +875,7 @@ This does not pose a problem by itself because they can't be accessed directly."
                     }
                     let candidate = Candidate::Argument { bb, index: i };
                     if is_shuffle && i == 2 {
-                        if this.can_promote(this.qualif) {
+                        if this.qualif.is_empty() {
                             this.promotion_candidates.push(candidate);
                         } else {
                             span_err!(this.tcx.sess, this.span, E0526,
@@ -965,7 +891,7 @@ This does not pose a problem by itself because they can't be accessed directly."
                     if !constant_arguments.contains(&i) {
                         return
                     }
-                    if this.can_promote(this.qualif) {
+                    if this.qualif.is_empty() {
                         this.promotion_candidates.push(candidate);
                     } else {
                         this.tcx.sess.span_err(this.span,
@@ -1059,7 +985,7 @@ This does not pose a problem by itself because they can't be accessed directly."
                 // HACK(eddyb) Emulate a bit of dataflow analysis,
                 // conservatively, that drop elaboration will do.
                 let needs_drop = if let Place::Local(local) = *place {
-                    if self.local_qualif[local].map_or(true, |q| q.intersects(Qualif::NEEDS_DROP)) {
+                    if self.local_qualif[local].map_or(true, |q| q.contains(Qualif::NEEDS_DROP)) {
                         Some(self.mir.local_decls[local].source_info.span)
                     } else {
                         None
@@ -1111,7 +1037,7 @@ This does not pose a problem by itself because they can't be accessed directly."
                 }
 
                 // Avoid a generic error for other uses of arguments.
-                if self.qualif.intersects(Qualif::FN_ARGUMENT) {
+                if self.qualif.contains(Qualif::FN_ARGUMENT) {
                     let decl = &self.mir.local_decls[index];
                     let mut err = feature_err(
                         &self.tcx.sess.parse_sess,
diff --git a/src/test/compile-fail/const-fn-not-safe-for-const.rs b/src/test/compile-fail/const-fn-not-safe-for-const.rs
index d985bae1f24..341cc7bb491 100644
--- a/src/test/compile-fail/const-fn-not-safe-for-const.rs
+++ b/src/test/compile-fail/const-fn-not-safe-for-const.rs
@@ -29,7 +29,6 @@ static Y: u32 = 0;
 const fn get_Y() -> u32 {
     Y
         //~^ ERROR E0013
-        //~| ERROR cannot refer to statics by value
 }
 
 const fn get_Y_addr() -> &'static u32 {
@@ -49,5 +48,4 @@ const fn get() -> u32 {
     //~| ERROR let bindings in constant functions are unstable
 }
 
-fn main() {
-}
+fn main() {}
diff --git a/src/test/compile-fail/issue-14227.rs b/src/test/compile-fail/issue-14227.rs
index d8f9f5543e4..95f017061a2 100644
--- a/src/test/compile-fail/issue-14227.rs
+++ b/src/test/compile-fail/issue-14227.rs
@@ -13,6 +13,10 @@
 extern {
     pub static symbol: ();
 }
-static CRASH: () = symbol; //~ cannot refer to other statics by value
+static CRASH: () = symbol;
+//~^ ERROR could not evaluate static initializer
+//~| tried to read from foreign (extern) static
+//~^^^ ERROR could not evaluate static initializer
+//~| tried to read from foreign (extern) static
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-16538.rs b/src/test/compile-fail/issue-16538.rs
index 7df445c676c..cc652119377 100644
--- a/src/test/compile-fail/issue-16538.rs
+++ b/src/test/compile-fail/issue-16538.rs
@@ -22,7 +22,6 @@ mod Y {
 
 static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
 //~^ ERROR `*const usize` cannot be shared between threads safely [E0277]
-//~| ERROR cannot refer to other statics by value, use the address-of operator or a constant instead
 //~| ERROR E0015
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-17718-references.rs b/src/test/compile-fail/issue-17718-references.rs
index 8e0df283cdb..586cfebcd16 100644
--- a/src/test/compile-fail/issue-17718-references.rs
+++ b/src/test/compile-fail/issue-17718-references.rs
@@ -22,14 +22,13 @@ static T4: &'static usize = &S;
 
 const T5: usize = C;
 const T6: usize = S; //~ ERROR: constants cannot refer to statics
-//~^ cannot refer to statics
 static T7: usize = C;
-static T8: usize = S; //~ ERROR: cannot refer to other statics by value
+static T8: usize = S;
 
 const T9: Struct = Struct { a: C };
-const T10: Struct = Struct { a: S }; //~ ERROR: cannot refer to statics by value
+const T10: Struct = Struct { a: S };
 //~^ ERROR: constants cannot refer to statics
 static T11: Struct = Struct { a: C };
-static T12: Struct = Struct { a: S }; //~ ERROR: cannot refer to other statics by value
+static T12: Struct = Struct { a: S };
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-28324.rs b/src/test/compile-fail/issue-28324.rs
index 3c4d6b42b50..8512238dd31 100644
--- a/src/test/compile-fail/issue-28324.rs
+++ b/src/test/compile-fail/issue-28324.rs
@@ -15,6 +15,9 @@ extern {
 }
 
 pub static BAZ: u32 = *&error_message_count;
-//~^ ERROR cannot refer to other statics by value
+//~^ ERROR could not evaluate static initializer
+//~| tried to read from foreign (extern) static
+//~^^^ ERROR could not evaluate static initializer
+//~| tried to read from foreign (extern) static
 
 fn main() {}
diff --git a/src/test/ui/error-codes/E0494.rs b/src/test/compile-fail/recursive-static-definition.rs
index 5f8632ac1c2..62c1859e09d 100644
--- a/src/test/ui/error-codes/E0494.rs
+++ b/src/test/compile-fail/recursive-static-definition.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,12 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-struct Foo {
-    a: u32
-}
+pub static FOO: u32 = FOO;
+//~^ ERROR cycle detected when const-evaluating `FOO`
 
-static S : Foo = Foo { a : 0 };
-static A : &'static u32 = &S.a; //~ ERROR E0494
-
-fn main() {
-}
+fn main() {}
diff --git a/src/test/compile-fail/thread-local-in-ctfe.rs b/src/test/compile-fail/thread-local-in-ctfe.rs
index dc220bd1cc9..62e26f28b06 100644
--- a/src/test/compile-fail/thread-local-in-ctfe.rs
+++ b/src/test/compile-fail/thread-local-in-ctfe.rs
@@ -15,14 +15,12 @@ static A: u32 = 1;
 
 static B: u32 = A;
 //~^ ERROR thread-local statics cannot be accessed at compile-time
-//~| ERROR cannot refer to other statics by value
 
 static C: &u32 = &A;
 //~^ ERROR thread-local statics cannot be accessed at compile-time
 
 const D: u32 = A;
 //~^ ERROR thread-local statics cannot be accessed at compile-time
-//~| ERROR cannot refer to statics by value
 
 const E: &u32 = &A;
 //~^ ERROR thread-local statics cannot be accessed at compile-time
@@ -30,7 +28,6 @@ const E: &u32 = &A;
 const fn f() -> u32 {
     A
     //~^ ERROR thread-local statics cannot be accessed at compile-time
-    //~| ERROR cannot refer to statics by value
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/write-to-static-mut-in-static.rs b/src/test/compile-fail/write-to-static-mut-in-static.rs
new file mode 100644
index 00000000000..1ea74f73723
--- /dev/null
+++ b/src/test/compile-fail/write-to-static-mut-in-static.rs
@@ -0,0 +1,22 @@
+// Copyright 2018 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.
+
+#![feature(const_let)]
+
+pub static mut A: u32 = 0;
+pub static mut B: () = unsafe { A = 1; };
+//~^ ERROR statements in statics are unstable
+
+pub static mut C: u32 = unsafe { C = 1; 0 };
+//~^ ERROR statements in statics are unstable
+
+pub static D: u32 = D;
+
+fn main() {}
diff --git a/src/test/incremental/static_refering_to_other_static3/issue.rs b/src/test/incremental/static_refering_to_other_static3/issue.rs
new file mode 100644
index 00000000000..f19ae9e0e8d
--- /dev/null
+++ b/src/test/incremental/static_refering_to_other_static3/issue.rs
@@ -0,0 +1,25 @@
+// Copyright 2018 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.
+
+// revisions:rpass1 rpass2
+
+#[cfg(rpass1)]
+pub static A: u8 = 42;
+#[cfg(rpass2)]
+pub static A: u8 = 43;
+
+static B: &u8 = &C.1;
+static C: (&&u8, u8) = (&B, A);
+
+fn main() {
+    assert_eq!(*B, A);
+    assert_eq!(**C.0, A);
+    assert_eq!(C.1, A);
+}
diff --git a/src/test/compile-fail/auxiliary/pub_static_array.rs b/src/test/run-pass/auxiliary/pub_static_array.rs
index 7248d0e543b..7248d0e543b 100644
--- a/src/test/compile-fail/auxiliary/pub_static_array.rs
+++ b/src/test/run-pass/auxiliary/pub_static_array.rs
diff --git a/src/test/compile-fail/issue-17450.rs b/src/test/run-pass/issue-17450.rs
index cde1bbbe492..242d8c20cd7 100644
--- a/src/test/compile-fail/issue-17450.rs
+++ b/src/test/run-pass/issue-17450.rs
@@ -11,9 +11,6 @@
 #![allow(dead_code, warnings)]
 
 static mut x: isize = 3;
-static mut y: isize = unsafe {
-    x
-//~^ ERROR cannot refer to other statics by value, use the address-of operator or a constant instea
-};
+static mut y: isize = unsafe { x };
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-17718-borrow-interior.rs b/src/test/run-pass/issue-17718-borrow-interior.rs
index 31352c57f1b..cafc0375257 100644
--- a/src/test/compile-fail/issue-17718-borrow-interior.rs
+++ b/src/test/run-pass/issue-17718-borrow-interior.rs
@@ -9,17 +9,19 @@
 // except according to those terms.
 
 struct S { a: usize }
-static A: S  = S { a: 3 };
+
+static A: S = S { a: 3 };
 static B: &'static usize = &A.a;
-//~^ ERROR: cannot refer to the interior of another static
 static C: &'static usize = &(A.a);
-//~^ ERROR: cannot refer to the interior of another static
 
 static D: [usize; 1] = [1];
 static E: usize = D[0];
-//~^ ERROR: cannot refer to the interior of another static
-//~^^ ERROR: cannot refer to other statics by value
 static F: &'static usize = &D[0];
-//~^ ERROR: cannot refer to the interior of another static
 
-fn main() {}
+fn main() {
+    assert_eq!(*B, A.a);
+    assert_eq!(*B, A.a);
+
+    assert_eq!(E, D[0]);
+    assert_eq!(*F, D[0]);
+}
diff --git a/src/test/compile-fail/issue-34194.rs b/src/test/run-pass/issue-34194.rs
index dd607ebad62..e1aef899619 100644
--- a/src/test/compile-fail/issue-34194.rs
+++ b/src/test/run-pass/issue-34194.rs
@@ -16,6 +16,5 @@ struct A {
 
 static B: &'static A = &A { a: &() };
 static C: &'static A = &B;
-//~^ ERROR cannot refer to other statics by value
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-6991.rs b/src/test/run-pass/issue-6991.rs
index 0cc5898adfc..32a9a055d49 100644
--- a/src/test/compile-fail/issue-6991.rs
+++ b/src/test/run-pass/issue-6991.rs
@@ -10,6 +10,5 @@
 
 static x: &'static usize = &1;
 static y: usize = *x;
-//~^ ERROR cannot refer to other statics by value,
-//         use the address-of operator or a constant instead
+
 fn main() {}
diff --git a/src/test/ui/error-codes/E0394.rs b/src/test/run-pass/refer-to-other-statics-by-value.rs
index dae8e14c5ef..94c98ff95ab 100644
--- a/src/test/ui/error-codes/E0394.rs
+++ b/src/test/run-pass/refer-to-other-statics-by-value.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,11 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(warnings)]
-
-static A: u32 = 0;
-static B: u32 = A;
-//~^ ERROR E0394
+static A: usize = 42;
+static B: usize = A;
 
 fn main() {
+    assert_eq!(B, 42);
 }
diff --git a/src/test/compile-fail/static-array-across-crate.rs b/src/test/run-pass/static-array-across-crate.rs
index d101432f6d1..732d94cee8e 100644
--- a/src/test/compile-fail/static-array-across-crate.rs
+++ b/src/test/run-pass/static-array-across-crate.rs
@@ -15,13 +15,7 @@ extern crate pub_static_array as array;
 use array::ARRAY;
 
 static X: &'static u8 = &ARRAY[0];
-//~^ ERROR: cannot refer to the interior of another static, use a constant
-
 static Y: &'static u8 = &(&ARRAY)[0];
-//~^ ERROR: cannot refer to the interior of another static, use a constant
-
 static Z: u8 = (&ARRAY)[0];
-//~^ ERROR: cannot refer to the interior of another static, use a constant
-//~^^ ERROR: cannot refer to other statics by value
 
 pub fn main() {}
diff --git a/src/test/ui/error-codes/E0394.stderr b/src/test/ui/error-codes/E0394.stderr
deleted file mode 100644
index 6c89957de07..00000000000
--- a/src/test/ui/error-codes/E0394.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0394]: cannot refer to other statics by value, use the address-of operator or a constant instead
-  --> $DIR/E0394.rs:14:17
-   |
-LL | static B: u32 = A;
-   |                 ^ referring to another static by value
-   |
-   = note: use the address-of operator or a constant instead
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0394`.
diff --git a/src/test/ui/error-codes/E0494.stderr b/src/test/ui/error-codes/E0494.stderr
deleted file mode 100644
index 65e6b1fe670..00000000000
--- a/src/test/ui/error-codes/E0494.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0494]: cannot refer to the interior of another static, use a constant instead
-  --> $DIR/E0494.rs:16:27
-   |
-LL | static A : &'static u32 = &S.a; //~ ERROR E0494
-   |                           ^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0494`.