about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs23
-rw-r--r--src/test/run-pass/issue-44373.rs2
2 files changed, 18 insertions, 7 deletions
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index b9b86dd6e84..2b2323928ef 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -41,6 +41,9 @@ use transform::{MirPass, MirSource};
 use super::promote_consts::{self, Candidate, TempState};
 
 bitflags! {
+    // Borrows of temporaries can be promoted only if
+    // they have none of these qualifications, with
+    // the exception of `STATIC_REF` (in statics only).
     struct Qualif: u8 {
         // Constant containing interior mutability (UnsafeCell).
         const MUTABLE_INTERIOR  = 1 << 0;
@@ -65,10 +68,6 @@ bitflags! {
         // promote_consts decided they weren't simple enough.
         const NOT_PROMOTABLE    = 1 << 6;
 
-        // Borrows of temporaries can be promoted only
-        // if they have none of the above qualifications.
-        const NEVER_PROMOTE     = 0b111_1111;
-
         // Const items can only have MUTABLE_INTERIOR
         // and NOT_PROMOTABLE without producing an error.
         const CONST_ERROR       = !Qualif::MUTABLE_INTERIOR.bits &
@@ -197,7 +196,17 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
         self.add(original);
     }
 
-    /// Check if an Place with the current qualifications could
+    /// Check if a Local with the current qualifications is promotable.
+    fn can_promote(&mut self) -> bool {
+        // References to statics are allowed, but only in other statics.
+        if self.mode == Mode::Static || self.mode == Mode::StaticMut {
+            (self.qualif - Qualif::STATIC_REF).is_empty()
+        } else {
+            self.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 {
@@ -633,7 +642,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
 
                 // We might have a candidate for promotion.
                 let candidate = Candidate::Ref(location);
-                if !self.qualif.intersects(Qualif::NEVER_PROMOTE) {
+                if self.can_promote() {
                     // We can only promote direct borrows of temps.
                     if let Place::Local(local) = *place {
                         if self.mir.local_kind(local) == LocalKind::Temp {
@@ -745,7 +754,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                     this.visit_operand(arg, location);
                     if is_shuffle && i == 2 && this.mode == Mode::Fn {
                         let candidate = Candidate::ShuffleIndices(bb);
-                        if !this.qualif.intersects(Qualif::NEVER_PROMOTE) {
+                        if this.can_promote() {
                             this.promotion_candidates.push(candidate);
                         } else {
                             span_err!(this.tcx.sess, this.span, E0526,
diff --git a/src/test/run-pass/issue-44373.rs b/src/test/run-pass/issue-44373.rs
index 06627e2ad93..d0f8ed96f4c 100644
--- a/src/test/run-pass/issue-44373.rs
+++ b/src/test/run-pass/issue-44373.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// compile-flags: -Z borrowck=compare
+
 struct Foo(bool);
 
 struct Container(&'static [&'static Foo]);