Skip to content

Commit fea32f1

Browse files
committed
Auto merge of #53604 - oli-obk:min_const_fn, r=Centril,varkor
Implement the `min_const_fn` feature gate cc @RalfJung @eddyb r? @Centril implements the feature gate for #53555 I added a hack so the `const_fn` feature gate also enables the `min_const_fn` feature gate. This ensures that nightly users of `const_fn` don't have to touch their code at all. The `min_const_fn` checks are run first, and if they succeeded, the `const_fn` checks are run additionally to ensure we didn't miss anything.
2 parents e6381a7 + 2839f4f commit fea32f1

File tree

83 files changed

+1713
-279
lines changed

Some content is hidden

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

83 files changed

+1713
-279
lines changed

src/liballoc/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@
8888
#![feature(box_syntax)]
8989
#![feature(cfg_target_has_atomic)]
9090
#![feature(coerce_unsized)]
91-
#![feature(const_fn)]
91+
#![cfg_attr(stage0, feature(const_fn))]
92+
#![cfg_attr(not(stage0), feature(min_const_fn))]
9293
#![feature(core_intrinsics)]
9394
#![feature(custom_attribute)]
9495
#![feature(dropck_eyepatch)]

src/liballoc/tests/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
#![feature(allocator_api)]
1212
#![feature(alloc_system)]
1313
#![feature(box_syntax)]
14-
#![feature(const_fn)]
14+
#![cfg_attr(stage0, feature(const_fn))]
15+
#![cfg_attr(not(stage0), feature(min_const_fn))]
1516
#![feature(drain_filter)]
1617
#![feature(exact_size_is_empty)]
1718
#![feature(pattern)]

src/libcore/mem.rs

+28
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,15 @@ pub fn forget<T>(t: T) {
285285
/// [alignment]: ./fn.align_of.html
286286
#[inline]
287287
#[stable(feature = "rust1", since = "1.0.0")]
288+
#[cfg(not(stage0))]
289+
pub const fn size_of<T>() -> usize {
290+
intrinsics::size_of::<T>()
291+
}
292+
293+
#[inline]
294+
#[stable(feature = "rust1", since = "1.0.0")]
295+
#[cfg(stage0)]
296+
/// Ceci n'est pas la documentation
288297
pub const fn size_of<T>() -> usize {
289298
unsafe { intrinsics::size_of::<T>() }
290299
}
@@ -334,6 +343,16 @@ pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
334343
#[inline]
335344
#[stable(feature = "rust1", since = "1.0.0")]
336345
#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
346+
#[cfg(not(stage0))]
347+
pub fn min_align_of<T>() -> usize {
348+
intrinsics::min_align_of::<T>()
349+
}
350+
351+
#[inline]
352+
#[stable(feature = "rust1", since = "1.0.0")]
353+
#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
354+
#[cfg(stage0)]
355+
/// Ceci n'est pas la documentation
337356
pub fn min_align_of<T>() -> usize {
338357
unsafe { intrinsics::min_align_of::<T>() }
339358
}
@@ -376,6 +395,15 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
376395
/// ```
377396
#[inline]
378397
#[stable(feature = "rust1", since = "1.0.0")]
398+
#[cfg(not(stage0))]
399+
pub const fn align_of<T>() -> usize {
400+
intrinsics::min_align_of::<T>()
401+
}
402+
403+
#[inline]
404+
#[stable(feature = "rust1", since = "1.0.0")]
405+
#[cfg(stage0)]
406+
/// Ceci n'est pas la documentation
379407
pub const fn align_of<T>() -> usize {
380408
unsafe { intrinsics::min_align_of::<T>() }
381409
}

src/librustc/ich/impls_mir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ for mir::UnsafetyViolationKind {
6565

6666
match *self {
6767
mir::UnsafetyViolationKind::General => {}
68+
mir::UnsafetyViolationKind::MinConstFn => {}
6869
mir::UnsafetyViolationKind::ExternStatic(lint_node_id) |
6970
mir::UnsafetyViolationKind::BorrowPacked(lint_node_id) => {
7071
lint_node_id.hash_stable(hcx, hasher);

src/librustc/ich/impls_syntax.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
130130
level,
131131
feature,
132132
rustc_depr,
133-
rustc_const_unstable
133+
const_stability
134134
});
135135

136136
impl<'a> HashStable<StableHashingContext<'a>>
@@ -161,7 +161,6 @@ for ::syntax::attr::StabilityLevel {
161161
}
162162

163163
impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason });
164-
impl_stable_hash_for!(struct ::syntax::attr::RustcConstUnstable { feature });
165164

166165

