Skip to content

Commit

Permalink
Enforce stability of const fn in promoteds
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed May 20, 2018
1 parent 1b240da commit 0a94f78
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 17 deletions.
33 changes: 20 additions & 13 deletions src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,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.temp_qualif[index]);
}
}
Expand Down Expand Up @@ -959,10 +959,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
Expand All @@ -975,14 +972,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 {
Expand Down
28 changes: 24 additions & 4 deletions src/librustc_passes/rvalue_promotion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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) {
Expand All @@ -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();
}
}
}

Expand Down Expand Up @@ -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
}
Expand All @@ -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 {
Expand Down
21 changes: 21 additions & 0 deletions src/test/ui/const-eval/dont_promote_unstable_const_fn.nll.stderr
Original file line number Diff line number Diff line change
@@ -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`.
34 changes: 34 additions & 0 deletions src/test/ui/const-eval/dont_promote_unstable_const_fn.rs
Original file line number Diff line number Diff line change
@@ -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();
}
32 changes: 32 additions & 0 deletions src/test/ui/const-eval/dont_promote_unstable_const_fn.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 0a94f78

Please sign in to comment.