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
|
/// [alignment]: ./fn.align_of.html
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||||
pub const fn size_of<T>() -> usize {
|
pub const fn size_of<T>() -> usize {
|
||||||
intrinsics::size_of::<T>()
|
intrinsics::size_of::<T>()
|
||||||
}
|
}
|
||||||
|
@ -376,6 +377,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||||
pub const fn align_of<T>() -> usize {
|
pub const fn align_of<T>() -> usize {
|
||||||
intrinsics::min_align_of::<T>()
|
intrinsics::min_align_of::<T>()
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,6 +216,7 @@ $EndFeature, "
|
||||||
```"),
|
```"),
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||||
pub const fn min_value() -> Self {
|
pub const fn min_value() -> Self {
|
||||||
!0 ^ ((!0 as $UnsignedT) >> 1) as Self
|
!0 ^ ((!0 as $UnsignedT) >> 1) as Self
|
||||||
}
|
}
|
||||||
|
@ -234,6 +235,7 @@ $EndFeature, "
|
||||||
```"),
|
```"),
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||||
pub const fn max_value() -> Self {
|
pub const fn max_value() -> Self {
|
||||||
!Self::min_value()
|
!Self::min_value()
|
||||||
}
|
}
|
||||||
|
|
|
@ -391,6 +391,7 @@ impl<Idx> RangeInclusive<Idx> {
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "inclusive_range_methods", since = "1.27.0")]
|
#[stable(feature = "inclusive_range_methods", since = "1.27.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||||
pub const fn new(start: Idx, end: Idx) -> Self {
|
pub const fn new(start: Idx, end: Idx) -> Self {
|
||||||
Self { start, end, is_empty: None }
|
Self { start, end, is_empty: None }
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,6 +209,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||||
pub const fn null<T>() -> *const T { 0 as *const T }
|
pub const fn null<T>() -> *const T { 0 as *const T }
|
||||||
|
|
||||||
/// Creates a null mutable raw pointer.
|
/// Creates a null mutable raw pointer.
|
||||||
|
@ -223,6 +224,7 @@ pub const fn null<T>() -> *const T { 0 as *const T }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||||
pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
|
pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
|
||||||
|
|
||||||
/// Swaps the values at two mutable locations of the same type, without
|
/// Swaps the values at two mutable locations of the same type, without
|
||||||
|
|
|
@ -109,6 +109,7 @@ impl Duration {
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "duration", since = "1.3.0")]
|
#[stable(feature = "duration", since = "1.3.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||||
pub const fn from_secs(secs: u64) -> Duration {
|
pub const fn from_secs(secs: u64) -> Duration {
|
||||||
Duration { secs, nanos: 0 }
|
Duration { secs, nanos: 0 }
|
||||||
}
|
}
|
||||||
|
@ -127,6 +128,7 @@ impl Duration {
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "duration", since = "1.3.0")]
|
#[stable(feature = "duration", since = "1.3.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||||
pub const fn from_millis(millis: u64) -> Duration {
|
pub const fn from_millis(millis: u64) -> Duration {
|
||||||
Duration {
|
Duration {
|
||||||
secs: millis / MILLIS_PER_SEC,
|
secs: millis / MILLIS_PER_SEC,
|
||||||
|
@ -148,6 +150,7 @@ impl Duration {
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "duration_from_micros", since = "1.27.0")]
|
#[stable(feature = "duration_from_micros", since = "1.27.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||||
pub const fn from_micros(micros: u64) -> Duration {
|
pub const fn from_micros(micros: u64) -> Duration {
|
||||||
Duration {
|
Duration {
|
||||||
secs: micros / MICROS_PER_SEC,
|
secs: micros / MICROS_PER_SEC,
|
||||||
|
@ -169,6 +172,7 @@ impl Duration {
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "duration_extras", since = "1.27.0")]
|
#[stable(feature = "duration_extras", since = "1.27.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg_attr(not(stage0), rustc_promotable)]
|
||||||
pub const fn from_nanos(nanos: u64) -> Duration {
|
pub const fn from_nanos(nanos: u64) -> Duration {
|
||||||
Duration {
|
Duration {
|
||||||
secs: nanos / (NANOS_PER_SEC as u64),
|
secs: nanos / (NANOS_PER_SEC as u64),
|
||||||
|
|
|
@ -515,6 +515,7 @@ define_dep_nodes!( <'tcx>
|
||||||
[] ItemVarianceConstraints(DefId),
|
[] ItemVarianceConstraints(DefId),
|
||||||
[] ItemVariances(DefId),
|
[] ItemVariances(DefId),
|
||||||
[] IsConstFn(DefId),
|
[] IsConstFn(DefId),
|
||||||
|
[] IsPromotableConstFn(DefId),
|
||||||
[] IsForeignItem(DefId),
|
[] IsForeignItem(DefId),
|
||||||
[] TypeParamPredicates { item_id: DefId, param_id: DefId },
|
[] TypeParamPredicates { item_id: DefId, param_id: DefId },
|
||||||
[] SizedConstraint(DefId),
|
[] SizedConstraint(DefId),
|
||||||
|
|
|
@ -130,6 +130,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
|
||||||
level,
|
level,
|
||||||
feature,
|
feature,
|
||||||
rustc_depr,
|
rustc_depr,
|
||||||
|
promotable,
|
||||||
const_stability
|
const_stability
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -441,6 +441,7 @@ impl<'a, 'tcx> Index<'tcx> {
|
||||||
feature: Symbol::intern("rustc_private"),
|
feature: Symbol::intern("rustc_private"),
|
||||||
rustc_depr: None,
|
rustc_depr: None,
|
||||||
const_stability: None,
|
const_stability: None,
|
||||||
|
promotable: false,
|
||||||
});
|
});
|
||||||
annotator.parent_stab = Some(stability);
|
annotator.parent_stab = Some(stability);
|
||||||
}
|
}
|
||||||
|
|
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
|
local as usize == global as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this function must conform to `min_const_fn`
|
|
||||||
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
|
|
||||||
if self.features().staged_api {
|
|
||||||
// some intrinsics are waved through if called inside the
|
|
||||||
// standard library. Users never need to call them directly
|
|
||||||
if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
|
|
||||||
assert!(!self.is_const_fn(def_id));
|
|
||||||
match &self.item_name(def_id).as_str()[..] {
|
|
||||||
| "size_of"
|
|
||||||
| "min_align_of"
|
|
||||||
| "needs_drop"
|
|
||||||
=> return true,
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// in order for a libstd function to be considered min_const_fn
|
|
||||||
// it needs to be stable and have no `rustc_const_unstable` attribute
|
|
||||||
match self.lookup_stability(def_id) {
|
|
||||||
// stable functions with unstable const fn aren't `min_const_fn`
|
|
||||||
Some(&attr::Stability { const_stability: Some(_), .. }) => false,
|
|
||||||
// unstable functions don't need to conform
|
|
||||||
Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
|
|
||||||
// everything else needs to conform, because it would be callable from
|
|
||||||
// other `min_const_fn` functions
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// users enabling the `const_fn` can do what they want
|
|
||||||
!self.sess.features_untracked().const_fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a type context and call the closure with a `TyCtxt` reference
|
/// Create a type context and call the closure with a `TyCtxt` reference
|
||||||
/// to the context. The closure enforces that the type context and any interned
|
/// to the context. The closure enforces that the type context and any interned
|
||||||
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid
|
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid
|
||||||
|
|
|
@ -109,7 +109,9 @@ impl<'tcx> InstanceDef<'tcx> {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
let codegen_fn_attrs = tcx.codegen_fn_attrs(self.def_id());
|
let codegen_fn_attrs = tcx.codegen_fn_attrs(self.def_id());
|
||||||
codegen_fn_attrs.requests_inline() || tcx.is_const_fn(self.def_id())
|
// need to use `is_const_fn_raw` since we don't really care if the user can use it as a
|
||||||
|
// const fn, just whether the function should be inlined
|
||||||
|
codegen_fn_attrs.requests_inline() || tcx.is_const_fn_raw(self.def_id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,7 @@ pub mod binding;
|
||||||
pub mod cast;
|
pub mod cast;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod codec;
|
pub mod codec;
|
||||||
|
mod constness;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod erase_regions;
|
mod erase_regions;
|
||||||
pub mod fast_reject;
|
pub mod fast_reject;
|
||||||
|
@ -3056,6 +3057,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
||||||
erase_regions::provide(providers);
|
erase_regions::provide(providers);
|
||||||
layout::provide(providers);
|
layout::provide(providers);
|
||||||
util::provide(providers);
|
util::provide(providers);
|
||||||
|
constness::provide(providers);
|
||||||
*providers = ty::query::Providers {
|
*providers = ty::query::Providers {
|
||||||
associated_item,
|
associated_item,
|
||||||
associated_item_def_ids,
|
associated_item_def_ids,
|
||||||
|
|
|
@ -437,7 +437,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::is_object_safe<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> QueryDescription<'tcx> for queries::is_const_fn<'tcx> {
|
impl<'tcx> QueryDescription<'tcx> for queries::is_const_fn_raw<'tcx> {
|
||||||
fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> String {
|
fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> String {
|
||||||
format!("checking if item is const fn: `{}`", tcx.item_path_str(def_id))
|
format!("checking if item is const fn: `{}`", tcx.item_path_str(def_id))
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,8 +160,23 @@ define_queries! { <'tcx>
|
||||||
DefId
|
DefId
|
||||||
) -> Result<DtorckConstraint<'tcx>, NoSolution>,
|
) -> Result<DtorckConstraint<'tcx>, NoSolution>,
|
||||||
|
|
||||||
/// True if this is a const fn
|
/// True if this is a const fn, use the `is_const_fn` to know whether your crate actually
|
||||||
[] fn is_const_fn: IsConstFn(DefId) -> bool,
|
/// sees it as const fn (e.g. the const-fn-ness might be unstable and you might not have
|
||||||
|
/// the feature gate active)
|
||||||
|
///
|
||||||
|
/// DO NOT CALL MANUALLY, it is only meant to cache the base data for the `is_const_fn`
|
||||||
|
/// function
|
||||||
|
[] fn is_const_fn_raw: IsConstFn(DefId) -> bool,
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns true if calls to the function may be promoted
|
||||||
|
///
|
||||||
|
/// This is either because the function is e.g. a tuple-struct or tuple-variant constructor,
|
||||||
|
/// or because it has the `#[rustc_promotable]` attribute. The attribute should be removed
|
||||||
|
/// in the future in favour of some form of check which figures out whether the function
|
||||||
|
/// does not inspect the bits of any of its arguments (so is essentially just a constructor
|
||||||
|
/// function)
|
||||||
|
[] fn is_promotable_const_fn: IsPromotableConstFn(DefId) -> bool,
|
||||||
|
|
||||||
/// True if this is a foreign item (i.e., linked via `extern { ... }`).
|
/// True if this is a foreign item (i.e., linked via `extern { ... }`).
|
||||||
[] fn is_foreign_item: IsForeignItem(DefId) -> bool,
|
[] fn is_foreign_item: IsForeignItem(DefId) -> bool,
|
||||||
|
|
|
@ -1136,7 +1136,8 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
|
||||||
DepKind::FnSignature => { force!(fn_sig, def_id!()); }
|
DepKind::FnSignature => { force!(fn_sig, def_id!()); }
|
||||||
DepKind::CoerceUnsizedInfo => { force!(coerce_unsized_info, def_id!()); }
|
DepKind::CoerceUnsizedInfo => { force!(coerce_unsized_info, def_id!()); }
|
||||||
DepKind::ItemVariances => { force!(variances_of, def_id!()); }
|
DepKind::ItemVariances => { force!(variances_of, def_id!()); }
|
||||||
DepKind::IsConstFn => { force!(is_const_fn, def_id!()); }
|
DepKind::IsConstFn => { force!(is_const_fn_raw, def_id!()); }
|
||||||
|
DepKind::IsPromotableConstFn => { force!(is_promotable_const_fn, def_id!()); }
|
||||||
DepKind::IsForeignItem => { force!(is_foreign_item, def_id!()); }
|
DepKind::IsForeignItem => { force!(is_foreign_item, def_id!()); }
|
||||||
DepKind::SizedConstraint => { force!(adt_sized_constraint, def_id!()); }
|
DepKind::SizedConstraint => { force!(adt_sized_constraint, def_id!()); }
|
||||||
DepKind::DtorckConstraint => { force!(adt_dtorck_constraint, def_id!()); }
|
DepKind::DtorckConstraint => { force!(adt_dtorck_constraint, def_id!()); }
|
||||||
|
|
|
@ -26,7 +26,6 @@ use rustc::ty::{self, TyCtxt};
|
||||||
use rustc::ty::query::Providers;
|
use rustc::ty::query::Providers;
|
||||||
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
|
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
|
||||||
use rustc::hir::map::{DefKey, DefPath, DefPathHash};
|
use rustc::hir::map::{DefKey, DefPath, DefPathHash};
|
||||||
use rustc::hir::map::blocks::FnLikeNode;
|
|
||||||
use rustc::hir::map::definitions::DefPathTable;
|
use rustc::hir::map::definitions::DefPathTable;
|
||||||
use rustc::util::nodemap::DefIdMap;
|
use rustc::util::nodemap::DefIdMap;
|
||||||
use rustc_data_structures::svh::Svh;
|
use rustc_data_structures::svh::Svh;
|
||||||
|
@ -43,7 +42,6 @@ use syntax::parse::source_file_to_stream;
|
||||||
use syntax::symbol::Symbol;
|
use syntax::symbol::Symbol;
|
||||||
use syntax_pos::{Span, NO_EXPANSION, FileName};
|
use syntax_pos::{Span, NO_EXPANSION, FileName};
|
||||||
use rustc_data_structures::bit_set::BitSet;
|
use rustc_data_structures::bit_set::BitSet;
|
||||||
use rustc::hir;
|
|
||||||
|
|
||||||
macro_rules! provide {
|
macro_rules! provide {
|
||||||
(<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident,
|
(<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident,
|
||||||
|
@ -145,7 +143,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
||||||
}
|
}
|
||||||
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
|
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
|
||||||
inherent_impls => { Lrc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
|
inherent_impls => { Lrc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
|
||||||
is_const_fn => { cdata.is_const_fn(def_id.index) }
|
is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) }
|
||||||
is_foreign_item => { cdata.is_foreign_item(def_id.index) }
|
is_foreign_item => { cdata.is_foreign_item(def_id.index) }
|
||||||
describe_def => { cdata.get_def(def_id.index) }
|
describe_def => { cdata.get_def(def_id.index) }
|
||||||
def_span => { cdata.get_span(def_id.index, &tcx.sess) }
|
def_span => { cdata.get_span(def_id.index, &tcx.sess) }
|
||||||
|
@ -264,22 +262,10 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
|
pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
|
||||||
fn is_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
|
|
||||||
let node_id = tcx.hir.as_local_node_id(def_id)
|
|
||||||
.expect("Non-local call to local provider is_const_fn");
|
|
||||||
|
|
||||||
if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
|
|
||||||
fn_like.constness() == hir::Constness::Const
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME(#44234) - almost all of these queries have no sub-queries and
|
// FIXME(#44234) - almost all of these queries have no sub-queries and
|
||||||
// therefore no actual inputs, they're just reading tables calculated in
|
// therefore no actual inputs, they're just reading tables calculated in
|
||||||
// resolve! Does this work? Unsure! That's what the issue is about
|
// resolve! Does this work? Unsure! That's what the issue is about
|
||||||
*providers = Providers {
|
*providers = Providers {
|
||||||
is_const_fn,
|
|
||||||
is_dllimport_foreign_item: |tcx, id| {
|
is_dllimport_foreign_item: |tcx, id| {
|
||||||
tcx.native_library_kind(id) == Some(NativeLibraryKind::NativeUnknown)
|
tcx.native_library_kind(id) == Some(NativeLibraryKind::NativeUnknown)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1114,7 +1114,7 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_const_fn(&self, id: DefIndex) -> bool {
|
crate fn is_const_fn_raw(&self, id: DefIndex) -> bool {
|
||||||
let constness = match self.entry(id).kind {
|
let constness = match self.entry(id).kind {
|
||||||
EntryKind::Method(data) => data.decode(self).fn_data.constness,
|
EntryKind::Method(data) => data.decode(self).fn_data.constness,
|
||||||
EntryKind::Fn(data) => data.decode(self).constness,
|
EntryKind::Fn(data) => data.decode(self).constness,
|
||||||
|
|
|
@ -213,7 +213,6 @@ impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum ConstEvalError {
|
enum ConstEvalError {
|
||||||
NeedsRfc(String),
|
NeedsRfc(String),
|
||||||
NotConst(String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ConstEvalError {
|
impl fmt::Display for ConstEvalError {
|
||||||
|
@ -227,7 +226,6 @@ impl fmt::Display for ConstEvalError {
|
||||||
msg
|
msg
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
NotConst(ref msg) => write!(f, "{}", msg),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,7 +235,6 @@ impl Error for ConstEvalError {
|
||||||
use self::ConstEvalError::*;
|
use self::ConstEvalError::*;
|
||||||
match *self {
|
match *self {
|
||||||
NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants",
|
NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants",
|
||||||
NotConst(_) => "this feature is not compatible with constant evaluation",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,9 +290,6 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
|
||||||
ecx.goto_block(ret)?; // fully evaluated and done
|
ecx.goto_block(ret)?; // fully evaluated and done
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
return Err(
|
|
||||||
ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// This is a const fn. Call it.
|
// This is a const fn. Call it.
|
||||||
Ok(Some(match ecx.load_mir(instance.def) {
|
Ok(Some(match ecx.load_mir(instance.def) {
|
||||||
|
|
|
@ -29,7 +29,6 @@ use rustc::mir::traversal::ReversePostorder;
|
||||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||||
use rustc::middle::lang_items;
|
use rustc::middle::lang_items;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use syntax::attr;
|
|
||||||
use syntax::ast::LitKind;
|
use syntax::ast::LitKind;
|
||||||
use syntax::feature_gate::{UnstableFeatures, feature_err, emit_feature_err, GateIssue};
|
use syntax::feature_gate::{UnstableFeatures, feature_err, emit_feature_err, GateIssue};
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
|
@ -813,7 +812,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||||
|
|
||||||
let fn_ty = func.ty(self.mir, self.tcx);
|
let fn_ty = func.ty(self.mir, self.tcx);
|
||||||
let mut callee_def_id = None;
|
let mut callee_def_id = None;
|
||||||
let (mut is_shuffle, mut is_const_fn) = (false, None);
|
let (mut is_shuffle, mut is_const_fn) = (false, false);
|
||||||
if let ty::FnDef(def_id, _) = fn_ty.sty {
|
if let ty::FnDef(def_id, _) = fn_ty.sty {
|
||||||
callee_def_id = Some(def_id);
|
callee_def_id = Some(def_id);
|
||||||
match self.tcx.fn_sig(def_id).abi() {
|
match self.tcx.fn_sig(def_id).abi() {
|
||||||
|
@ -839,10 +838,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||||
| "unchecked_shr"
|
| "unchecked_shr"
|
||||||
| "add_with_overflow"
|
| "add_with_overflow"
|
||||||
| "sub_with_overflow"
|
| "sub_with_overflow"
|
||||||
| "mul_with_overflow" => is_const_fn = Some(def_id),
|
| "mul_with_overflow"
|
||||||
|
// no need to check feature gates, intrinsics are only callable from the
|
||||||
|
// libstd or with forever unstable feature gates
|
||||||
|
=> is_const_fn = true,
|
||||||
|
// special intrinsic that can be called diretly without an intrinsic
|
||||||
|
// feature gate needs a language feature gate
|
||||||
"transmute" => {
|
"transmute" => {
|
||||||
|
// never promote transmute calls
|
||||||
if self.mode != Mode::Fn {
|
if self.mode != Mode::Fn {
|
||||||
is_const_fn = Some(def_id);
|
is_const_fn = true;
|
||||||
|
// const eval transmute calls only with the feature gate
|
||||||
if !self.tcx.sess.features_untracked().const_transmute {
|
if !self.tcx.sess.features_untracked().const_transmute {
|
||||||
emit_feature_err(
|
emit_feature_err(
|
||||||
&self.tcx.sess.parse_sess, "const_transmute",
|
&self.tcx.sess.parse_sess, "const_transmute",
|
||||||
|
@ -861,8 +867,81 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if self.tcx.is_const_fn(def_id) || self.is_const_panic_fn(def_id) {
|
// in normal functions we only care about promotion
|
||||||
is_const_fn = Some(def_id);
|
if self.mode == Mode::Fn {
|
||||||
|
// never promote const fn calls of
|
||||||
|
// functions without #[rustc_promotable]
|
||||||
|
if self.tcx.is_promotable_const_fn(def_id) {
|
||||||
|
is_const_fn = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// stable const fn or unstable const fns with their feature gate
|
||||||
|
// active
|
||||||
|
if self.tcx.is_const_fn(def_id) {
|
||||||
|
is_const_fn = true;
|
||||||
|
} else if self.is_const_panic_fn(def_id) {
|
||||||
|
// check the const_panic feature gate
|
||||||
|
// FIXME: cannot allow this inside `allow_internal_unstable` because
|
||||||
|
// that would make `panic!` insta stable in constants, since the
|
||||||
|
// macro is marked with the attr
|
||||||
|
if self.tcx.sess.features_untracked().const_panic {
|
||||||
|
is_const_fn = true;
|
||||||
|
} else {
|
||||||
|
// don't allow panics in constants without the feature gate
|
||||||
|
emit_feature_err(
|
||||||
|
&self.tcx.sess.parse_sess,
|
||||||
|
"const_panic",
|
||||||
|
self.span,
|
||||||
|
GateIssue::Language,
|
||||||
|
&format!("panicking in {}s is unstable", self.mode),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) {
|
||||||
|
// check `#[unstable]` const fns or `#[rustc_const_unstable]`
|
||||||
|
// functions without the feature gate active in this crate to report
|
||||||
|
// a better error message than the one below
|
||||||
|
if self.span.allows_unstable() {
|
||||||
|
// `allow_internal_unstable` can make such calls stable
|
||||||
|
is_const_fn = true;
|
||||||
|
} else {
|
||||||
|
let mut err = self.tcx.sess.struct_span_err(self.span,
|
||||||
|
&format!("`{}` is not yet stable as a const fn",
|
||||||
|
self.tcx.item_path_str(def_id)));
|
||||||
|
help!(&mut err,
|
||||||
|
"in Nightly builds, add `#![feature({})]` \
|
||||||
|
to the crate attributes to enable",
|
||||||
|
feature);
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// FIXME(#24111) Remove this check when const fn stabilizes
|
||||||
|
let (msg, note) = if let UnstableFeatures::Disallow =
|
||||||
|
self.tcx.sess.opts.unstable_features {
|
||||||
|
(format!("calls in {}s are limited to \
|
||||||
|
tuple structs and tuple variants",
|
||||||
|
self.mode),
|
||||||
|
Some("a limited form of compile-time function \
|
||||||
|
evaluation is available on a nightly \
|
||||||
|
compiler via `const fn`"))
|
||||||
|
} else {
|
||||||
|
(format!("calls in {}s are limited \
|
||||||
|
to constant functions, \
|
||||||
|
tuple structs and tuple variants",
|
||||||
|
self.mode),
|
||||||
|
None)
|
||||||
|
};
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
self.tcx.sess,
|
||||||
|
self.span,
|
||||||
|
E0015,
|
||||||
|
"{}",
|
||||||
|
msg,
|
||||||
|
);
|
||||||
|
if let Some(note) = note {
|
||||||
|
err.span_note(self.span, note);
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -905,78 +984,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Const fn calls.
|
// non-const fn calls.
|
||||||
if let Some(def_id) = is_const_fn {
|
if !is_const_fn {
|
||||||
// check the const_panic feature gate or
|
|
||||||
// find corresponding rustc_const_unstable feature
|
|
||||||
// FIXME: cannot allow this inside `allow_internal_unstable` because that would make
|
|
||||||
// `panic!` insta stable in constants, since the macro is marked with the attr
|
|
||||||
if self.is_const_panic_fn(def_id) {
|
|
||||||
if self.mode == Mode::Fn {
|
|
||||||
// never promote panics
|
|
||||||
self.qualif = Qualif::NOT_CONST;
|
|
||||||
} else if !self.tcx.sess.features_untracked().const_panic {
|
|
||||||
// don't allow panics in constants without the feature gate
|
|
||||||
emit_feature_err(
|
|
||||||
&self.tcx.sess.parse_sess,
|
|
||||||
"const_panic",
|
|
||||||
self.span,
|
|
||||||
GateIssue::Language,
|
|
||||||
&format!("panicking in {}s is unstable", self.mode),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if let Some(&attr::Stability {
|
|
||||||
const_stability: Some(ref feature_name),
|
|
||||||
.. }) = self.tcx.lookup_stability(def_id) {
|
|
||||||
if
|
|
||||||
// feature-gate is not enabled,
|
|
||||||
!self.tcx.features()
|
|
||||||
.declared_lib_features
|
|
||||||
.iter()
|
|
||||||
.any(|&(ref sym, _)| sym == feature_name) &&
|
|
||||||
|
|
||||||
// this doesn't come from a macro that has #[allow_internal_unstable]
|
|
||||||
!self.span.allows_unstable()
|
|
||||||
{
|
|
||||||
self.qualif = Qualif::NOT_CONST;
|
|
||||||
if self.mode != Mode::Fn {
|
|
||||||
// inside a constant environment, not having the feature gate is
|
|
||||||
// an error
|
|
||||||
let mut err = self.tcx.sess.struct_span_err(self.span,
|
|
||||||
&format!("`{}` is not yet stable as a const fn",
|
|
||||||
self.tcx.item_path_str(def_id)));
|
|
||||||
help!(&mut err,
|
|
||||||
"in Nightly builds, add `#![feature({})]` \
|
|
||||||
to the crate attributes to enable",
|
|
||||||
feature_name);
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.qualif = Qualif::NOT_CONST;
|
self.qualif = Qualif::NOT_CONST;
|
||||||
if self.mode != Mode::Fn {
|
if self.mode != Mode::Fn {
|
||||||
// FIXME(#24111) Remove this check when const fn stabilizes
|
self.tcx.sess.delay_span_bug(
|
||||||
let (msg, note) = if let UnstableFeatures::Disallow =
|
self.span,
|
||||||
self.tcx.sess.opts.unstable_features {
|
"should have reported an error about non-const fn calls in constants",
|
||||||
(format!("calls in {}s are limited to \
|
)
|
||||||
tuple structs and tuple variants",
|
|
||||||
self.mode),
|
|
||||||
Some("a limited form of compile-time function \
|
|
||||||
evaluation is available on a nightly \
|
|
||||||
compiler via `const fn`"))
|
|
||||||
} else {
|
|
||||||
(format!("calls in {}s are limited \
|
|
||||||
to constant functions, \
|
|
||||||
tuple structs and tuple variants",
|
|
||||||
self.mode),
|
|
||||||
None)
|
|
||||||
};
|
|
||||||
let mut err = struct_span_err!(self.tcx.sess, self.span, E0015, "{}", msg);
|
|
||||||
if let Some(note) = note {
|
|
||||||
err.span_note(self.span, note);
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
use rustc::ty::cast::CastKind;
|
use rustc::ty::cast::CastKind;
|
||||||
use rustc::hir::def::{Def, CtorKind};
|
use rustc::hir::def::{Def, CtorKind};
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::hir::map::blocks::FnLikeNode;
|
|
||||||
use rustc::middle::expr_use_visitor as euv;
|
use rustc::middle::expr_use_visitor as euv;
|
||||||
use rustc::middle::mem_categorization as mc;
|
use rustc::middle::mem_categorization as mc;
|
||||||
use rustc::middle::mem_categorization::Categorization;
|
use rustc::middle::mem_categorization::Categorization;
|
||||||
|
@ -38,7 +37,6 @@ use rustc::util::nodemap::{ItemLocalSet, NodeSet};
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::attr;
|
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
use self::Promotability::*;
|
use self::Promotability::*;
|
||||||
use std::ops::{BitAnd, BitAndAssign, BitOr};
|
use std::ops::{BitAnd, BitAndAssign, BitOr};
|
||||||
|
@ -160,41 +158,15 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_const_fn_call(&mut self, def_id: DefId,
|
fn handle_const_fn_call(
|
||||||
ret_ty: Ty<'gcx>, span: Span) -> Promotability {
|
&mut self,
|
||||||
if self.type_promotability(ret_ty) == NotPromotable {
|
def_id: DefId,
|
||||||
return NotPromotable;
|
) -> Promotability {
|
||||||
}
|
if self.tcx.is_promotable_const_fn(def_id) {
|
||||||
|
Promotable
|
||||||
let node_check = if let Some(fn_id) = self.tcx.hir.as_local_node_id(def_id) {
|
|
||||||
FnLikeNode::from_node(self.tcx.hir.get(fn_id)).map_or(false, |fn_like| {
|
|
||||||
fn_like.constness() == hir::Constness::Const
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
self.tcx.is_const_fn(def_id)
|
NotPromotable
|
||||||
};
|
|
||||||
|
|
||||||
if !node_check {
|
|
||||||
return NotPromotable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(&attr::Stability {
|
|
||||||
const_stability: Some(ref feature_name),
|
|
||||||
.. }) = self.tcx.lookup_stability(def_id) {
|
|
||||||
let stable_check =
|
|
||||||
// feature-gate is enabled,
|
|
||||||
self.tcx.features()
|
|
||||||
.declared_lib_features
|
|
||||||
.iter()
|
|
||||||
.any(|&(ref sym, _)| sym == feature_name) ||
|
|
||||||
|
|
||||||
// this comes from a macro that has #[allow_internal_unstable]
|
|
||||||
span.allows_unstable();
|
|
||||||
if !stable_check {
|
|
||||||
return NotPromotable
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Promotable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// While the `ExprUseVisitor` walks, we will identify which
|
/// While the `ExprUseVisitor` walks, we will identify which
|
||||||
|
@ -443,14 +415,10 @@ fn check_expr_kind<'a, 'tcx>(
|
||||||
Def::StructCtor(_, CtorKind::Fn) |
|
Def::StructCtor(_, CtorKind::Fn) |
|
||||||
Def::VariantCtor(_, CtorKind::Fn) |
|
Def::VariantCtor(_, CtorKind::Fn) |
|
||||||
Def::SelfCtor(..) => Promotable,
|
Def::SelfCtor(..) => Promotable,
|
||||||
Def::Fn(did) => {
|
Def::Fn(did) => v.handle_const_fn_call(did),
|
||||||
v.handle_const_fn_call(did, node_ty, e.span)
|
|
||||||
}
|
|
||||||
Def::Method(did) => {
|
Def::Method(did) => {
|
||||||
match v.tcx.associated_item(did).container {
|
match v.tcx.associated_item(did).container {
|
||||||
ty::ImplContainer(_) => {
|
ty::ImplContainer(_) => v.handle_const_fn_call(did),
|
||||||
v.handle_const_fn_call(did, node_ty, e.span)
|
|
||||||
}
|
|
||||||
ty::TraitContainer(_) => NotPromotable,
|
ty::TraitContainer(_) => NotPromotable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -466,16 +434,13 @@ fn check_expr_kind<'a, 'tcx>(
|
||||||
if let Some(def) = v.tables.type_dependent_defs().get(e.hir_id) {
|
if let Some(def) = v.tables.type_dependent_defs().get(e.hir_id) {
|
||||||
let def_id = def.def_id();
|
let def_id = def.def_id();
|
||||||
match v.tcx.associated_item(def_id).container {
|
match v.tcx.associated_item(def_id).container {
|
||||||
ty::ImplContainer(_) => {
|
ty::ImplContainer(_) => method_call_result & v.handle_const_fn_call(def_id),
|
||||||
method_call_result = method_call_result
|
ty::TraitContainer(_) => NotPromotable,
|
||||||
& v.handle_const_fn_call(def_id, node_ty, e.span);
|
}
|
||||||
}
|
|
||||||
ty::TraitContainer(_) => return NotPromotable,
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
v.tcx.sess.delay_span_bug(e.span, "no type-dependent def for method call");
|
v.tcx.sess.delay_span_bug(e.span, "no type-dependent def for method call");
|
||||||
|
NotPromotable
|
||||||
}
|
}
|
||||||
method_call_result
|
|
||||||
}
|
}
|
||||||
hir::ExprKind::Struct(ref _qpath, ref hirvec, ref option_expr) => {
|
hir::ExprKind::Struct(ref _qpath, ref hirvec, ref option_expr) => {
|
||||||
let mut struct_result = Promotable;
|
let mut struct_result = Promotable;
|
||||||
|
|
|
@ -112,6 +112,8 @@ pub struct Stability {
|
||||||
/// `Some` contains the feature gate required to be able to use the function
|
/// `Some` contains the feature gate required to be able to use the function
|
||||||
/// as const fn
|
/// as const fn
|
||||||
pub const_stability: Option<Symbol>,
|
pub const_stability: Option<Symbol>,
|
||||||
|
/// whether the function has a `#[rustc_promotable]` attribute
|
||||||
|
pub promotable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The available stability levels.
|
/// The available stability levels.
|
||||||
|
@ -176,6 +178,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
||||||
let mut stab: Option<Stability> = None;
|
let mut stab: Option<Stability> = None;
|
||||||
let mut rustc_depr: Option<RustcDeprecation> = None;
|
let mut rustc_depr: Option<RustcDeprecation> = None;
|
||||||
let mut rustc_const_unstable: Option<Symbol> = None;
|
let mut rustc_const_unstable: Option<Symbol> = None;
|
||||||
|
let mut promotable = false;
|
||||||
|
|
||||||
'outer: for attr in attrs_iter {
|
'outer: for attr in attrs_iter {
|
||||||
if ![
|
if ![
|
||||||
|
@ -183,6 +186,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
||||||
"rustc_const_unstable",
|
"rustc_const_unstable",
|
||||||
"unstable",
|
"unstable",
|
||||||
"stable",
|
"stable",
|
||||||
|
"rustc_promotable",
|
||||||
].iter().any(|&s| attr.path == s) {
|
].iter().any(|&s| attr.path == s) {
|
||||||
continue // not a stability level
|
continue // not a stability level
|
||||||
}
|
}
|
||||||
|
@ -190,8 +194,12 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
||||||
mark_used(attr);
|
mark_used(attr);
|
||||||
|
|
||||||
let meta = attr.meta();
|
let meta = attr.meta();
|
||||||
|
|
||||||
|
if attr.path == "rustc_promotable" {
|
||||||
|
promotable = true;
|
||||||
|
}
|
||||||
// attributes with data
|
// attributes with data
|
||||||
if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta {
|
else if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta {
|
||||||
let meta = meta.as_ref().unwrap();
|
let meta = meta.as_ref().unwrap();
|
||||||
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
|
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
|
||||||
if item.is_some() {
|
if item.is_some() {
|
||||||
|
@ -329,6 +337,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
||||||
feature,
|
feature,
|
||||||
rustc_depr: None,
|
rustc_depr: None,
|
||||||
const_stability: None,
|
const_stability: None,
|
||||||
|
promotable: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
(None, _, _) => {
|
(None, _, _) => {
|
||||||
|
@ -378,6 +387,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
||||||
feature,
|
feature,
|
||||||
rustc_depr: None,
|
rustc_depr: None,
|
||||||
const_stability: None,
|
const_stability: None,
|
||||||
|
promotable: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
(None, _) => {
|
(None, _) => {
|
||||||
|
@ -420,6 +430,17 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge the const-unstable info into the stability info
|
||||||
|
if promotable {
|
||||||
|
if let Some(ref mut stab) = stab {
|
||||||
|
stab.promotable = true;
|
||||||
|
} else {
|
||||||
|
span_err!(diagnostic, item_sp, E0717,
|
||||||
|
"rustc_promotable attribute must be paired with \
|
||||||
|
either stable or unstable attribute");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stab
|
stab
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -413,4 +413,5 @@ register_diagnostics! {
|
||||||
E0694, // an unknown tool name found in scoped attributes
|
E0694, // an unknown tool name found in scoped attributes
|
||||||
E0703, // invalid ABI
|
E0703, // invalid ABI
|
||||||
E0704, // incorrect visibility restriction
|
E0704, // incorrect visibility restriction
|
||||||
|
E0717, // rustc_promotable without stability attribute
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
|
|
||||||
// compile-flags: -C debug_assertions=yes
|
// compile-flags: -C debug_assertions=yes
|
||||||
|
|
||||||
#![feature(const_fn, libc)]
|
#![stable(feature = "rustc", since = "1.0.0")]
|
||||||
|
#![feature(const_fn, libc, staged_api, rustc_attrs)]
|
||||||
#![allow(const_err)]
|
#![allow(const_err)]
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
@ -23,6 +24,8 @@ use std::env;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
// this will panic in debug mode and overflow in release mode
|
// this will panic in debug mode and overflow in release mode
|
||||||
|
#[stable(feature = "rustc", since = "1.0.0")]
|
||||||
|
#[rustc_promotable]
|
||||||
const fn bar() -> usize { 0 - 1 }
|
const fn bar() -> usize { 0 - 1 }
|
||||||
|
|
||||||
fn foo() {
|
fn foo() {
|
||||||
|
|
|
@ -13,13 +13,15 @@
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
const FIVE: Cell<i32> = Cell::new(5);
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn tuple_field() -> &'static u32 {
|
fn tuple_field() -> &'static u32 {
|
||||||
// This test is MIR-borrowck-only because the old borrowck
|
// This test is MIR-borrowck-only because the old borrowck
|
||||||
// doesn't agree that borrows of "frozen" (i.e. without any
|
// doesn't agree that borrows of "frozen" (i.e. without any
|
||||||
// interior mutability) fields of non-frozen temporaries,
|
// interior mutability) fields of non-frozen temporaries,
|
||||||
// should be promoted, while MIR promotion does promote them.
|
// should be promoted, while MIR promotion does promote them.
|
||||||
&(Cell::new(5), 42).1
|
&(FIVE, 42).1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -15,5 +15,4 @@ fn f(x: usize) -> usize {
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ = [0; f(2)];
|
let _ = [0; f(2)];
|
||||||
//~^ ERROR calls in constants are limited to constant functions
|
//~^ ERROR calls in constants are limited to constant functions
|
||||||
//~| E0080
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,6 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct
|
||||||
LL | let _ = [0; f(2)];
|
LL | let _ = [0; f(2)];
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error[E0080]: could not evaluate repeat length
|
error: aborting due to previous error
|
||||||
--> $DIR/const-call.rs:16:17
|
|
||||||
|
|
|
||||||
LL | let _ = [0; f(2)];
|
|
||||||
| ^^^^ calling non-const fn `f`
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
For more information about this error, try `rustc --explain E0015`.
|
||||||
|
|
||||||
Some errors occurred: E0015, E0080.
|
|
||||||
For more information about an error, try `rustc --explain E0015`.
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ error[E0716]: temporary value dropped while borrowed
|
||||||
|
|
|
|
||||||
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
|
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
|
||||||
LL | //~^ does not live long enough
|
LL | //~^ ERROR does not live long enough
|
||||||
LL | }
|
LL | }
|
||||||
| - temporary value is freed at the end of this statement
|
| - temporary value is freed at the end of this statement
|
||||||
|
|
|
|
||||||
|
|
|
@ -31,5 +31,5 @@ fn a() {
|
||||||
fn main() {
|
fn main() {
|
||||||
let _: &'static u32 = &meh(); //~ ERROR does not live long enough
|
let _: &'static u32 = &meh(); //~ ERROR does not live long enough
|
||||||
let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
|
let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
|
||||||
//~^ does not live long enough
|
//~^ ERROR does not live long enough
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ error[E0597]: borrowed value does not live long enough
|
||||||
|
|
|
|
||||||
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
|
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
|
||||||
LL | //~^ does not live long enough
|
LL | //~^ ERROR does not live long enough
|
||||||
LL | }
|
LL | }
|
||||||
| - temporary value only lives until here
|
| - temporary value only lives until here
|
||||||
|
|
|
|
||||||
|
|
|
@ -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
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-pass
|
|
||||||
|
|
||||||
#![feature(const_fn, const_fn_union)]
|
#![feature(const_fn, const_fn_union)]
|
||||||
|
|
||||||
#![deny(const_err)]
|
#![deny(const_err)]
|
||||||
|
@ -29,10 +27,7 @@ const fn bar() -> u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// FIXME(oli-obk): this should panic at runtime
|
let x: &'static u8 = &(bar() + 1); //~ ERROR does not live long enough
|
||||||
// this will actually compile, but then
|
|
||||||
// abort at runtime (not panic, hard abort).
|
|
||||||
let x: &'static u8 = &(bar() + 1);
|
|
||||||
let y = *x;
|
let y = *x;
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
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() {
|
fn main() {
|
||||||
let array: [usize; Dim3::dim()]
|
let array: [usize; Dim3::dim()]
|
||||||
//~^ ERROR E0015
|
//~^ ERROR E0015
|
||||||
//~| ERROR E0080
|
|
||||||
= [0; Dim3::dim()];
|
= [0; Dim3::dim()];
|
||||||
//~^ ERROR E0015
|
//~^ ERROR E0015
|
||||||
//~| ERROR E0080
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,26 +5,11 @@ LL | let array: [usize; Dim3::dim()]
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||||
--> $DIR/issue-39559-2.rs:27:15
|
--> $DIR/issue-39559-2.rs:26:15
|
||||||
|
|
|
|
||||||
LL | = [0; Dim3::dim()];
|
LL | = [0; Dim3::dim()];
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0080]: could not evaluate repeat length
|
error: aborting due to 2 previous errors
|
||||||
--> $DIR/issue-39559-2.rs:27:15
|
|
||||||
|
|
|
||||||
LL | = [0; Dim3::dim()];
|
|
||||||
| ^^^^^^^^^^^ calling non-const fn `<Dim3 as Dim>::dim`
|
|
||||||
|
|
||||||
error[E0080]: could not evaluate constant expression
|
For more information about this error, try `rustc --explain E0015`.
|
||||||
--> $DIR/issue-39559-2.rs:24:16
|
|
||||||
|
|
|
||||||
LL | let array: [usize; Dim3::dim()]
|
|
||||||
| ^^^^^^^^-----------^
|
|
||||||
| |
|
|
||||||
| calling non-const fn `<Dim3 as Dim>::dim`
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
|
||||||
|
|
||||||
Some errors occurred: E0015, E0080.
|
|
||||||
For more information about an error, try `rustc --explain E0015`.
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ const NUM: u8 = xyz();
|
||||||
fn main() {
|
fn main() {
|
||||||
match 1 {
|
match 1 {
|
||||||
NUM => unimplemented!(),
|
NUM => unimplemented!(),
|
||||||
//~^ ERROR could not evaluate constant pattern
|
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,6 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct
|
||||||
LL | const NUM: u8 = xyz();
|
LL | const NUM: u8 = xyz();
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error[E0080]: could not evaluate constant pattern
|
error: aborting due to previous error
|
||||||
--> $DIR/issue-43105.rs:18:9
|
|
||||||
|
|
|
||||||
LL | const NUM: u8 = xyz();
|
|
||||||
| ----- calling non-const fn `xyz`
|
|
||||||
...
|
|
||||||
LL | NUM => unimplemented!(),
|
|
||||||
| ^^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
For more information about this error, try `rustc --explain E0015`.
|
||||||
|
|
||||||
Some errors occurred: E0015, E0080.
|
|
||||||
For more information about an error, try `rustc --explain E0015`.
|
|
||||||
|
|
|
@ -27,7 +27,8 @@ const fn baz() -> i32 {
|
||||||
fn main() {
|
fn main() {
|
||||||
foo(2);
|
foo(2);
|
||||||
foo(2 + 3);
|
foo(2 + 3);
|
||||||
foo(baz());
|
const BAZ: i32 = baz();
|
||||||
|
foo(BAZ);
|
||||||
let a = 4;
|
let a = 4;
|
||||||
foo(A);
|
foo(A);
|
||||||
foo(a); //~ ERROR: argument 1 is required to be a constant
|
foo(a); //~ ERROR: argument 1 is required to be a constant
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
error: argument 1 is required to be a constant
|
error: argument 1 is required to be a constant
|
||||||
--> $DIR/rustc-args-required-const.rs:33:5
|
--> $DIR/rustc-args-required-const.rs:34:5
|
||||||
|
|
|
|
||||||
LL | foo(a); //~ ERROR: argument 1 is required to be a constant
|
LL | foo(a); //~ ERROR: argument 1 is required to be a constant
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: argument 2 is required to be a constant
|
error: argument 2 is required to be a constant
|
||||||
--> $DIR/rustc-args-required-const.rs:35:5
|
--> $DIR/rustc-args-required-const.rs:36:5
|
||||||
|
|
|
|
||||||
LL | bar(a, a); //~ ERROR: argument 2 is required to be a constant
|
LL | bar(a, a); //~ ERROR: argument 2 is required to be a constant
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue