Skip to content

Commit 088fc73

Browse files
committed
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
2 parents c67ea54 + c793391 commit 088fc73

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+484
-335
lines changed

src/libcore/mem.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ pub fn forget<T>(t: T) {
285285
/// [alignment]: ./fn.align_of.html
286286
#[inline]
287287
#[stable(feature = "rust1", since = "1.0.0")]
288+
#[cfg_attr(not(stage0), rustc_promotable)]
288289
pub const fn size_of<T>() -> usize {
289290
intrinsics::size_of::<T>()
290291
}
@@ -376,6 +377,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
376377
/// ```
377378
#[inline]
378379
#[stable(feature = "rust1", since = "1.0.0")]
380+
#[cfg_attr(not(stage0), rustc_promotable)]
379381
pub const fn align_of<T>() -> usize {
380382
intrinsics::min_align_of::<T>()
381383
}

src/libcore/num/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ $EndFeature, "
216216
```"),
217217
#[stable(feature = "rust1", since = "1.0.0")]
218218
#[inline]
219+
#[cfg_attr(not(stage0), rustc_promotable)]
219220
pub const fn min_value() -> Self {
220221
!0 ^ ((!0 as $UnsignedT) >> 1) as Self
221222
}
@@ -234,6 +235,7 @@ $EndFeature, "
234235
```"),
235236
#[stable(feature = "rust1", since = "1.0.0")]
236237
#[inline]
238+
#[cfg_attr(not(stage0), rustc_promotable)]
237239
pub const fn max_value() -> Self {
238240
!Self::min_value()
239241
}

src/libcore/ops/range.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ impl<Idx> RangeInclusive<Idx> {
391391
/// ```
392392
#[stable(feature = "inclusive_range_methods", since = "1.27.0")]
393393
#[inline]
394+
#[cfg_attr(not(stage0), rustc_promotable)]
394395
pub const fn new(start: Idx, end: Idx) -> Self {
395396
Self { start, end, is_empty: None }
396397
}

src/libcore/ptr.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
209209
/// ```
210210
#[inline]
211211
#[stable(feature = "rust1", since = "1.0.0")]
212+
#[cfg_attr(not(stage0), rustc_promotable)]
212213
pub const fn null<T>() -> *const T { 0 as *const T }
213214

214215
/// Creates a null mutable raw pointer.
@@ -223,6 +224,7 @@ pub const fn null<T>() -> *const T { 0 as *const T }
223224
/// ```
224225
#[inline]
225226
#[stable(feature = "rust1", since = "1.0.0")]
227+
#[cfg_attr(not(stage0), rustc_promotable)]
226228
pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
227229

228230
/// Swaps the values at two mutable locations of the same type, without

src/libcore/time.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ impl Duration {
109109
/// ```
110110
#[stable(feature = "duration", since = "1.3.0")]
111111
#[inline]
112+
#[cfg_attr(not(stage0), rustc_promotable)]
112113
pub const fn from_secs(secs: u64) -> Duration {
113114
Duration { secs, nanos: 0 }
114115
}
@@ -127,6 +128,7 @@ impl Duration {
127128
/// ```
128129
#[stable(feature = "duration", since = "1.3.0")]
129130
#[inline]
131+
#[cfg_attr(not(stage0), rustc_promotable)]
130132
pub const fn from_millis(millis: u64) -> Duration {
131133
Duration {
132134
secs: millis / MILLIS_PER_SEC,
@@ -148,6 +150,7 @@ impl Duration {
148150
/// ```
149151
#[stable(feature = "duration_from_micros", since = "1.27.0")]
150152
#[inline]
153+
#[cfg_attr(not(stage0), rustc_promotable)]
151154
pub const fn from_micros(micros: u64) -> Duration {
152155
Duration {
153156
secs: micros / MICROS_PER_SEC,
@@ -169,6 +172,7 @@ impl Duration {
169172
/// ```
170173
#[stable(feature = "duration_extras", since = "1.27.0")]
171174
#[inline]
175+
#[cfg_attr(not(stage0), rustc_promotable)]
172176
pub const fn from_nanos(nanos: u64) -> Duration {
173177
Duration {
174178
secs: nanos / (NANOS_PER_SEC as u64),

src/librustc/dep_graph/dep_node.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ define_dep_nodes!( <'tcx>
515515
[] ItemVarianceConstraints(DefId),
516516
[] ItemVariances(DefId),
517517
[] IsConstFn(DefId),
518+
[] IsPromotableConstFn(DefId),
518519
[] IsForeignItem(DefId),
519520
[] TypeParamPredicates { item_id: DefId, param_id: DefId },
520521
[] SizedConstraint(DefId),

src/librustc/ich/impls_syntax.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
130130
level,
131131
feature,
132132
rustc_depr,
133+
promotable,
133134
const_stability
134135
});
135136

src/librustc/middle/stability.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ impl<'a, 'tcx> Index<'tcx> {
441441
feature: Symbol::intern("rustc_private"),
442442
rustc_depr: None,
443443
const_stability: None,
444+
promotable: false,
444445
});
445446
annotator.parent_stab = Some(stability);
446447
}

src/librustc/ty/constness.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use ty::query::Providers;
2+
use hir::def_id::DefId;
3+
use hir;
4+
use ty::TyCtxt;
5+
use syntax_pos::symbol::Symbol;
6+
use hir::map::blocks::FnLikeNode;
7+
use syntax::attr;
8+
use rustc_target::spec::abi;
9+
10+
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
11+
/// Whether the `def_id` counts as const fn in your current crate, considering all active
12+
/// feature gates
13+
pub fn is_const_fn(self, def_id: DefId) -> bool {
14+
self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) {
15+
Some(stab) => match stab.const_stability {
16+
// has a `rustc_const_unstable` attribute, check whether the user enabled the
17+
// corresponding feature gate
18+
Some(feature_name) => self.features()
19+
.declared_lib_features
20+
.iter()
21+
.any(|&(sym, _)| sym == feature_name),
22+
// the function has no stability attribute, it is stable as const fn or the user
23+
// needs to use feature gates to use the function at all
24+
None => true,
25+
},
26+
// functions without stability are either stable user written const fn or the user is
27+
// using feature gates and we thus don't care what they do
28+
None => true,
29+
}
30+
}
31+
32+
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
33+
pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
34+
if self.is_const_fn_raw(def_id) {
35+
self.lookup_stability(def_id)?.const_stability
36+
} else {
37+
None
38+
}
39+
}
40+
41+
/// Returns true if this function must conform to `min_const_fn`
42+
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
43+
if self.features().staged_api {
44+
// some intrinsics are waved through if called inside the
45+
// standard library. Users never need to call them directly
46+
if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
47+
assert!(!self.is_const_fn(def_id));
48+
match &self.item_name(def_id).as_str()[..] {
49+
| "size_of"
50+
| "min_align_of"
51+
| "needs_drop"
52+
=> return true,
53+
_ => {},
54+
}
55+
}
56+
// in order for a libstd function to be considered min_const_fn
57+
// it needs to be stable and have no `rustc_const_unstable` attribute
58+
match self.lookup_stability(def_id) {
59+
// stable functions with unstable const fn aren't `min_const_fn`
60+
Some(&attr::Stability { const_stability: Some(_), .. }) => false,
61+
// unstable functions don't need to conform
62+
Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
63+
// everything else needs to conform, because it would be callable from
64+
// other `min_const_fn` functions
65+
_ => true,
66+
}
67+
} else {
68+
// users enabling the `const_fn` can do what they want
69+
!self.sess.features_untracked().const_fn
70+
}
71+
}
72+
}
73+
74+
75+
pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
76+
/// only checks whether the function has a `const` modifier
77+
fn is_const_fn_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
78+
let node_id = tcx.hir.as_local_node_id(def_id)
79+
.expect("Non-local call to local provider is_const_fn");
80+
81+
if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
82+
fn_like.constness() == hir::Constness::Const
83+
} else {
84+
false
85+
}
86+
}
87+
88+
fn is_promotable_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
89+
tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) {
90+
Some(stab) => {
91+
if cfg!(debug_assertions) && stab.promotable {
92+
let sig = tcx.fn_sig(def_id);
93+
assert_eq!(
94+
sig.unsafety(),
95+
hir::Unsafety::Normal,
96+
"don't mark const unsafe fns as promotable",
97+
// https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
98+
);
99+
}
100+
stab.promotable
101+
},
102+
None => false,
103+
}
104+
}
105+
106+
*providers = Providers {
107+
is_const_fn_raw,
108+
is_promotable_const_fn,
109+
..*providers
110+
};
111+
}

