about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Schneider <github35764891676564198441@oli-obk.de>2018-05-20 02:19:20 +0200
committerOliver Schneider <github35764891676564198441@oli-obk.de>2018-05-24 17:22:31 +0200
commit383a5df58cf29e640b1b77da301825a5abc86ce7 (patch)
tree3bfd03735629fcfa9ec5db5dea4e27fcdcf2f2cc
parentd022dd48cceaceffa931f87490c7921aa3c3f8b1 (diff)
downloadrust-383a5df58cf29e640b1b77da301825a5abc86ce7.tar.gz
rust-383a5df58cf29e640b1b77da301825a5abc86ce7.zip
Enforce stability of const fn in promoteds
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs33
-rw-r--r--src/librustc_passes/rvalue_promotion.rs28
-rw-r--r--src/test/ui/const-eval/dont_promote_unstable_const_fn.nll.stderr21
-rw-r--r--src/test/ui/const-eval/dont_promote_unstable_const_fn.rs34
-rw-r--r--src/test/ui/const-eval/dont_promote_unstable_const_fn.stderr32
5 files changed, 131 insertions, 17 deletions
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 999e3d89fc7..83c0d257999 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -279,7 +279,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
             if let Place::Local(index) = *dest {
                 if self.mir.local_kind(index) == LocalKind::Temp
                 && self.temp_promotion_state[index].is_promotable() {
-                    debug!("store to promotable temp {:?}", index);
+                    debug!("store to promotable temp {:?} ({:?})", index, qualif);
                     store(&mut self.local_qualif[index]);
                 }
             }
@@ -969,10 +969,7 @@ This does not pose a problem by itself because they can't be accessed directly."
                         feature: ref feature_name
                     }),
                 .. }) = self.tcx.lookup_stability(def_id) {
-
-                    // We are in a const or static initializer,
-                    if self.mode != Mode::Fn &&
-
+                    if
                         // feature-gate is not enabled,
                         !self.tcx.features()
                             .declared_lib_features
@@ -985,14 +982,24 @@ This does not pose a problem by itself because they can't be accessed directly."
                         // this doesn't come from a macro that has #[allow_internal_unstable]
                         !self.span.allows_unstable()
                     {
-                        let mut err = self.tcx.sess.struct_span_err(self.span,
-                            &format!("`{}` is not yet stable as a const fn",
-                                     self.tcx.item_path_str(def_id)));
-                        help!(&mut err,
-                              "in Nightly builds, add `#![feature({})]` \
-                               to the crate attributes to enable",
-                              feature_name);
-                        err.emit();
+                        if self.mode == Mode::Fn {
+                            // We are in a normal function
+                            // with a turned off feature gate. We can still call the function
+                            // but we can't promote it
+                            self.qualif = Qualif::NOT_CONST;
+                            debug!("unstable const fn");
+                        } else {
+                            // inside a constant environment, not having the feature gate is
+                            // an error
+                            let mut err = self.tcx.sess.struct_span_err(self.span,
+                                &format!("`{}` is not yet stable as a const fn",
+                                        self.tcx.item_path_str(def_id)));
+                            help!(&mut err,
+                                "in Nightly builds, add `#![feature({})]` \
+                                to the crate attributes to enable",
+                                feature_name);
+                            err.emit();
+                        }
                     }
                 }
             } else {
diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs
index 2e737a016da..52ceb3ff595 100644
--- a/src/librustc_passes/rvalue_promotion.rs
+++ b/src/librustc_passes/rvalue_promotion.rs
@@ -38,6 +38,7 @@ use rustc::util::nodemap::{ItemLocalSet, NodeSet};
 use rustc::hir;
 use rustc_data_structures::sync::Lrc;
 use syntax::ast;
+use syntax::attr;
 use syntax_pos::{Span, DUMMY_SP};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 
@@ -119,7 +120,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
         !ty.needs_drop(self.tcx, self.param_env)
     }
 
-    fn handle_const_fn_call(&mut self, def_id: DefId, ret_ty: Ty<'gcx>) {
+    fn handle_const_fn_call(&mut self, def_id: DefId, ret_ty: Ty<'gcx>, span: Span) {
         self.promotable &= self.type_has_only_promotable_values(ret_ty);
 
         self.promotable &= if let Some(fn_id) = self.tcx.hir.as_local_node_id(def_id) {
@@ -129,6 +130,25 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
         } else {
             self.tcx.is_const_fn(def_id)
         };
+
+        if let Some(&attr::Stability {
+            rustc_const_unstable: Some(attr::RustcConstUnstable {
+                feature: ref feature_name
+            }),
+        .. }) = self.tcx.lookup_stability(def_id) {
+            self.promotable &=
+                // feature-gate is enabled,
+                self.tcx.features()
+                    .declared_lib_features
+                    .iter()
+                    .any(|&(ref sym, _)| sym == feature_name) ||
+
+                // this comes from a crate with the feature-gate enabled,
+                !def_id.is_local() ||
+
+                // this comes from a macro that has #[allow_internal_unstable]
+                span.allows_unstable();
+        }
     }
 }
 
@@ -359,12 +379,12 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
                 Def::StructCtor(_, CtorKind::Fn) |
                 Def::VariantCtor(_, CtorKind::Fn) => {}
                 Def::Fn(did) => {
-                    v.handle_const_fn_call(did, node_ty)
+                    v.handle_const_fn_call(did, node_ty, e.span)
                 }
                 Def::Method(did) => {
                     match v.tcx.associated_item(did).container {
                         ty::ImplContainer(_) => {
-                            v.handle_const_fn_call(did, node_ty)
+                            v.handle_const_fn_call(did, node_ty, e.span)
                         }
                         ty::TraitContainer(_) => v.promotable = false
                     }
@@ -376,7 +396,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             if let Some(def) = v.tables.type_dependent_defs().get(e.hir_id) {
                 let def_id = def.def_id();
                 match v.tcx.associated_item(def_id).container {
-                    ty::ImplContainer(_) => v.handle_const_fn_call(def_id, node_ty),
+                    ty::ImplContainer(_) => v.handle_const_fn_call(def_id, node_ty, e.span),
                     ty::TraitContainer(_) => v.promotable = false
                 }
             } else {
diff --git a/src/test/ui/const-eval/dont_promote_unstable_const_fn.nll.stderr b/src/test/ui/const-eval/dont_promote_unstable_const_fn.nll.stderr
new file mode 100644
index 00000000000..684fa1c997b
--- /dev/null
+++ b/src/test/ui/const-eval/dont_promote_unstable_const_fn.nll.stderr
@@ -0,0 +1,21 @@
+error: `foo` is not yet stable as a const fn
+  --> $DIR/dont_promote_unstable_const_fn.rs:25:25
+   |
+LL | const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn
+   |                         ^^^^^
+   |
+   = help: in Nightly builds, add `#![feature(foo)]` to the crate attributes to enable
+
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/dont_promote_unstable_const_fn.rs:33:26
+   |
+LL |     let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+LL | }
+   | - temporary value only lives until here
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/const-eval/dont_promote_unstable_const_fn.rs b/src/test/ui/const-eval/dont_promote_unstable_const_fn.rs
new file mode 100644
index 00000000000..a590e569947
--- /dev/null
+++ b/src/test/ui/const-eval/dont_promote_unstable_const_fn.rs
@@ -0,0 +1,34 @@
+// 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.
+
+#![unstable(feature = "humans",
+            reason = "who ever let humans program computers,
+            we're apparently really bad at it",
+            issue = "0")]
+
+#![feature(rustc_const_unstable, const_fn)]
+#![feature(staged_api)]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo")]
+const fn foo() -> u32 { 42 }
+
+fn meh() -> u32 { 42 }
+
+const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn
+
+fn a() {
+    let _: &'static u32 = &foo(); //~ ERROR does not live long enough
+}
+
+fn main() {
+    let _: &'static u32 = &meh(); //~ ERROR does not live long enough
+    let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
+}
diff --git a/src/test/ui/const-eval/dont_promote_unstable_const_fn.stderr b/src/test/ui/const-eval/dont_promote_unstable_const_fn.stderr
new file mode 100644
index 00000000000..7963cbb4e45
--- /dev/null
+++ b/src/test/ui/const-eval/dont_promote_unstable_const_fn.stderr
@@ -0,0 +1,32 @@
+error: `foo` is not yet stable as a const fn
+  --> $DIR/dont_promote_unstable_const_fn.rs:25:25
+   |
+LL | const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn
+   |                         ^^^^^
+   |
+   = help: in Nightly builds, add `#![feature(foo)]` to the crate attributes to enable
+
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/dont_promote_unstable_const_fn.rs:28:28
+   |
+LL |     let _: &'static u32 = &foo(); //~ ERROR does not live long enough
+   |                            ^^^^^ temporary value does not live long enough
+LL | }
+   | - temporary value only lives until here
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/dont_promote_unstable_const_fn.rs:32:28
+   |
+LL |     let _: &'static u32 = &meh(); //~ ERROR does not live long enough
+   |                            ^^^^^ temporary value does not live long enough
+LL |     let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
+LL | }
+   | - temporary value only lives until here
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.