167166
impl_stable_hash_for!(enum ::syntax::attr::IntType {

src/librustc/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242

4343
#![feature(box_patterns)]
4444
#![feature(box_syntax)]
45-
#![feature(const_fn)]
45+
#![cfg_attr(stage0, feature(const_fn))]
46+
#![cfg_attr(not(stage0), feature(min_const_fn))]
4647
#![feature(core_intrinsics)]
4748
#![feature(drain_filter)]
4849
#![cfg_attr(windows, feature(libc))]

src/librustc/middle/stability.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ impl<'a, 'tcx> Index<'tcx> {
440440
},
441441
feature: Symbol::intern("rustc_private"),
442442
rustc_depr: None,
443-
rustc_const_unstable: None,
443+
const_stability: None,
444444
});
445445
annotator.parent_stab = Some(stability);
446446
}

src/librustc/mir/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2430,6 +2430,8 @@ impl Location {
24302430
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
24312431
pub enum UnsafetyViolationKind {
24322432
General,
2433+
/// unsafety is not allowed at all in min const fn
2434+
MinConstFn,
24332435
ExternStatic(ast::NodeId),
24342436
BorrowPacked(ast::NodeId),
24352437
}

src/librustc/ty/context.rs

+31
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,37 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
10991099
local as usize == global as usize
11001100
}
11011101

1102+
/// Returns true if this function must conform to `min_const_fn`
1103+
pub fn is_min_const_fn(self, def_id: DefId) -> bool {
1104+
if self.features().staged_api {
1105+
// some intrinsics are waved through if called inside the
1106+
// standard library. Users never need to call them directly
1107+
if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
1108+
assert!(!self.is_const_fn(def_id));
1109+
match &self.item_name(def_id).as_str()[..] {
1110+
| "size_of"
1111+
| "min_align_of"
1112+
=> return true,
1113+
_ => {},
1114+
}
1115+
}
1116+
// in order for a libstd function to be considered min_const_fn
1117+
// it needs to be stable and have no `rustc_const_unstable` attribute
1118+
match self.lookup_stability(def_id) {
1119+
// stable functions with unstable const fn aren't `min_const_fn`
1120+
Some(&attr::Stability { const_stability: Some(_), .. }) => false,
1121+
// unstable functions don't need to conform
1122+
Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
1123+
// everything else needs to conform, because it would be callable from
1124+
// other `min_const_fn` functions
1125+
_ => true,
1126+
}
1127+
} else {
1128+
// users enabling the `const_fn` can do what they want
1129+
!self.sess.features_untracked().const_fn
1130+
}
1131+
}
1132+
11021133
/// Create a type context and call the closure with a `TyCtxt` reference
11031134
/// to the context. The closure enforces that the type context and any interned
11041135
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid

src/librustc_mir/hair/cx/mod.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use hair::*;
1818

1919
use rustc_data_structures::indexed_vec::Idx;
2020
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
21-
use rustc::hir::map::blocks::FnLikeNode;
2221
use rustc::hir::Node;
2322
use rustc::middle::region;
2423
use rustc::infer::InferCtxt;
@@ -67,10 +66,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
6766
let constness = match body_owner_kind {
6867
hir::BodyOwnerKind::Const |
6968
hir::BodyOwnerKind::Static(_) => hir::Constness::Const,
70-
hir::BodyOwnerKind::Fn => {
71-
let fn_like = FnLikeNode::from_node(infcx.tcx.hir.get(src_id));
72-
fn_like.map_or(hir::Constness::NotConst, |f| f.constness())
73-
}
69+
hir::BodyOwnerKind::Fn => hir::Constness::NotConst,
7470
};
7571

7672
let attrs = tcx.hir.attrs(src_id);
@@ -83,7 +79,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
8379
// Respect -C overflow-checks.
8480
check_overflow |= tcx.sess.overflow_checks();
8581

86-
// Constants and const fn's always need overflow checks.
82+
// Constants always need overflow checks.
8783
check_overflow |= constness == hir::Constness::Const;
8884

8985
let lint_level = lint_level_for_hir_id(tcx, src_id);

src/librustc_mir/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
2323
#![feature(box_patterns)]
2424
#![feature(box_syntax)]
2525
#![feature(crate_visibility_modifier)]
26-
#![feature(const_fn)]
2726
#![feature(core_intrinsics)]
2827
#![feature(decl_macro)]
2928
#![cfg_attr(stage0, feature(macro_vis_matcher))]

src/librustc_mir/transform/check_unsafety.rs

+28-5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use util;
2828

2929
pub struct UnsafetyChecker<'a, 'tcx: 'a> {
3030
mir: &'a Mir<'tcx>,
31+
min_const_fn: bool,
3132
source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
3233
violations: Vec<UnsafetyViolation>,
3334
source_info: SourceInfo,
@@ -38,12 +39,16 @@ pub struct UnsafetyChecker<'a, 'tcx: 'a> {
3839
}
3940

