diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f537add999a03..27ee9556bd089 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -285,6 +285,7 @@ pub fn forget(t: T) { /// [alignment]: ./fn.align_of.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(stage0), rustc_promotable)] pub const fn size_of() -> usize { intrinsics::size_of::() } @@ -376,6 +377,7 @@ pub fn min_align_of_val(val: &T) -> usize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(stage0), rustc_promotable)] pub const fn align_of() -> usize { intrinsics::min_align_of::() } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index f054580cba7bc..772502cc800e8 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -216,6 +216,7 @@ $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn min_value() -> Self { !0 ^ ((!0 as $UnsignedT) >> 1) as Self } @@ -234,6 +235,7 @@ $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn max_value() -> Self { !Self::min_value() } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index f7e5a89a7aae1..07ba285ea5cb3 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -391,6 +391,7 @@ impl RangeInclusive { /// ``` #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn new(start: Idx, end: Idx) -> Self { Self { start, end, is_empty: None } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 14f2148a64e0e..bd58dcf4ae055 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -209,6 +209,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(stage0), rustc_promotable)] pub const fn null() -> *const T { 0 as *const T } /// Creates a null mutable raw pointer. @@ -223,6 +224,7 @@ pub const fn null() -> *const T { 0 as *const T } /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(stage0), rustc_promotable)] pub const fn null_mut() -> *mut T { 0 as *mut T } /// Swaps the values at two mutable locations of the same type, without diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 1aed5a7b426fd..81ae8ade12d93 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -109,6 +109,7 @@ impl Duration { /// ``` #[stable(feature = "duration", since = "1.3.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn from_secs(secs: u64) -> Duration { Duration { secs, nanos: 0 } } @@ -127,6 +128,7 @@ impl Duration { /// ``` #[stable(feature = "duration", since = "1.3.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn from_millis(millis: u64) -> Duration { Duration { secs: millis / MILLIS_PER_SEC, @@ -148,6 +150,7 @@ impl Duration { /// ``` #[stable(feature = "duration_from_micros", since = "1.27.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn from_micros(micros: u64) -> Duration { Duration { secs: micros / MICROS_PER_SEC, @@ -169,6 +172,7 @@ impl Duration { /// ``` #[stable(feature = "duration_extras", since = "1.27.0")] #[inline] + #[cfg_attr(not(stage0), rustc_promotable)] pub const fn from_nanos(nanos: u64) -> Duration { Duration { secs: nanos / (NANOS_PER_SEC as u64), diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 0d0dc0832a459..994bbe727fcf8 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -515,6 +515,7 @@ define_dep_nodes!( <'tcx> [] ItemVarianceConstraints(DefId), [] ItemVariances(DefId), [] IsConstFn(DefId), + [] IsPromotableConstFn(DefId), [] IsForeignItem(DefId), [] TypeParamPredicates { item_id: DefId, param_id: DefId }, [] SizedConstraint(DefId), diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index a15411c7d8369..4be467c01aac1 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -130,6 +130,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr, + promotable, const_stability }); diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 73a55265f009a..b7b149ea02988 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -441,6 +441,7 @@ impl<'a, 'tcx> Index<'tcx> { feature: Symbol::intern("rustc_private"), rustc_depr: None, const_stability: None, + promotable: false, }); annotator.parent_stab = Some(stability); } diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs new file mode 100644 index 0000000000000..64e677fbe1261 --- /dev/null +++ b/src/librustc/ty/constness.rs @@ -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 { + 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 + }; +} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 64e9d15092eb8..85559c892c4af 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1134,38 +1134,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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 /// 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 diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index a6e181a26f420..3416d6594c7f7 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -109,7 +109,9 @@ impl<'tcx> InstanceDef<'tcx> { return true } 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()) } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b2281691bd660..57afbafc2a5f6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -94,6 +94,7 @@ pub mod binding; pub mod cast; #[macro_use] pub mod codec; +mod constness; pub mod error; mod erase_regions; pub mod fast_reject; @@ -3056,6 +3057,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { erase_regions::provide(providers); layout::provide(providers); util::provide(providers); + constness::provide(providers); *providers = ty::query::Providers { associated_item, associated_item_def_ids, diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index 9ea655ba6fd5d..66d7541633cde 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -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 { format!("checking if item is const fn: `{}`", tcx.item_path_str(def_id)) } diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index e0a503a9cebf5..44c9c55b8a4eb 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -160,8 +160,23 @@ define_queries! { <'tcx> DefId ) -> Result, NoSolution>, - /// True if this is a const fn - [] fn is_const_fn: IsConstFn(DefId) -> bool, + /// True if this is a const fn, use the `is_const_fn` to know whether your crate actually + /// 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 { ... }`). [] fn is_foreign_item: IsForeignItem(DefId) -> bool, diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 510ca08b62100..fbd3a8f69bc45 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -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::CoerceUnsizedInfo => { force!(coerce_unsized_info, 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::SizedConstraint => { force!(adt_sized_constraint, def_id!()); } DepKind::DtorckConstraint => { force!(adt_dtorck_constraint, def_id!()); } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index fb0d683798606..7988de28b5d7b 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -26,7 +26,6 @@ use rustc::ty::{self, TyCtxt}; use rustc::ty::query::Providers; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; use rustc::hir::map::{DefKey, DefPath, DefPathHash}; -use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::definitions::DefPathTable; use rustc::util::nodemap::DefIdMap; use rustc_data_structures::svh::Svh; @@ -43,7 +42,6 @@ use syntax::parse::source_file_to_stream; use syntax::symbol::Symbol; use syntax_pos::{Span, NO_EXPANSION, FileName}; use rustc_data_structures::bit_set::BitSet; -use rustc::hir; macro_rules! provide { (<$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) } 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) } describe_def => { cdata.get_def(def_id.index) } 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>) { - 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 // therefore no actual inputs, they're just reading tables calculated in // resolve! Does this work? Unsure! That's what the issue is about *providers = Providers { - is_const_fn, is_dllimport_foreign_item: |tcx, id| { tcx.native_library_kind(id) == Some(NativeLibraryKind::NativeUnknown) }, diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 33a4af053eb73..9864c1f3d7c68 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -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 { EntryKind::Method(data) => data.decode(self).fn_data.constness, EntryKind::Fn(data) => data.decode(self).constness, diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 07e2cfe1e80d2..3b1eba51aaf45 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -213,7 +213,6 @@ impl<'tcx> Into> for ConstEvalError { #[derive(Clone, Debug)] enum ConstEvalError { NeedsRfc(String), - NotConst(String), } impl fmt::Display for ConstEvalError { @@ -227,7 +226,6 @@ impl fmt::Display for ConstEvalError { msg ) } - NotConst(ref msg) => write!(f, "{}", msg), } } } @@ -237,7 +235,6 @@ impl Error for ConstEvalError { use self::ConstEvalError::*; match *self { 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 return Ok(None); } - return Err( - ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(), - ); } // This is a const fn. Call it. Ok(Some(match ecx.load_mir(instance.def) { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 2811848424b4e..17fe78d325cf1 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -29,7 +29,6 @@ use rustc::mir::traversal::ReversePostorder; use rustc::mir::visit::{PlaceContext, Visitor}; use rustc::middle::lang_items; use rustc_target::spec::abi::Abi; -use syntax::attr; use syntax::ast::LitKind; use syntax::feature_gate::{UnstableFeatures, feature_err, emit_feature_err, GateIssue}; 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 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 { callee_def_id = Some(def_id); match self.tcx.fn_sig(def_id).abi() { @@ -839,10 +838,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { | "unchecked_shr" | "add_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" => { + // never promote transmute calls 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 { emit_feature_err( &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) { - is_const_fn = Some(def_id); + // in normal functions we only care about promotion + 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. - if let Some(def_id) = 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 { + // non-const fn calls. + if !is_const_fn { self.qualif = Qualif::NOT_CONST; if self.mode != Mode::Fn { - // 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(); + self.tcx.sess.delay_span_bug( + self.span, + "should have reported an error about non-const fn calls in constants", + ) } } diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index efe59e4face5e..5e9169e86a98d 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -27,7 +27,6 @@ use rustc::ty::cast::CastKind; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; -use rustc::hir::map::blocks::FnLikeNode; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; @@ -38,7 +37,6 @@ 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 self::Promotability::*; 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, - ret_ty: Ty<'gcx>, span: Span) -> Promotability { - if self.type_promotability(ret_ty) == NotPromotable { - return NotPromotable; - } - - 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 - }) + fn handle_const_fn_call( + &mut self, + def_id: DefId, + ) -> Promotability { + if self.tcx.is_promotable_const_fn(def_id) { + Promotable } else { - self.tcx.is_const_fn(def_id) - }; - - if !node_check { - return NotPromotable + 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 @@ -443,14 +415,10 @@ fn check_expr_kind<'a, 'tcx>( Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) | Def::SelfCtor(..) => Promotable, - Def::Fn(did) => { - v.handle_const_fn_call(did, node_ty, e.span) - } + Def::Fn(did) => v.handle_const_fn_call(did), Def::Method(did) => { match v.tcx.associated_item(did).container { - ty::ImplContainer(_) => { - v.handle_const_fn_call(did, node_ty, e.span) - } + ty::ImplContainer(_) => v.handle_const_fn_call(did), 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) { let def_id = def.def_id(); match v.tcx.associated_item(def_id).container { - ty::ImplContainer(_) => { - method_call_result = method_call_result - & v.handle_const_fn_call(def_id, node_ty, e.span); - } - ty::TraitContainer(_) => return NotPromotable, - }; + ty::ImplContainer(_) => method_call_result & v.handle_const_fn_call(def_id), + ty::TraitContainer(_) => NotPromotable, + } } else { 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) => { let mut struct_result = Promotable; diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 5fc9c5578e1f2..f1cec422420ed 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -112,6 +112,8 @@ pub struct Stability { /// `Some` contains the feature gate required to be able to use the function /// as const fn pub const_stability: Option, + /// whether the function has a `#[rustc_promotable]` attribute + pub promotable: bool, } /// The available stability levels. @@ -176,6 +178,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut stab: Option = None; let mut rustc_depr: Option = None; let mut rustc_const_unstable: Option = None; + let mut promotable = false; 'outer: for attr in attrs_iter { if ![ @@ -183,6 +186,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, "rustc_const_unstable", "unstable", "stable", + "rustc_promotable", ].iter().any(|&s| attr.path == s) { continue // not a stability level } @@ -190,8 +194,12 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, mark_used(attr); let meta = attr.meta(); + + if attr.path == "rustc_promotable" { + promotable = true; + } // 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 get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { @@ -329,6 +337,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, feature, rustc_depr: None, const_stability: None, + promotable: false, }) } (None, _, _) => { @@ -378,6 +387,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, feature, rustc_depr: None, const_stability: None, + promotable: false, }) } (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 } diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 23ce7fc6a6568..5155ebbe19d47 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -413,4 +413,5 @@ register_diagnostics! { E0694, // an unknown tool name found in scoped attributes E0703, // invalid ABI E0704, // incorrect visibility restriction + E0717, // rustc_promotable without stability attribute } diff --git a/src/test/ui/consts/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs similarity index 100% rename from src/test/ui/consts/const-fn-error.rs rename to src/test/compile-fail/const-fn-error.rs diff --git a/src/test/ui/consts/const-eval/issue-52443.rs b/src/test/compile-fail/issue-52443.rs similarity index 100% rename from src/test/ui/consts/const-eval/issue-52443.rs rename to src/test/compile-fail/issue-52443.rs diff --git a/src/test/run-pass/invalid_const_promotion.rs b/src/test/run-pass/invalid_const_promotion.rs index e861f21762991..ed8c4992417af 100644 --- a/src/test/run-pass/invalid_const_promotion.rs +++ b/src/test/run-pass/invalid_const_promotion.rs @@ -14,7 +14,8 @@ // 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)] extern crate libc; @@ -23,6 +24,8 @@ use std::env; use std::process::{Command, Stdio}; // 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 } fn foo() { diff --git a/src/test/run-pass/issues/issue-49955-2.rs b/src/test/run-pass/issues/issue-49955-2.rs index 40827b0162202..88883821073d3 100644 --- a/src/test/run-pass/issues/issue-49955-2.rs +++ b/src/test/run-pass/issues/issue-49955-2.rs @@ -13,13 +13,15 @@ use std::cell::Cell; +const FIVE: Cell = Cell::new(5); + #[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 + &(FIVE, 42).1 } fn main() { diff --git a/src/test/ui/consts/const-call.rs b/src/test/ui/consts/const-call.rs index 02264228a6bf6..18476494300b2 100644 --- a/src/test/ui/consts/const-call.rs +++ b/src/test/ui/consts/const-call.rs @@ -15,5 +15,4 @@ fn f(x: usize) -> usize { fn main() { let _ = [0; f(2)]; //~^ ERROR calls in constants are limited to constant functions - //~| E0080 } diff --git a/src/test/ui/consts/const-call.stderr b/src/test/ui/consts/const-call.stderr index efc3c58c6813b..81be93e916e8b 100644 --- a/src/test/ui/consts/const-call.stderr +++ b/src/test/ui/consts/const-call.stderr @@ -4,13 +4,6 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | let _ = [0; f(2)]; | ^^^^ -error[E0080]: could not evaluate repeat length - --> $DIR/const-call.rs:16:17 - | -LL | let _ = [0; f(2)]; - | ^^^^ calling non-const fn `f` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0015, E0080. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr index fe7187af5f598..bae8b89f3d0f5 100644 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr @@ -32,7 +32,7 @@ error[E0716]: temporary value dropped while borrowed | LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use -LL | //~^ does not live long enough +LL | //~^ ERROR does not live long enough LL | } | - temporary value is freed at the end of this statement | diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs index 623e99480a70a..a371d5485e146 100644 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs @@ -31,5 +31,5 @@ fn a() { fn main() { let _: &'static u32 = &meh(); //~ ERROR does not live long enough let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); - //~^ does not live long enough + //~^ ERROR does not live long enough } diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr index b9856d37b0ee1..b3d7ba3e5c47a 100644 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr @@ -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(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough -LL | //~^ does not live long enough +LL | //~^ ERROR does not live long enough LL | } | - temporary value only lives until here | diff --git a/src/test/ui/consts/const-eval/issue-52443.stderr b/src/test/ui/consts/const-eval/issue-52443.stderr deleted file mode 100644 index 3a145ba78d9b1..0000000000000 --- a/src/test/ui/consts/const-eval/issue-52443.stderr +++ /dev/null @@ -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 `>::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`. diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.nll.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail.nll.stderr new file mode 100644 index 0000000000000..b8e2d6a96c509 --- /dev/null +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.nll.stderr @@ -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`. diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs index 19db07dd330ae..9b03ddd189168 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass - #![feature(const_fn, const_fn_union)] #![deny(const_err)] @@ -29,10 +27,7 @@ const fn bar() -> u8 { } fn main() { - // FIXME(oli-obk): this should panic at runtime - // this will actually compile, but then - // abort at runtime (not panic, hard abort). - let x: &'static u8 = &(bar() + 1); + let x: &'static u8 = &(bar() + 1); //~ ERROR does not live long enough let y = *x; unreachable!(); } diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr new file mode 100644 index 0000000000000..4d80f701bcf04 --- /dev/null +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr @@ -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`. diff --git a/src/test/ui/consts/const-fn-error.stderr b/src/test/ui/consts/const-fn-error.stderr deleted file mode 100644 index cdbf86f42ecc0..0000000000000 --- a/src/test/ui/consts/const-fn-error.stderr +++ /dev/null @@ -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 `>::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`. diff --git a/src/test/ui/consts/min_const_fn/promotion.nll.stderr b/src/test/ui/consts/min_const_fn/promotion.nll.stderr new file mode 100644 index 0000000000000..999c26b535e9c --- /dev/null +++ b/src/test/ui/consts/min_const_fn/promotion.nll.stderr @@ -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 = &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> = &foo5(); //~ ERROR does not live long enough + | ^^^^^^ creates a temporary which is freed while still in use +LL | let a: &'static Option> = &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> = &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`. diff --git a/src/test/ui/consts/min_const_fn/promotion.rs b/src/test/ui/consts/min_const_fn/promotion.rs new file mode 100644 index 0000000000000..cb3bfd74711ca --- /dev/null +++ b/src/test/ui/consts/min_const_fn/promotion.rs @@ -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 { Cell::new(42) } +const fn foo5() -> Option> { Some(Cell::new(42)) } +const fn foo6() -> Option> { 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 = &foo4(); //~ ERROR does not live long enough + let a: &'static Option> = &foo5(); //~ ERROR does not live long enough + let a: &'static Option> = &foo6(); //~ ERROR does not live long enough +} diff --git a/src/test/ui/consts/min_const_fn/promotion.stderr b/src/test/ui/consts/min_const_fn/promotion.stderr new file mode 100644 index 0000000000000..68d584658223f --- /dev/null +++ b/src/test/ui/consts/min_const_fn/promotion.stderr @@ -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 = &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> = &foo5(); //~ ERROR does not live long enough + | ^^^^^^ temporary value does not live long enough +LL | let a: &'static Option> = &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> = &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`. diff --git a/src/test/ui/issues/issue-39559-2.rs b/src/test/ui/issues/issue-39559-2.rs index f01fd1fd8f144..2e480a29774ce 100644 --- a/src/test/ui/issues/issue-39559-2.rs +++ b/src/test/ui/issues/issue-39559-2.rs @@ -23,8 +23,6 @@ impl Dim for Dim3 { fn main() { let array: [usize; Dim3::dim()] //~^ ERROR E0015 - //~| ERROR E0080 = [0; Dim3::dim()]; //~^ ERROR E0015 - //~| ERROR E0080 } diff --git a/src/test/ui/issues/issue-39559-2.stderr b/src/test/ui/issues/issue-39559-2.stderr index 91520a7ec0867..ca9da096b6c16 100644 --- a/src/test/ui/issues/issue-39559-2.stderr +++ b/src/test/ui/issues/issue-39559-2.stderr @@ -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 - --> $DIR/issue-39559-2.rs:27:15 + --> $DIR/issue-39559-2.rs:26:15 | LL | = [0; Dim3::dim()]; | ^^^^^^^^^^^ -error[E0080]: could not evaluate repeat length - --> $DIR/issue-39559-2.rs:27:15 - | -LL | = [0; Dim3::dim()]; - | ^^^^^^^^^^^ calling non-const fn `::dim` - -error[E0080]: could not evaluate constant expression - --> $DIR/issue-39559-2.rs:24:16 - | -LL | let array: [usize; Dim3::dim()] - | ^^^^^^^^-----------^ - | | - | calling non-const fn `::dim` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0015, E0080. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/issues/issue-43105.rs b/src/test/ui/issues/issue-43105.rs index 8a0471135afc4..2bddc443d5baf 100644 --- a/src/test/ui/issues/issue-43105.rs +++ b/src/test/ui/issues/issue-43105.rs @@ -16,7 +16,6 @@ const NUM: u8 = xyz(); fn main() { match 1 { NUM => unimplemented!(), - //~^ ERROR could not evaluate constant pattern _ => unimplemented!(), } } diff --git a/src/test/ui/issues/issue-43105.stderr b/src/test/ui/issues/issue-43105.stderr index 18da9310503ea..67a6008cd8ebc 100644 --- a/src/test/ui/issues/issue-43105.stderr +++ b/src/test/ui/issues/issue-43105.stderr @@ -4,16 +4,6 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | const NUM: u8 = xyz(); | ^^^^^ -error[E0080]: could not evaluate constant pattern - --> $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 +error: aborting due to previous error -Some errors occurred: E0015, E0080. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/rustc-args-required-const.rs b/src/test/ui/rustc-args-required-const.rs index 35b43b4c460a4..15465ac52aa43 100644 --- a/src/test/ui/rustc-args-required-const.rs +++ b/src/test/ui/rustc-args-required-const.rs @@ -27,7 +27,8 @@ const fn baz() -> i32 { fn main() { foo(2); foo(2 + 3); - foo(baz()); + const BAZ: i32 = baz(); + foo(BAZ); let a = 4; foo(A); foo(a); //~ ERROR: argument 1 is required to be a constant diff --git a/src/test/ui/rustc-args-required-const.stderr b/src/test/ui/rustc-args-required-const.stderr index 07f2d880c82b4..efd4c58f152a7 100644 --- a/src/test/ui/rustc-args-required-const.stderr +++ b/src/test/ui/rustc-args-required-const.stderr @@ -1,11 +1,11 @@ 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 | ^^^^^^ 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 | ^^^^^^^^^