1
Fork 0

Auto merge of #53851 - oli-obk:local_promotion, r=eddyb

Limit the promotion of const fns to the libstd and the `rustc_promotable` attribute

There are so many questions around promoting const fn calls... it seems saner to try to limit automatic promotion to const fns which were explicitly opted in for promotion.

I added the attribute to all public stable const fns that were already promotable (e.g. not Cell::new) in order to not cause any breakage

r? @eddyb

cc @nikomatsakis
This commit is contained in:
bors 2018-10-04 06:48:13 +00:00
commit 088fc7384c
45 changed files with 484 additions and 335 deletions

View file

@ -285,6 +285,7 @@ pub fn forget<T>(t: T) {
/// [alignment]: ./fn.align_of.html /// [alignment]: ./fn.align_of.html
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn size_of<T>() -> usize { pub const fn size_of<T>() -> usize {
intrinsics::size_of::<T>() intrinsics::size_of::<T>()
} }
@ -376,6 +377,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
/// ``` /// ```
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn align_of<T>() -> usize { pub const fn align_of<T>() -> usize {
intrinsics::min_align_of::<T>() intrinsics::min_align_of::<T>()
} }

View file

@ -216,6 +216,7 @@ $EndFeature, "
```"), ```"),
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[inline] #[inline]
#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn min_value() -> Self { pub const fn min_value() -> Self {
!0 ^ ((!0 as $UnsignedT) >> 1) as Self !0 ^ ((!0 as $UnsignedT) >> 1) as Self
} }
@ -234,6 +235,7 @@ $EndFeature, "
```"), ```"),
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[inline] #[inline]
#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn max_value() -> Self { pub const fn max_value() -> Self {
!Self::min_value() !Self::min_value()
} }

View file

@ -391,6 +391,7 @@ impl<Idx> RangeInclusive<Idx> {
/// ``` /// ```
#[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
#[inline] #[inline]
#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn new(start: Idx, end: Idx) -> Self { pub const fn new(start: Idx, end: Idx) -> Self {
Self { start, end, is_empty: None } Self { start, end, is_empty: None }
} }

View file

@ -209,6 +209,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
/// ``` /// ```
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn null<T>() -> *const T { 0 as *const T } pub const fn null<T>() -> *const T { 0 as *const T }
/// Creates a null mutable raw pointer. /// Creates a null mutable raw pointer.
@ -223,6 +224,7 @@ pub const fn null<T>() -> *const T { 0 as *const T }
/// ``` /// ```
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn null_mut<T>() -> *mut T { 0 as *mut T } pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
/// Swaps the values at two mutable locations of the same type, without /// Swaps the values at two mutable locations of the same type, without

View file

@ -109,6 +109,7 @@ impl Duration {
/// ``` /// ```
#[stable(feature = "duration", since = "1.3.0")] #[stable(feature = "duration", since = "1.3.0")]
#[inline] #[inline]
#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn from_secs(secs: u64) -> Duration { pub const fn from_secs(secs: u64) -> Duration {
Duration { secs, nanos: 0 } Duration { secs, nanos: 0 }
} }
@ -127,6 +128,7 @@ impl Duration {
/// ``` /// ```
#[stable(feature = "duration", since = "1.3.0")] #[stable(feature = "duration", since = "1.3.0")]
#[inline] #[inline]
#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn from_millis(millis: u64) -> Duration { pub const fn from_millis(millis: u64) -> Duration {
Duration { Duration {
secs: millis / MILLIS_PER_SEC, secs: millis / MILLIS_PER_SEC,
@ -148,6 +150,7 @@ impl Duration {
/// ``` /// ```
#[stable(feature = "duration_from_micros", since = "1.27.0")] #[stable(feature = "duration_from_micros", since = "1.27.0")]
#[inline] #[inline]
#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn from_micros(micros: u64) -> Duration { pub const fn from_micros(micros: u64) -> Duration {
Duration { Duration {
secs: micros / MICROS_PER_SEC, secs: micros / MICROS_PER_SEC,
@ -169,6 +172,7 @@ impl Duration {
/// ``` /// ```
#[stable(feature = "duration_extras", since = "1.27.0")] #[stable(feature = "duration_extras", since = "1.27.0")]
#[inline] #[inline]
#[cfg_attr(not(stage0), rustc_promotable)]
pub const fn from_nanos(nanos: u64) -> Duration { pub const fn from_nanos(nanos: u64) -> Duration {
Duration { Duration {
secs: nanos / (NANOS_PER_SEC as u64), secs: nanos / (NANOS_PER_SEC as u64),

View file

@ -515,6 +515,7 @@ define_dep_nodes!( <'tcx>
[] ItemVarianceConstraints(DefId), [] ItemVarianceConstraints(DefId),
[] ItemVariances(DefId), [] ItemVariances(DefId),
[] IsConstFn(DefId), [] IsConstFn(DefId),
[] IsPromotableConstFn(DefId),
[] IsForeignItem(DefId), [] IsForeignItem(DefId),
[] TypeParamPredicates { item_id: DefId, param_id: DefId }, [] TypeParamPredicates { item_id: DefId, param_id: DefId },
[] SizedConstraint(DefId), [] SizedConstraint(DefId),

View file

@ -130,6 +130,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
level, level,
feature, feature,
rustc_depr, rustc_depr,
promotable,
const_stability const_stability
}); });

View file

@ -441,6 +441,7 @@ impl<'a, 'tcx> Index<'tcx> {
feature: Symbol::intern("rustc_private"), feature: Symbol::intern("rustc_private"),
rustc_depr: None, rustc_depr: None,
const_stability: None, const_stability: None,
promotable: false,
}); });
annotator.parent_stab = Some(stability); annotator.parent_stab = Some(stability);
} }

View file

@ -0,0 +1,111 @@
use ty::query::Providers;
use hir::def_id::DefId;
use hir;
use ty::TyCtxt;
use syntax_pos::symbol::Symbol;
use hir::map::blocks::FnLikeNode;
use syntax::attr;
use rustc_target::spec::abi;
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
/// Whether the `def_id` counts as const fn in your current crate, considering all active
/// feature gates
pub fn is_const_fn(self, def_id: DefId) -> bool {
self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) {
Some(stab) => match stab.const_stability {
// has a `rustc_const_unstable` attribute, check whether the user enabled the
// corresponding feature gate
Some(feature_name) => self.features()
.declared_lib_features
.iter()
.any(|&(sym, _)| sym == feature_name),
// the function has no stability attribute, it is stable as const fn or the user
// needs to use feature gates to use the function at all
None => true,
},
// functions without stability are either stable user written const fn or the user is
// using feature gates and we thus don't care what they do
None => true,
}
}
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
if self.is_const_fn_raw(def_id) {
self.lookup_stability(def_id)?.const_stability
} else {
None
}
}
/// Returns true if this function must conform to `min_const_fn`
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
if self.features().staged_api {
// some intrinsics are waved through if called inside the
// standard library. Users never need to call them directly
if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
assert!(!self.is_const_fn(def_id));
match &self.item_name(def_id).as_str()[..] {
| "size_of"
| "min_align_of"
| "needs_drop"
=> return true,
_ => {},
}
}
// in order for a libstd function to be considered min_const_fn
// it needs to be stable and have no `rustc_const_unstable` attribute
match self.lookup_stability(def_id) {
// stable functions with unstable const fn aren't `min_const_fn`
Some(&attr::Stability { const_stability: Some(_), .. }) => false,
// unstable functions don't need to conform
Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
// everything else needs to conform, because it would be callable from
// other `min_const_fn` functions
_ => true,
}
} else {
// users enabling the `const_fn` can do what they want
!self.sess.features_untracked().const_fn
}
}
}
pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
/// only checks whether the function has a `const` modifier
fn is_const_fn_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
let node_id = tcx.hir.as_local_node_id(def_id)
.expect("Non-local call to local provider is_const_fn");
if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
fn_like.constness() == hir::Constness::Const
} else {
false
}
}
fn is_promotable_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) {
Some(stab) => {
if cfg!(debug_assertions) && stab.promotable {
let sig = tcx.fn_sig(def_id);
assert_eq!(
sig.unsafety(),
hir::Unsafety::Normal,
"don't mark const unsafe fns as promotable",
// https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
);
}
stab.promotable
},
None => false,
}
}
*providers = Providers {
is_const_fn_raw,
is_promotable_const_fn,
..*providers
};
}

View file

@ -1134,38 +1134,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
local as usize == global as usize local as usize == global as usize
} }
/// Returns true if this function must conform to `min_const_fn`
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
if self.features().staged_api {
// some intrinsics are waved through if called inside the
// standard library. Users never need to call them directly
if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
assert!(!self.is_const_fn(def_id));
match &self.item_name(def_id).as_str()[..] {
| "size_of"
| "min_align_of"
| "needs_drop"
=> return true,
_ => {},
}
}
// in order for a libstd function to be considered min_const_fn
// it needs to be stable and have no `rustc_const_unstable` attribute
match self.lookup_stability(def_id) {
// stable functions with unstable const fn aren't `min_const_fn`
Some(&attr::Stability { const_stability: Some(_), .. }) => false,
// unstable functions don't need to conform
Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
// everything else needs to conform, because it would be callable from
// other `min_const_fn` functions
_ => true,
}
} else {
// users enabling the `const_fn` can do what they want
!self.sess.features_untracked().const_fn
}
}
/// Create a type context and call the closure with a `TyCtxt` reference /// Create a type context and call the closure with a `TyCtxt` reference
/// to the context. The closure enforces that the type context and any interned /// to the context. The closure enforces that the type context and any interned
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid /// value (types, substs, etc.) can only be used while `ty::tls` has a valid

View file

@ -109,7 +109,9 @@ impl<'tcx> InstanceDef<'tcx> {
return true return true
} }
let codegen_fn_attrs = tcx.codegen_fn_attrs(self.def_id()); let codegen_fn_attrs = tcx.codegen_fn_attrs(self.def_id());
codegen_fn_attrs.requests_inline() || tcx.is_const_fn(self.def_id()) // need to use `is_const_fn_raw` since we don't really care if the user can use it as a
// const fn, just whether the function should be inlined
codegen_fn_attrs.requests_inline() || tcx.is_const_fn_raw(self.def_id())
} }
} }

View file

@ -94,6 +94,7 @@ pub mod binding;
pub mod cast; pub mod cast;
#[macro_use] #[macro_use]
pub mod codec; pub mod codec;
mod constness;
pub mod error; pub mod error;
mod erase_regions; mod erase_regions;
pub mod fast_reject; pub mod fast_reject;
@ -3056,6 +3057,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
erase_regions::provide(providers); erase_regions::provide(providers);
layout::provide(providers); layout::provide(providers);
util::provide(providers); util::provide(providers);
constness::provide(providers);
*providers = ty::query::Providers { *providers = ty::query::Providers {
associated_item, associated_item,
associated_item_def_ids, associated_item_def_ids,

View file

@ -437,7 +437,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::is_object_safe<'tcx> {
} }
} }
impl<'tcx> QueryDescription<'tcx> for queries::is_const_fn<'tcx> { impl<'tcx> QueryDescription<'tcx> for queries::is_const_fn_raw<'tcx> {
fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> String { fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> String {
format!("checking if item is const fn: `{}`", tcx.item_path_str(def_id)) format!("checking if item is const fn: `{}`", tcx.item_path_str(def_id))
} }

View file

@ -160,8 +160,23 @@ define_queries! { <'tcx>
DefId DefId
) -> Result<DtorckConstraint<'tcx>, NoSolution>, ) -> Result<DtorckConstraint<'tcx>, NoSolution>,
/// True if this is a const fn /// True if this is a const fn, use the `is_const_fn` to know whether your crate actually
[] fn is_const_fn: IsConstFn(DefId) -> bool, /// sees it as const fn (e.g. the const-fn-ness might be unstable and you might not have
/// the feature gate active)
///
/// DO NOT CALL MANUALLY, it is only meant to cache the base data for the `is_const_fn`
/// function
[] fn is_const_fn_raw: IsConstFn(DefId) -> bool,
/// Returns true if calls to the function may be promoted
///
/// This is either because the function is e.g. a tuple-struct or tuple-variant constructor,
/// or because it has the `#[rustc_promotable]` attribute. The attribute should be removed
/// in the future in favour of some form of check which figures out whether the function
/// does not inspect the bits of any of its arguments (so is essentially just a constructor
/// function)
[] fn is_promotable_const_fn: IsPromotableConstFn(DefId) -> bool,
/// True if this is a foreign item (i.e., linked via `extern { ... }`). /// True if this is a foreign item (i.e., linked via `extern { ... }`).
[] fn is_foreign_item: IsForeignItem(DefId) -> bool, [] fn is_foreign_item: IsForeignItem(DefId) -> bool,

View file

@ -1136,7 +1136,8 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::FnSignature => { force!(fn_sig, def_id!()); } DepKind::FnSignature => { force!(fn_sig, def_id!()); }
DepKind::CoerceUnsizedInfo => { force!(coerce_unsized_info, def_id!()); } DepKind::CoerceUnsizedInfo => { force!(coerce_unsized_info, def_id!()); }
DepKind::ItemVariances => { force!(variances_of, def_id!()); } DepKind::ItemVariances => { force!(variances_of, def_id!()); }
DepKind::IsConstFn => { force!(is_const_fn, def_id!()); } DepKind::IsConstFn => { force!(is_const_fn_raw, def_id!()); }
DepKind::IsPromotableConstFn => { force!(is_promotable_const_fn, def_id!()); }
DepKind::IsForeignItem => { force!(is_foreign_item, def_id!()); } DepKind::IsForeignItem => { force!(is_foreign_item, def_id!()); }
DepKind::SizedConstraint => { force!(adt_sized_constraint, def_id!()); } DepKind::SizedConstraint => { force!(adt_sized_constraint, def_id!()); }
DepKind::DtorckConstraint => { force!(adt_dtorck_constraint, def_id!()); } DepKind::DtorckConstraint => { force!(adt_dtorck_constraint, def_id!()); }

View file

@ -26,7 +26,6 @@ use rustc::ty::{self, TyCtxt};
use rustc::ty::query::Providers; use rustc::ty::query::Providers;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
use rustc::hir::map::{DefKey, DefPath, DefPathHash}; use rustc::hir::map::{DefKey, DefPath, DefPathHash};
use rustc::hir::map::blocks::FnLikeNode;
use rustc::hir::map::definitions::DefPathTable; use rustc::hir::map::definitions::DefPathTable;
use rustc::util::nodemap::DefIdMap; use rustc::util::nodemap::DefIdMap;
use rustc_data_structures::svh::Svh; use rustc_data_structures::svh::Svh;
@ -43,7 +42,6 @@ use syntax::parse::source_file_to_stream;
use syntax::symbol::Symbol; use syntax::symbol::Symbol;
use syntax_pos::{Span, NO_EXPANSION, FileName}; use syntax_pos::{Span, NO_EXPANSION, FileName};
use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::bit_set::BitSet;
use rustc::hir;
macro_rules! provide { macro_rules! provide {
(<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident,
@ -145,7 +143,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
} }
fn_sig => { cdata.fn_sig(def_id.index, tcx) } fn_sig => { cdata.fn_sig(def_id.index, tcx) }
inherent_impls => { Lrc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } inherent_impls => { Lrc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
is_const_fn => { cdata.is_const_fn(def_id.index) } is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) }
is_foreign_item => { cdata.is_foreign_item(def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) }
describe_def => { cdata.get_def(def_id.index) } describe_def => { cdata.get_def(def_id.index) }
def_span => { cdata.get_span(def_id.index, &tcx.sess) } def_span => { cdata.get_span(def_id.index, &tcx.sess) }
@ -264,22 +262,10 @@ provide! { <'tcx> tcx, def_id, other, cdata,
} }
pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
fn is_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
let node_id = tcx.hir.as_local_node_id(def_id)
.expect("Non-local call to local provider is_const_fn");
if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
fn_like.constness() == hir::Constness::Const
} else {
false
}
}
// FIXME(#44234) - almost all of these queries have no sub-queries and // FIXME(#44234) - almost all of these queries have no sub-queries and
// therefore no actual inputs, they're just reading tables calculated in // therefore no actual inputs, they're just reading tables calculated in
// resolve! Does this work? Unsure! That's what the issue is about // resolve! Does this work? Unsure! That's what the issue is about
*providers = Providers { *providers = Providers {
is_const_fn,
is_dllimport_foreign_item: |tcx, id| { is_dllimport_foreign_item: |tcx, id| {
tcx.native_library_kind(id) == Some(NativeLibraryKind::NativeUnknown) tcx.native_library_kind(id) == Some(NativeLibraryKind::NativeUnknown)
}, },

View file

@ -1114,7 +1114,7 @@ impl<'a, 'tcx> CrateMetadata {
} }
} }
pub fn is_const_fn(&self, id: DefIndex) -> bool { crate fn is_const_fn_raw(&self, id: DefIndex) -> bool {
let constness = match self.entry(id).kind { let constness = match self.entry(id).kind {
EntryKind::Method(data) => data.decode(self).fn_data.constness, EntryKind::Method(data) => data.decode(self).fn_data.constness,
EntryKind::Fn(data) => data.decode(self).constness, EntryKind::Fn(data) => data.decode(self).constness,

View file

@ -213,7 +213,6 @@ impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum ConstEvalError { enum ConstEvalError {
NeedsRfc(String), NeedsRfc(String),
NotConst(String),
} }
impl fmt::Display for ConstEvalError { impl fmt::Display for ConstEvalError {
@ -227,7 +226,6 @@ impl fmt::Display for ConstEvalError {
msg msg
) )
} }
NotConst(ref msg) => write!(f, "{}", msg),
} }
} }
} }
@ -237,7 +235,6 @@ impl Error for ConstEvalError {
use self::ConstEvalError::*; use self::ConstEvalError::*;
match *self { match *self {
NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants", NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants",
NotConst(_) => "this feature is not compatible with constant evaluation",
} }
} }
@ -293,9 +290,6 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
ecx.goto_block(ret)?; // fully evaluated and done ecx.goto_block(ret)?; // fully evaluated and done
return Ok(None); return Ok(None);
} }
return Err(
ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(),
);
} }
// This is a const fn. Call it. // This is a const fn. Call it.
Ok(Some(match ecx.load_mir(instance.def) { Ok(Some(match ecx.load_mir(instance.def) {

View file

@ -29,7 +29,6 @@ use rustc::mir::traversal::ReversePostorder;
use rustc::mir::visit::{PlaceContext, Visitor}; use rustc::mir::visit::{PlaceContext, Visitor};
use rustc::middle::lang_items; use rustc::middle::lang_items;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use syntax::attr;
use syntax::ast::LitKind; use syntax::ast::LitKind;
use syntax::feature_gate::{UnstableFeatures, feature_err, emit_feature_err, GateIssue}; use syntax::feature_gate::{UnstableFeatures, feature_err, emit_feature_err, GateIssue};
use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::{Span, DUMMY_SP};
@ -813,7 +812,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
let fn_ty = func.ty(self.mir, self.tcx); let fn_ty = func.ty(self.mir, self.tcx);
let mut callee_def_id = None; let mut callee_def_id = None;
let (mut is_shuffle, mut is_const_fn) = (false, None); let (mut is_shuffle, mut is_const_fn) = (false, false);
if let ty::FnDef(def_id, _) = fn_ty.sty { if let ty::FnDef(def_id, _) = fn_ty.sty {
callee_def_id = Some(def_id); callee_def_id = Some(def_id);
match self.tcx.fn_sig(def_id).abi() { match self.tcx.fn_sig(def_id).abi() {
@ -839,10 +838,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
| "unchecked_shr" | "unchecked_shr"
| "add_with_overflow" | "add_with_overflow"
| "sub_with_overflow" | "sub_with_overflow"
| "mul_with_overflow" => is_const_fn = Some(def_id), | "mul_with_overflow"
// no need to check feature gates, intrinsics are only callable from the
// libstd or with forever unstable feature gates
=> is_const_fn = true,
// special intrinsic that can be called diretly without an intrinsic
// feature gate needs a language feature gate
"transmute" => { "transmute" => {
// never promote transmute calls
if self.mode != Mode::Fn { if self.mode != Mode::Fn {
is_const_fn = Some(def_id); is_const_fn = true;
// const eval transmute calls only with the feature gate
if !self.tcx.sess.features_untracked().const_transmute { if !self.tcx.sess.features_untracked().const_transmute {
emit_feature_err( emit_feature_err(
&self.tcx.sess.parse_sess, "const_transmute", &self.tcx.sess.parse_sess, "const_transmute",
@ -861,8 +867,81 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
} }
} }
_ => { _ => {
if self.tcx.is_const_fn(def_id) || self.is_const_panic_fn(def_id) { // in normal functions we only care about promotion
is_const_fn = Some(def_id); if self.mode == Mode::Fn {
// never promote const fn calls of
// functions without #[rustc_promotable]
if self.tcx.is_promotable_const_fn(def_id) {
is_const_fn = true;
}
} else {
// stable const fn or unstable const fns with their feature gate
// active
if self.tcx.is_const_fn(def_id) {
is_const_fn = true;
} else if self.is_const_panic_fn(def_id) {
// check the const_panic feature gate
// FIXME: cannot allow this inside `allow_internal_unstable` because
// that would make `panic!` insta stable in constants, since the
// macro is marked with the attr
if self.tcx.sess.features_untracked().const_panic {
is_const_fn = true;
} else {
// don't allow panics in constants without the feature gate
emit_feature_err(
&self.tcx.sess.parse_sess,
"const_panic",
self.span,
GateIssue::Language,
&format!("panicking in {}s is unstable", self.mode),
);
}
} else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) {
// check `#[unstable]` const fns or `#[rustc_const_unstable]`
// functions without the feature gate active in this crate to report
// a better error message than the one below
if self.span.allows_unstable() {
// `allow_internal_unstable` can make such calls stable
is_const_fn = true;
} else {
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);
err.emit();
}
} else {
// FIXME(#24111) Remove this check when const fn stabilizes
let (msg, note) = if let UnstableFeatures::Disallow =
self.tcx.sess.opts.unstable_features {
(format!("calls in {}s are limited to \
tuple structs and tuple variants",
self.mode),
Some("a limited form of compile-time function \
evaluation is available on a nightly \
compiler via `const fn`"))
} else {
(format!("calls in {}s are limited \
to constant functions, \
tuple structs and tuple variants",
self.mode),
None)
};
let mut err = struct_span_err!(
self.tcx.sess,
self.span,
E0015,
"{}",
msg,
);
if let Some(note) = note {
err.span_note(self.span, note);
}
err.emit();
}
} }
} }
} }
@ -905,78 +984,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
}); });
} }
// Const fn calls. // non-const fn calls.
if let Some(def_id) = is_const_fn { if !is_const_fn {
// check the const_panic feature gate or
// find corresponding rustc_const_unstable feature
// FIXME: cannot allow this inside `allow_internal_unstable` because that would make
// `panic!` insta stable in constants, since the macro is marked with the attr
if self.is_const_panic_fn(def_id) {
if self.mode == Mode::Fn {
// never promote panics
self.qualif = Qualif::NOT_CONST;
} else if !self.tcx.sess.features_untracked().const_panic {
// don't allow panics in constants without the feature gate
emit_feature_err(
&self.tcx.sess.parse_sess,
"const_panic",
self.span,
GateIssue::Language,
&format!("panicking in {}s is unstable", self.mode),
);
}
} else if let Some(&attr::Stability {
const_stability: Some(ref feature_name),
.. }) = self.tcx.lookup_stability(def_id) {
if
// feature-gate is not enabled,
!self.tcx.features()
.declared_lib_features
.iter()
.any(|&(ref sym, _)| sym == feature_name) &&
// this doesn't come from a macro that has #[allow_internal_unstable]
!self.span.allows_unstable()
{
self.qualif = Qualif::NOT_CONST;
if self.mode != Mode::Fn {
// 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 {
self.qualif = Qualif::NOT_CONST; self.qualif = Qualif::NOT_CONST;
if self.mode != Mode::Fn { if self.mode != Mode::Fn {
// FIXME(#24111) Remove this check when const fn stabilizes self.tcx.sess.delay_span_bug(
let (msg, note) = if let UnstableFeatures::Disallow = self.span,
self.tcx.sess.opts.unstable_features { "should have reported an error about non-const fn calls in constants",
(format!("calls in {}s are limited to \ )
tuple structs and tuple variants",
self.mode),
Some("a limited form of compile-time function \
evaluation is available on a nightly \
compiler via `const fn`"))
} else {
(format!("calls in {}s are limited \
to constant functions, \
tuple structs and tuple variants",
self.mode),
None)
};
let mut err = struct_span_err!(self.tcx.sess, self.span, E0015, "{}", msg);
if let Some(note) = note {
err.span_note(self.span, note);
}
err.emit();
} }
} }

View file

@ -27,7 +27,6 @@
use rustc::ty::cast::CastKind; use rustc::ty::cast::CastKind;
use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::middle::expr_use_visitor as euv; use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization; use rustc::middle::mem_categorization::Categorization;
@ -38,7 +37,6 @@ use rustc::util::nodemap::{ItemLocalSet, NodeSet};
use rustc::hir; use rustc::hir;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use syntax::ast; use syntax::ast;
use syntax::attr;
use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::{Span, DUMMY_SP};
use self::Promotability::*; use self::Promotability::*;
use std::ops::{BitAnd, BitAndAssign, BitOr}; use std::ops::{BitAnd, BitAndAssign, BitOr};
@ -160,41 +158,15 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
} }
} }
fn handle_const_fn_call(&mut self, def_id: DefId, fn handle_const_fn_call(
ret_ty: Ty<'gcx>, span: Span) -> Promotability { &mut self,
if self.type_promotability(ret_ty) == NotPromotable { def_id: DefId,
return NotPromotable; ) -> Promotability {
} if self.tcx.is_promotable_const_fn(def_id) {
Promotable
let node_check = if let Some(fn_id) = self.tcx.hir.as_local_node_id(def_id) {
FnLikeNode::from_node(self.tcx.hir.get(fn_id)).map_or(false, |fn_like| {
fn_like.constness() == hir::Constness::Const
})
} else { } else {
self.tcx.is_const_fn(def_id) NotPromotable
};
if !node_check {
return NotPromotable
} }
if let Some(&attr::Stability {
const_stability: Some(ref feature_name),
.. }) = self.tcx.lookup_stability(def_id) {
let stable_check =
// feature-gate is enabled,
self.tcx.features()
.declared_lib_features
.iter()
.any(|&(ref sym, _)| sym == feature_name) ||
// this comes from a macro that has #[allow_internal_unstable]
span.allows_unstable();
if !stable_check {
return NotPromotable
}
};
Promotable
} }
/// While the `ExprUseVisitor` walks, we will identify which /// While the `ExprUseVisitor` walks, we will identify which
@ -443,14 +415,10 @@ fn check_expr_kind<'a, 'tcx>(
Def::StructCtor(_, CtorKind::Fn) | Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) |
Def::SelfCtor(..) => Promotable, Def::SelfCtor(..) => Promotable,
Def::Fn(did) => { Def::Fn(did) => v.handle_const_fn_call(did),
v.handle_const_fn_call(did, node_ty, e.span)
}
Def::Method(did) => { Def::Method(did) => {
match v.tcx.associated_item(did).container { match v.tcx.associated_item(did).container {
ty::ImplContainer(_) => { ty::ImplContainer(_) => v.handle_const_fn_call(did),
v.handle_const_fn_call(did, node_ty, e.span)
}
ty::TraitContainer(_) => NotPromotable, ty::TraitContainer(_) => NotPromotable,
} }
} }
@ -466,16 +434,13 @@ fn check_expr_kind<'a, 'tcx>(
if let Some(def) = v.tables.type_dependent_defs().get(e.hir_id) { if let Some(def) = v.tables.type_dependent_defs().get(e.hir_id) {
let def_id = def.def_id(); let def_id = def.def_id();
match v.tcx.associated_item(def_id).container { match v.tcx.associated_item(def_id).container {
ty::ImplContainer(_) => { ty::ImplContainer(_) => method_call_result & v.handle_const_fn_call(def_id),
method_call_result = method_call_result ty::TraitContainer(_) => NotPromotable,
& v.handle_const_fn_call(def_id, node_ty, e.span); }
}
ty::TraitContainer(_) => return NotPromotable,
};
} else { } else {
v.tcx.sess.delay_span_bug(e.span, "no type-dependent def for method call"); v.tcx.sess.delay_span_bug(e.span, "no type-dependent def for method call");
NotPromotable
} }
method_call_result
} }
hir::ExprKind::Struct(ref _qpath, ref hirvec, ref option_expr) => { hir::ExprKind::Struct(ref _qpath, ref hirvec, ref option_expr) => {
let mut struct_result = Promotable; let mut struct_result = Promotable;

View file

@ -112,6 +112,8 @@ pub struct Stability {
/// `Some` contains the feature gate required to be able to use the function /// `Some` contains the feature gate required to be able to use the function
/// as const fn /// as const fn
pub const_stability: Option<Symbol>, pub const_stability: Option<Symbol>,
/// whether the function has a `#[rustc_promotable]` attribute
pub promotable: bool,
} }
/// The available stability levels. /// The available stability levels.
@ -176,6 +178,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
let mut stab: Option<Stability> = None; let mut stab: Option<Stability> = None;
let mut rustc_depr: Option<RustcDeprecation> = None; let mut rustc_depr: Option<RustcDeprecation> = None;
let mut rustc_const_unstable: Option<Symbol> = None; let mut rustc_const_unstable: Option<Symbol> = None;
let mut promotable = false;
'outer: for attr in attrs_iter { 'outer: for attr in attrs_iter {
if ![ if ![
@ -183,6 +186,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
"rustc_const_unstable", "rustc_const_unstable",
"unstable", "unstable",
"stable", "stable",
"rustc_promotable",
].iter().any(|&s| attr.path == s) { ].iter().any(|&s| attr.path == s) {
continue // not a stability level continue // not a stability level
} }
@ -190,8 +194,12 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
mark_used(attr); mark_used(attr);
let meta = attr.meta(); let meta = attr.meta();
if attr.path == "rustc_promotable" {
promotable = true;
}
// attributes with data // attributes with data
if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta { else if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta {
let meta = meta.as_ref().unwrap(); let meta = meta.as_ref().unwrap();
let get = |meta: &MetaItem, item: &mut Option<Symbol>| { let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
if item.is_some() { if item.is_some() {
@ -329,6 +337,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
feature, feature,
rustc_depr: None, rustc_depr: None,
const_stability: None, const_stability: None,
promotable: false,
}) })
} }
(None, _, _) => { (None, _, _) => {
@ -378,6 +387,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
feature, feature,
rustc_depr: None, rustc_depr: None,
const_stability: None, const_stability: None,
promotable: false,
}) })
} }
(None, _) => { (None, _) => {
@ -420,6 +430,17 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
} }
} }
// Merge the const-unstable info into the stability info
if promotable {
if let Some(ref mut stab) = stab {
stab.promotable = true;
} else {
span_err!(diagnostic, item_sp, E0717,
"rustc_promotable attribute must be paired with \
either stable or unstable attribute");
}
}
stab stab
} }

View file

@ -413,4 +413,5 @@ register_diagnostics! {
E0694, // an unknown tool name found in scoped attributes E0694, // an unknown tool name found in scoped attributes
E0703, // invalid ABI E0703, // invalid ABI
E0704, // incorrect visibility restriction E0704, // incorrect visibility restriction
E0717, // rustc_promotable without stability attribute
} }

View file

@ -14,7 +14,8 @@
// compile-flags: -C debug_assertions=yes // compile-flags: -C debug_assertions=yes
#![feature(const_fn, libc)] #![stable(feature = "rustc", since = "1.0.0")]
#![feature(const_fn, libc, staged_api, rustc_attrs)]
#![allow(const_err)] #![allow(const_err)]
extern crate libc; extern crate libc;
@ -23,6 +24,8 @@ use std::env;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
// this will panic in debug mode and overflow in release mode // this will panic in debug mode and overflow in release mode
#[stable(feature = "rustc", since = "1.0.0")]
#[rustc_promotable]
const fn bar() -> usize { 0 - 1 } const fn bar() -> usize { 0 - 1 }
fn foo() { fn foo() {

View file

@ -13,13 +13,15 @@
use std::cell::Cell; use std::cell::Cell;
const FIVE: Cell<i32> = Cell::new(5);
#[inline(never)] #[inline(never)]
fn tuple_field() -> &'static u32 { fn tuple_field() -> &'static u32 {
// This test is MIR-borrowck-only because the old borrowck // This test is MIR-borrowck-only because the old borrowck
// doesn't agree that borrows of "frozen" (i.e. without any // doesn't agree that borrows of "frozen" (i.e. without any
// interior mutability) fields of non-frozen temporaries, // interior mutability) fields of non-frozen temporaries,
// should be promoted, while MIR promotion does promote them. // should be promoted, while MIR promotion does promote them.
&(Cell::new(5), 42).1 &(FIVE, 42).1
} }
fn main() { fn main() {

View file

@ -15,5 +15,4 @@ fn f(x: usize) -> usize {
fn main() { fn main() {
let _ = [0; f(2)]; let _ = [0; f(2)];
//~^ ERROR calls in constants are limited to constant functions //~^ ERROR calls in constants are limited to constant functions
//~| E0080
} }

View file

@ -4,13 +4,6 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct
LL | let _ = [0; f(2)]; LL | let _ = [0; f(2)];
| ^^^^ | ^^^^
error[E0080]: could not evaluate repeat length error: aborting due to previous error
--> $DIR/const-call.rs:16:17
|
LL | let _ = [0; f(2)];
| ^^^^ calling non-const fn `f`
error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0015`.
Some errors occurred: E0015, E0080.
For more information about an error, try `rustc --explain E0015`.

View file

@ -32,7 +32,7 @@ error[E0716]: temporary value dropped while borrowed
| |
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
LL | //~^ does not live long enough LL | //~^ ERROR does not live long enough
LL | } LL | }
| - temporary value is freed at the end of this statement | - temporary value is freed at the end of this statement
| |

View file

@ -31,5 +31,5 @@ fn a() {
fn main() { fn main() {
let _: &'static u32 = &meh(); //~ ERROR does not live long enough let _: &'static u32 = &meh(); //~ ERROR does not live long enough
let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
//~^ does not live long enough //~^ ERROR does not live long enough
} }

View file

@ -32,7 +32,7 @@ error[E0597]: borrowed value does not live long enough
| |
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
LL | //~^ does not live long enough LL | //~^ ERROR does not live long enough
LL | } LL | }
| - temporary value only lives until here | - temporary value only lives until here
| |

View file

@ -1,51 +0,0 @@
error[E0308]: mismatched types
--> $DIR/issue-52443.rs:12:10
|
LL | [(); & { loop { continue } } ]; //~ ERROR mismatched types
| ^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected usize, found reference
| help: consider removing the borrow: `{ loop { continue } }`
|
= note: expected type `usize`
found type `&_`
error[E0308]: mismatched types
--> $DIR/issue-52443.rs:13:17
|
LL | [(); loop { break }]; //~ ERROR mismatched types
| ^^^^^ expected (), found usize
|
= note: expected type `()`
found type `usize`
error[E0019]: constant contains unimplemented expression type
--> $DIR/issue-52443.rs:14:11
|
LL | [(); {while true {break}; 0}]; //~ ERROR constant contains unimplemented expression type
| ^^^^^^^^^^^^^^^^^^
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
--> $DIR/issue-52443.rs:15:21
|
LL | [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
| ^^^^^^^^
error[E0019]: constant contains unimplemented expression type
--> $DIR/issue-52443.rs:15:21
|
LL | [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
| ^^^^^^^^
error[E0080]: could not evaluate repeat length
--> $DIR/issue-52443.rs:15:10
|
LL | [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
| ^^^^^^^^^^^--------^^^^^^^
| |
| calling non-const fn `<I as std::iter::IntoIterator><std::ops::RangeFrom<usize>>::into_iter`
error: aborting due to 6 previous errors
Some errors occurred: E0015, E0019, E0080, E0308.
For more information about an error, try `rustc --explain E0015`.

View file

@ -0,0 +1,14 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/promoted_const_fn_fail.rs:30:27
|
LL | let x: &'static u8 = &(bar() + 1); //~ ERROR does not live long enough
| ^^^^^^^^^^^ creates a temporary which is freed while still in use
...
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error
For more information about this error, try `rustc --explain E0716`.

View file

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// compile-pass
#![feature(const_fn, const_fn_union)] #![feature(const_fn, const_fn_union)]
#![deny(const_err)] #![deny(const_err)]
@ -29,10 +27,7 @@ const fn bar() -> u8 {
} }
fn main() { fn main() {
// FIXME(oli-obk): this should panic at runtime let x: &'static u8 = &(bar() + 1); //~ ERROR does not live long enough
// this will actually compile, but then
// abort at runtime (not panic, hard abort).
let x: &'static u8 = &(bar() + 1);
let y = *x; let y = *x;
unreachable!(); unreachable!();
} }

View file

@ -0,0 +1,14 @@
error[E0597]: borrowed value does not live long enough
--> $DIR/promoted_const_fn_fail.rs:30:27
|
LL | let x: &'static u8 = &(bar() + 1); //~ 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: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.

View file

@ -1,43 +0,0 @@
error[E0658]: let bindings in constant functions are unstable (see issue #48821)
--> $DIR/const-fn-error.rs:16:19
|
LL | let mut sum = 0;
| ^
|
= help: add #![feature(const_let)] to the crate attributes to enable
error[E0658]: statements in constant functions are unstable (see issue #48821)
--> $DIR/const-fn-error.rs:16:19
|
LL | let mut sum = 0;
| ^
|
= help: add #![feature(const_let)] to the crate attributes to enable
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
--> $DIR/const-fn-error.rs:19:14
|
LL | for i in 0..x {
| ^^^^
error[E0019]: constant function contains unimplemented expression type
--> $DIR/const-fn-error.rs:19:14
|
LL | for i in 0..x {
| ^^^^
error[E0080]: could not evaluate constant expression
--> $DIR/const-fn-error.rs:29:13
|
LL | for i in 0..x {
| ---- calling non-const fn `<I as std::iter::IntoIterator><std::ops::Range<usize>>::into_iter`
...
LL | let a : [i32; f(X)]; //~ ERROR E0080
| ^^^^^^----^
| |
| inside call to `f`
error: aborting due to 5 previous errors
Some errors occurred: E0015, E0019, E0080, E0658.
For more information about an error, try `rustc --explain E0015`.

View file

@ -0,0 +1,68 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/promotion.rs:13:27
|
LL | let x: &'static () = &foo1(); //~ ERROR does not live long enough
| ^^^^^^ creates a temporary which is freed while still in use
...
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...
error[E0716]: temporary value dropped while borrowed
--> $DIR/promotion.rs:14:28
|
LL | let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough
| ^^^^^^^^ creates a temporary which is freed while still in use
...
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...
error[E0716]: temporary value dropped while borrowed
--> $DIR/promotion.rs:15:28
|
LL | let z: &'static i32 = &foo3(); //~ ERROR does not live long enough
| ^^^^^^ creates a temporary which is freed while still in use
...
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...
error[E0716]: temporary value dropped while borrowed
--> $DIR/promotion.rs:16:34
|
LL | let a: &'static Cell<i32> = &foo4(); //~ ERROR does not live long enough
| ^^^^^^ creates a temporary which is freed while still in use
...
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...
error[E0716]: temporary value dropped while borrowed
--> $DIR/promotion.rs:17:42
|
LL | let a: &'static Option<Cell<i32>> = &foo5(); //~ ERROR does not live long enough
| ^^^^^^ creates a temporary which is freed while still in use
LL | let a: &'static Option<Cell<i32>> = &foo6(); //~ ERROR does not live long enough
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...
error[E0716]: temporary value dropped while borrowed
--> $DIR/promotion.rs:18:42
|
LL | let a: &'static Option<Cell<i32>> = &foo6(); //~ ERROR does not live long enough
| ^^^^^^ creates a temporary which is freed while still in use
LL | }
| - temporary value is freed at the end of this statement
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0716`.

View file

@ -0,0 +1,19 @@
#![feature(min_const_fn)]
use std::cell::Cell;
const fn foo1() {}
const fn foo2(x: i32) -> i32 { x }
const fn foo3() -> i32 { 42 }
const fn foo4() -> Cell<i32> { Cell::new(42) }
const fn foo5() -> Option<Cell<i32>> { Some(Cell::new(42)) }
const fn foo6() -> Option<Cell<i32>> { None }
fn main() {
let x: &'static () = &foo1(); //~ ERROR does not live long enough
let y: &'static i32 = &foo2(42); //~ ERROR does not live long enough
let z: &'static i32 = &foo3(); //~ ERROR does not live long enough
let a: &'static Cell<i32> = &foo4(); //~ ERROR does not live long enough
let a: &'static Option<Cell<i32>> = &foo5(); //~ ERROR does not live long enough
let a: &'static Option<Cell<i32>> = &foo6(); //~ ERROR does not live long enough
}

View file

@ -0,0 +1,68 @@
error[E0597]: borrowed value does not live long enough
--> $DIR/promotion.rs:13:27
|
LL | let x: &'static () = &foo1(); //~ 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/promotion.rs:14:28
|
LL | let y: &'static i32 = &foo2(42); //~ 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/promotion.rs:15:28
|
LL | let z: &'static i32 = &foo3(); //~ 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/promotion.rs:16:34
|
LL | let a: &'static Cell<i32> = &foo4(); //~ 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/promotion.rs:17:42
|
LL | let a: &'static Option<Cell<i32>> = &foo5(); //~ ERROR does not live long enough
| ^^^^^^ temporary value does not live long enough
LL | let a: &'static Option<Cell<i32>> = &foo6(); //~ ERROR 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/promotion.rs:18:42
|
LL | let a: &'static Option<Cell<i32>> = &foo6(); //~ 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: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0597`.

View file

@ -23,8 +23,6 @@ impl Dim for Dim3 {
fn main() { fn main() {
let array: [usize; Dim3::dim()] let array: [usize; Dim3::dim()]
//~^ ERROR E0015 //~^ ERROR E0015
//~| ERROR E0080
= [0; Dim3::dim()]; = [0; Dim3::dim()];
//~^ ERROR E0015 //~^ ERROR E0015
//~| ERROR E0080
} }

View file

@ -5,26 +5,11 @@ LL | let array: [usize; Dim3::dim()]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
--> $DIR/issue-39559-2.rs:27:15 --> $DIR/issue-39559-2.rs:26:15
| |
LL | = [0; Dim3::dim()]; LL | = [0; Dim3::dim()];
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error[E0080]: could not evaluate repeat length error: aborting due to 2 previous errors
--> $DIR/issue-39559-2.rs:27:15
|
LL | = [0; Dim3::dim()];
| ^^^^^^^^^^^ calling non-const fn `<Dim3 as Dim>::dim`
error[E0080]: could not evaluate constant expression For more information about this error, try `rustc --explain E0015`.
--> $DIR/issue-39559-2.rs:24:16
|
LL | let array: [usize; Dim3::dim()]
| ^^^^^^^^-----------^
| |
| calling non-const fn `<Dim3 as Dim>::dim`
error: aborting due to 4 previous errors
Some errors occurred: E0015, E0080.
For more information about an error, try `rustc --explain E0015`.

View file

@ -16,7 +16,6 @@ const NUM: u8 = xyz();
fn main() { fn main() {
match 1 { match 1 {
NUM => unimplemented!(), NUM => unimplemented!(),
//~^ ERROR could not evaluate constant pattern
_ => unimplemented!(), _ => unimplemented!(),
} }
} }

View file

@ -4,16 +4,6 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct
LL | const NUM: u8 = xyz(); LL | const NUM: u8 = xyz();
| ^^^^^ | ^^^^^
error[E0080]: could not evaluate constant pattern error: aborting due to previous error
--> $DIR/issue-43105.rs:18:9
|
LL | const NUM: u8 = xyz();
| ----- calling non-const fn `xyz`
...
LL | NUM => unimplemented!(),
| ^^^
error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0015`.
Some errors occurred: E0015, E0080.
For more information about an error, try `rustc --explain E0015`.

View file

@ -27,7 +27,8 @@ const fn baz() -> i32 {
fn main() { fn main() {
foo(2); foo(2);
foo(2 + 3); foo(2 + 3);
foo(baz()); const BAZ: i32 = baz();
foo(BAZ);
let a = 4; let a = 4;
foo(A); foo(A);
foo(a); //~ ERROR: argument 1 is required to be a constant foo(a); //~ ERROR: argument 1 is required to be a constant

View file

@ -1,11 +1,11 @@
error: argument 1 is required to be a constant error: argument 1 is required to be a constant
--> $DIR/rustc-args-required-const.rs:33:5 --> $DIR/rustc-args-required-const.rs:34:5
| |
LL | foo(a); //~ ERROR: argument 1 is required to be a constant LL | foo(a); //~ ERROR: argument 1 is required to be a constant
| ^^^^^^ | ^^^^^^
error: argument 2 is required to be a constant error: argument 2 is required to be a constant
--> $DIR/rustc-args-required-const.rs:35:5 --> $DIR/rustc-args-required-const.rs:36:5
| |
LL | bar(a, a); //~ ERROR: argument 2 is required to be a constant LL | bar(a, a); //~ ERROR: argument 2 is required to be a constant
| ^^^^^^^^^ | ^^^^^^^^^