4041
impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> {
41-
fn new(mir: &'a Mir<'tcx>,
42-
source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
43-
tcx: TyCtxt<'a, 'tcx, 'tcx>,
44-
param_env: ty::ParamEnv<'tcx>) -> Self {
42+
fn new(
43+
min_const_fn: bool,
44+
mir: &'a Mir<'tcx>,
45+
source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
46+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
47+
param_env: ty::ParamEnv<'tcx>,
48+
) -> Self {
4549
Self {
4650
mir,
51+
min_const_fn,
4752
source_scope_local_data,
4853
violations: vec![],
4954
source_info: SourceInfo {
@@ -269,14 +274,22 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
269274
fn register_violations(&mut self,
270275
violations: &[UnsafetyViolation],
271276
unsafe_blocks: &[(ast::NodeId, bool)]) {
277+
if self.min_const_fn {
278+
for violation in violations {
279+
let mut violation = violation.clone();
280+
violation.kind = UnsafetyViolationKind::MinConstFn;
281+
if !self.violations.contains(&violation) {
282+
self.violations.push(violation)
283+
}
284+
}
285+
}
272286
let within_unsafe = match self.source_scope_local_data[self.source_info.scope].safety {
273287
Safety::Safe => {
274288
for violation in violations {
275289
if !self.violations.contains(violation) {
276290
self.violations.push(violation.clone())
277291
}
278292
}
279-
280293
false
281294
}
282295
Safety::BuiltinUnsafe | Safety::FnUnsafe => true,
@@ -369,6 +382,7 @@ fn unsafety_check_result<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
369382

370383
let param_env = tcx.param_env(def_id);
371384
let mut checker = UnsafetyChecker::new(
385+
tcx.is_const_fn(def_id) && tcx.is_min_const_fn(def_id),
372386
mir, source_scope_local_data, tcx, param_env);
373387
checker.visit_mir(mir);
374388

@@ -478,6 +492,15 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
478492
.note(&details.as_str()[..])
479493
.emit();
480494
}
495+
UnsafetyViolationKind::MinConstFn => {
496+
tcx.sess.struct_span_err(
497+
source_info.span,
498+
&format!("{} is unsafe and unsafe operations \
499+
are not allowed in const fn", description))
500+
.span_label(source_info.span, &description.as_str()[..])
501+
.note(&details.as_str()[..])
502+
.emit();
503+
}
481504
UnsafetyViolationKind::ExternStatic(lint_node_id) => {
482505
tcx.lint_node_note(SAFE_EXTERN_STATICS,
483506
lint_node_id,

src/librustc_mir/transform/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub mod elaborate_drops;
3636
pub mod add_call_guards;
3737
pub mod promote_consts;
3838
pub mod qualify_consts;
39+
mod qualify_min_const_fn;
3940
pub mod remove_noop_landing_pads;
4041
pub mod dump_mir;
4142
pub mod deaggregator;

src/librustc_mir/transform/qualify_consts.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -917,9 +917,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
917917
);
918918
}
919919
} else if let Some(&attr::Stability {
920-
rustc_const_unstable: Some(attr::RustcConstUnstable {
921-
feature: ref feature_name
922-
}),
920+
const_stability: Some(ref feature_name),
923921
.. }) = self.tcx.lookup_stability(def_id) {
924922
if
925923
// feature-gate is not enabled,
@@ -1173,8 +1171,20 @@ impl MirPass for QualifyAndPromoteConstants {
11731171
let (temps, candidates) = {
11741172
let mut qualifier = Qualifier::new(tcx, def_id, mir, mode);
11751173
if mode == Mode::ConstFn {
1176-
// Enforce a constant-like CFG for `const fn`.
1177-
qualifier.qualify_const();
1174+
if tcx.is_min_const_fn(def_id) {
1175+
// enforce `min_const_fn` for stable const fns
1176+
use super::qualify_min_const_fn::is_min_const_fn;
1177+
if let Err((span, err)) = is_min_const_fn(tcx, def_id, mir) {
1178+
tcx.sess.span_err(span, &err);
1179+
} else {
1180+
// this should not produce any errors, but better safe than sorry
1181+
// FIXME(#53819)
1182+
qualifier.qualify_const();
1183+
}
1184+
} else {
1185+
// Enforce a constant-like CFG for `const fn`.
1186+
qualifier.qualify_const();
1187+
}
11781188
} else {
11791189
while let Some((bb, data)) = qualifier.rpo.next() {
11801190
qualifier.visit_basic_block_data(bb, data);

0 commit comments

Comments
 (0)