src/librustc/ty/context.rs

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,38 +1134,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
11341134
local as usize == global as usize
11351135
}
11361136

1137-
/// Returns true if this function must conform to `min_const_fn`
1138-
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
1139-
if self.features().staged_api {
1140-
// some intrinsics are waved through if called inside the
1141-
// standard library. Users never need to call them directly
1142-
if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
1143-
assert!(!self.is_const_fn(def_id));
1144-
match &self.item_name(def_id).as_str()[..] {
1145-
| "size_of"
1146-
| "min_align_of"
1147-
| "needs_drop"
1148-
=> return true,
1149-
_ => {},
1150-
}
1151-
}
1152-
// in order for a libstd function to be considered min_const_fn
1153-
// it needs to be stable and have no `rustc_const_unstable` attribute
1154-
match self.lookup_stability(def_id) {
1155-
// stable functions with unstable const fn aren't `min_const_fn`
1156-
Some(&attr::Stability { const_stability: Some(_), .. }) => false,
1157-
// unstable functions don't need to conform
1158-
Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
1159-
// everything else needs to conform, because it would be callable from
1160-
// other `min_const_fn` functions
1161-
_ => true,
1162-
}
1163-
} else {
1164-
// users enabling the `const_fn` can do what they want
1165-
!self.sess.features_untracked().const_fn
1166-
}
1167-
}
1168-
11691137
/// Create a type context and call the closure with a `TyCtxt` reference
11701138
/// to the context. The closure enforces that the type context and any interned
11711139
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid

0 commit comments

Comments
 (0)