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:
commit
088fc7384c
45 changed files with 484 additions and 335 deletions
|
@ -285,6 +285,7 @@ pub fn forget<T>(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<T>() -> usize {
|
||||
intrinsics::size_of::<T>()
|
||||
}
|
||||
|
@ -376,6 +377,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||
pub const fn align_of<T>() -> usize {
|
||||
intrinsics::min_align_of::<T>()
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -391,6 +391,7 @@ impl<Idx> RangeInclusive<Idx> {
|
|||
/// ```
|
||||
#[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 }
|
||||
}
|
||||
|
|
|
@ -209,6 +209,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||
pub const fn null<T>() -> *const T { 0 as *const T }
|
||||
|
||||
/// Creates a null mutable raw pointer.
|
||||
|
@ -223,6 +224,7 @@ pub const fn null<T>() -> *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<T>() -> *mut T { 0 as *mut T }
|
||||
|
||||
/// Swaps the values at two mutable locations of the same type, without
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -130,6 +130,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
|
|||
level,
|
||||
feature,
|
||||
rustc_depr,
|
||||
promotable,
|
||||
const_stability
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
111
src/librustc/ty/constness.rs
Normal file
111
src/librustc/ty/constness.rs
Normal 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
|
||||
};
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -160,8 +160,23 @@ define_queries! { <'tcx>
|
|||
DefId
|
||||
) -> Result<DtorckConstraint<'tcx>, 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,
|
||||
|
|
|
@ -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!()); }
|
||||
|
|
|
@ -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)
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -213,7 +213,6 @@ impl<'tcx> Into<EvalError<'tcx>> 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) {
|
||||
|
|
|
@ -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",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Symbol>,
|
||||
/// 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<Stability> = None;
|
||||
let mut rustc_depr: Option<RustcDeprecation> = None;
|
||||
let mut rustc_const_unstable: Option<Symbol> = 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<Symbol>| {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -13,13 +13,15 @@
|
|||
|
||||
use std::cell::Cell;
|
||||
|
||||
const FIVE: Cell<i32> = 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() {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 previous error
|
||||
|
||||
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`.
|
||||
|
|
|
@ -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
|
||||
|
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
||||
|
|
|
@ -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`.
|
|
@ -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`.
|
|
@ -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!();
|
||||
}
|
||||
|
|
14
src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr
Normal file
14
src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr
Normal 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`.
|
|
@ -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`.
|
68
src/test/ui/consts/min_const_fn/promotion.nll.stderr
Normal file
68
src/test/ui/consts/min_const_fn/promotion.nll.stderr
Normal 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`.
|
19
src/test/ui/consts/min_const_fn/promotion.rs
Normal file
19
src/test/ui/consts/min_const_fn/promotion.rs
Normal 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
|
||||
}
|
68
src/test/ui/consts/min_const_fn/promotion.stderr
Normal file
68
src/test/ui/consts/min_const_fn/promotion.stderr
Normal 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`.
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 `<Dim3 as Dim>::dim`
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
error[E0080]: could not evaluate constant expression
|
||||
--> $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`.
|
||||
For more information about this error, try `rustc --explain E0015`.
|
||||
|
|
|
@ -16,7 +16,6 @@ const NUM: u8 = xyz();
|
|||
fn main() {
|
||||
match 1 {
|
||||
NUM => unimplemented!(),
|
||||
//~^ ERROR could not evaluate constant pattern
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 previous error
|
||||
|
||||
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`.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
| ^^^^^^^^^
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue