]> git.lizzy.rs Git - rust.git/commitdiff
rustc_mir: allow promotion of promotable temps indexed at runtime.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Thu, 10 May 2018 10:11:36 +0000 (13:11 +0300)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Wed, 16 May 2018 12:40:54 +0000 (15:40 +0300)
src/librustc_mir/transform/qualify_consts.rs
src/test/mir-opt/match_false_edges.rs
src/test/run-pass/issue-49955-2.rs [new file with mode: 0644]
src/test/run-pass/issue-49955.rs

index 6f90794ed896bc30e9f6e4c48ec56896dbf390ac..fd4ba1d75625a0787bd097f28f9d57fa31a818d5 100644 (file)
@@ -229,12 +229,12 @@ fn nest<F: FnOnce(&mut Self)>(&mut self, f: F) {
     }
 
     /// Check if a Local with the current qualifications is promotable.
-    fn can_promote(&mut self) -> bool {
+    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 {
-            (self.qualif - Qualif::STATIC_REF).is_empty()
+            (qualif - Qualif::STATIC_REF).is_empty()
         } else {
-            self.qualif.is_empty()
+            qualif.is_empty()
         }
     }
 
@@ -746,10 +746,10 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
 
                 if forbidden_mut {
                     self.add(Qualif::NOT_CONST);
-                } else if self.can_promote() {
+                } else {
                     // We might have a candidate for promotion.
                     let candidate = Candidate::Ref(location);
-                    // We can only promote interior borrows of non-drop temps.
+                    // We can only promote interior borrows of promotable temps.
                     let mut place = place;
                     while let Place::Projection(ref proj) = *place {
                         if proj.elem == ProjectionElem::Deref {
@@ -760,7 +760,12 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                     if let Place::Local(local) = *place {
                         if self.mir.local_kind(local) == LocalKind::Temp {
                             if let Some(qualif) = self.temp_qualif[local] {
-                                if !qualif.intersects(Qualif::NEEDS_DROP) {
+                                // `forbidden_mut` is false, so we can safely ignore
+                                // `MUTABLE_INTERIOR` from the local's qualifications.
+                                // 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) {
                                     self.promotion_candidates.push(candidate);
                                 }
                             }
@@ -920,7 +925,7 @@ fn visit_terminator_kind(&mut self,
                     }
                     let candidate = Candidate::Argument { bb, index: i };
                     if is_shuffle && i == 2 {
-                        if this.can_promote() {
+                        if this.can_promote(this.qualif) {
                             this.promotion_candidates.push(candidate);
                         } else {
                             span_err!(this.tcx.sess, this.span, E0526,
@@ -936,7 +941,7 @@ fn visit_terminator_kind(&mut self,
                     if !constant_arguments.contains(&i) {
                         return
                     }
-                    if this.can_promote() {
+                    if this.can_promote(this.qualif) {
                         this.promotion_candidates.push(candidate);
                     } else {
                         this.tcx.sess.span_err(this.span,
index a31298a0f516007fcd8790a10d9539627b5b91af..c2a40399efe3d5718f5e3604a13a04ad56d724fb 100644 (file)
@@ -88,7 +88,8 @@ fn main() {
 //  }
 //  bb9: { // binding1 and guard
 //      StorageLive(_5);
-//      _5 = &((_2 as Some).0: i32);
+//      _11 = promoted[0];
+//      _5 = &(((*_11) as Some).0: i32);
 //      StorageLive(_8);
 //      _8 = const guard() -> [return: bb10, unwind: bb1];
 //  }
diff --git a/src/test/run-pass/issue-49955-2.rs b/src/test/run-pass/issue-49955-2.rs
new file mode 100644 (file)
index 0000000..17e1de9
--- /dev/null
@@ -0,0 +1,26 @@
+// 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.
+
+// compile-flags: -Z borrowck=mir
+
+use std::cell::Cell;
+
+#[inline(never)]
+fn tuple_field() -> &'static u32 {
+    // This test is MIR-borrowck-only because the old borrowck
+    // doesn't agree that borrows of "frozen" (i.e. without any
+    // interior mutability) fields of non-frozen temporaries,
+    // should be promoted, while MIR promotion does promote them.
+    &(Cell::new(5), 42).1
+}
+
+fn main() {
+    assert_eq!(tuple_field().to_string(), "42");
+}
index 2d36806ef4f44a5cec3ede0aec2c813516ea3c9c..57a1264aaee8033f6f504e52c4ee98c1389794d2 100644 (file)
@@ -26,5 +26,5 @@ fn tuple_field() -> &'static u32 {
 
 fn main() {
     assert_eq!(tuple_field().to_string(), "42");
-    // assert_eq!(array(0).to_string(), "1");
+    assert_eq!(array(0).to_string(), "1");
 }