about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2020-10-04 15:25:26 +0200
committerRalf Jung <post@ralfj.de>2020-10-04 15:25:26 +0200
commitd727f642b939305ed7a68e5f74875d4d52304ebf (patch)
tree53571ec26c04025e65a94e8433b8a4f282b9184b
parent0d37dca25a51fb900a402c94c8818ad1c2789e30 (diff)
downloadrust-d727f642b939305ed7a68e5f74875d4d52304ebf.tar.gz
rust-d727f642b939305ed7a68e5f74875d4d52304ebf.zip
stop promoting union field accesses in 'const'
-rw-r--r--compiler/rustc_mir/src/transform/promote_consts.rs34
-rw-r--r--src/test/ui/consts/promote-not.rs5
-rw-r--r--src/test/ui/consts/promote-not.stderr12
3 files changed, 30 insertions, 21 deletions
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index 89f7531b3a7..32c18c80b24 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -294,17 +294,6 @@ impl std::ops::Deref for Validator<'a, 'tcx> {
 struct Unpromotable;
 
 impl<'tcx> Validator<'_, 'tcx> {
-    /// Determines if this code could be executed at runtime and thus is subject to codegen.
-    /// That means even unused constants need to be evaluated.
-    ///
-    /// `const_kind` should not be used in this file other than through this method!
-    fn maybe_runtime(&self) -> bool {
-        match self.const_kind {
-            None | Some(hir::ConstContext::ConstFn) => true,
-            Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => false,
-        }
-    }
-
     fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
         match candidate {
             Candidate::Ref(loc) => {
@@ -555,14 +544,12 @@ impl<'tcx> Validator<'_, 'tcx> {
                     }
 
                     ProjectionElem::Field(..) => {
-                        if self.maybe_runtime() {
-                            let base_ty =
-                                Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
-                            if let Some(def) = base_ty.ty_adt_def() {
-                                // No promotion of union field accesses.
-                                if def.is_union() {
-                                    return Err(Unpromotable);
-                                }
+                        let base_ty =
+                            Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
+                        if let Some(def) = base_ty.ty_adt_def() {
+                            // No promotion of union field accesses.
+                            if def.is_union() {
+                                return Err(Unpromotable);
                             }
                         }
                     }
@@ -744,7 +731,14 @@ impl<'tcx> Validator<'_, 'tcx> {
     ) -> Result<(), Unpromotable> {
         let fn_ty = callee.ty(self.body, self.tcx);
 
-        if !self.explicit && self.maybe_runtime() {
+        // When doing explicit promotion and inside const/static items, we promote all (eligible) function calls.
+        // Everywhere else, we require `#[rustc_promotable]` on the callee.
+        let promote_all_const_fn = self.explicit
+            || matches!(
+                self.const_kind,
+                Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
+            );
+        if !promote_all_const_fn {
             if let ty::FnDef(def_id, _) = *fn_ty.kind() {
                 // Never promote runtime `const fn` calls of
                 // functions without `#[rustc_promotable]`.
diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs
index 8daac758377..30bb9917bf7 100644
--- a/src/test/ui/consts/promote-not.rs
+++ b/src/test/ui/consts/promote-not.rs
@@ -27,4 +27,9 @@ pub const fn promote_union() {
     let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed
 }
 
+// We do not promote union field accesses in `const`, either.
+const TEST_UNION: () = {
+    let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed
+};
+
 fn main() {}
diff --git a/src/test/ui/consts/promote-not.stderr b/src/test/ui/consts/promote-not.stderr
index efe921b6011..6ca7a4c273e 100644
--- a/src/test/ui/consts/promote-not.stderr
+++ b/src/test/ui/consts/promote-not.stderr
@@ -38,6 +38,16 @@ LL |     let _x: &'static i32 = &unsafe { U { x: 0 }.x };
 LL | }
    | - temporary value is freed at the end of this statement
 
-error: aborting due to 4 previous errors
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promote-not.rs:32:29
+   |
+LL |     let _x: &'static i32 = &unsafe { U { x: 0 }.x };
+   |             ------------    ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |             |
+   |             type annotation requires that borrow lasts for `'static`
+LL | };
+   | - temporary value is freed at the end of this statement
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0716`.