Skip to content

Commit 000a630

Browse files
authored
Rollup merge of rust-lang#84547 - RalfJung:max_const_fn, r=oli-obk
Get rid of is_min_const_fn This removes the last trace of the min_const_fn mechanism by making the unsafety checker agnostic about whether something is a min or "non-min" const fn. It seems this distinction was used to disallow some features inside `const fn`, but that is the responsibility of the const checker, not of the unsafety checker. No test seems to even notice this change in the unsafety checker so I guess we are good... r? `@oli-obk` Cc rust-lang#84510
2 parents 25508eb + 588530d commit 000a630

File tree

11 files changed

+102
-142
lines changed

11 files changed

+102
-142
lines changed

compiler/rustc_middle/src/mir/query.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@ use super::{Field, SourceInfo};
1919

2020
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
2121
pub enum UnsafetyViolationKind {
22-
/// Only permitted in regular `fn`s, prohibited in `const fn`s.
22+
/// Unsafe operation outside `unsafe`.
2323
General,
24-
/// Permitted both in `const fn`s and regular `fn`s.
25-
GeneralAndConstFn,
2624
/// Unsafe operation in an `unsafe fn` but outside an `unsafe` block.
2725
/// Has to be handled as a lint for backwards compatibility.
2826
UnsafeFn,

compiler/rustc_mir/src/const_eval/fn_queries.rs

-49
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use rustc_attr as attr;
21
use rustc_hir as hir;
32
use rustc_hir::def_id::{DefId, LocalDefId};
43
use rustc_middle::hir::map::blocks::FnLikeNode;
@@ -34,54 +33,6 @@ pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
3433
}
3534
}
3635

37-
/// Returns `true` if this function must conform to `min_const_fn`
38-
pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
39-
// Bail out if the signature doesn't contain `const`
40-
if !tcx.is_const_fn_raw(def_id) {
41-
return false;
42-
}
43-
44-
if tcx.features().staged_api {
45-
// In order for a libstd function to be considered min_const_fn
46-
// it needs to be stable and have no `rustc_const_unstable` attribute.
47-
match tcx.lookup_const_stability(def_id) {
48-
// `rustc_const_unstable` functions don't need to conform.
49-
Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
50-
None => {
51-
if let Some(stab) = tcx.lookup_stability(def_id) {
52-
if stab.level.is_stable() {
53-
tcx.sess.delay_span_bug(
54-
tcx.def_span(def_id),
55-
"stable const functions must have either `rustc_const_stable` or \
56-
`rustc_const_unstable` attribute",
57-
);
58-
// While we errored above, because we don't know if we need to conform, we
59-
// err on the "safe" side and require min_const_fn.
60-
true
61-
} else {
62-
// Unstable functions need not conform to min_const_fn.
63-
false
64-
}
65-
} else {
66-
// Internal functions are forced to conform to min_const_fn.
67-
// Annotate the internal function with a const stability attribute if
68-
// you need to use unstable features.
69-
// Note: this is an arbitrary choice that does not affect stability or const
70-
// safety or anything, it just changes whether we need to annotate some
71-
// internal functions with `rustc_const_stable` or with `rustc_const_unstable`
72-
true
73-
}
74-
}
75-
// Everything else needs to conform, because it would be callable from
76-
// other `min_const_fn` functions.
77-
_ => true,
78-
}
79-
} else {
80-
// users enabling the `const_fn` feature gate can do what they want
81-
!tcx.features().const_fn
82-
}
83-
}
84-
8536
pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
8637
let parent_id = tcx.hir().get_parent_did(hir_id);
8738
if !parent_id.is_top_level_module() { is_const_impl_raw(tcx, parent_id) } else { false }

compiler/rustc_mir/src/transform/check_unsafety.rs

+17-50
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,10 @@ use rustc_session::lint::Level;
1515

1616
use std::ops::Bound;
1717

18-
use crate::const_eval::is_min_const_fn;
19-
2018
pub struct UnsafetyChecker<'a, 'tcx> {
2119
body: &'a Body<'tcx>,
2220
body_did: LocalDefId,
2321
const_context: bool,
24-
min_const_fn: bool,
2522
violations: Vec<UnsafetyViolation>,
2623
source_info: SourceInfo,
2724
tcx: TyCtxt<'tcx>,
@@ -34,21 +31,15 @@ pub struct UnsafetyChecker<'a, 'tcx> {
3431
impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
3532
fn new(
3633
const_context: bool,
37-
min_const_fn: bool,
3834
body: &'a Body<'tcx>,
3935
body_did: LocalDefId,
4036
tcx: TyCtxt<'tcx>,
4137
param_env: ty::ParamEnv<'tcx>,
4238
) -> Self {
43-
// sanity check
44-
if min_const_fn {
45-
assert!(const_context);
46-
}
4739
Self {
4840
body,
4941
body_did,
5042
const_context,
51-
min_const_fn,
5243
violations: vec![],
5344
source_info: SourceInfo::outermost(body.span),
5445
tcx,
@@ -84,7 +75,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
8475
let sig = func_ty.fn_sig(self.tcx);
8576
if let hir::Unsafety::Unsafe = sig.unsafety() {
8677
self.require_unsafe(
87-
UnsafetyViolationKind::GeneralAndConstFn,
78+
UnsafetyViolationKind::General,
8879
UnsafetyViolationDetails::CallToUnsafeFunction,
8980
)
9081
}
@@ -134,7 +125,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
134125
match self.tcx.layout_scalar_valid_range(def.did) {
135126
(Bound::Unbounded, Bound::Unbounded) => {}
136127
_ => self.require_unsafe(
137-
UnsafetyViolationKind::GeneralAndConstFn,
128+
UnsafetyViolationKind::General,
138129
UnsafetyViolationDetails::InitializingTypeWith,
139130
),
140131
}
@@ -213,7 +204,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
213204
let base_ty = base.ty(self.body, self.tcx).ty;
214205
if base_ty.is_unsafe_ptr() {
215206
self.require_unsafe(
216-
UnsafetyViolationKind::GeneralAndConstFn,
207+
UnsafetyViolationKind::General,
217208
UnsafetyViolationDetails::DerefOfRawPointer,
218209
)
219210
}
@@ -258,15 +249,15 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
258249
);
259250
if !nodrop {
260251
self.require_unsafe(
261-
UnsafetyViolationKind::GeneralAndConstFn,
252+
UnsafetyViolationKind::General,
262253
UnsafetyViolationDetails::AssignToDroppingUnionField,
263254
);
264255
} else {
265256
// write to non-drop union field, safe
266257
}
267258
} else {
268259
self.require_unsafe(
269-
UnsafetyViolationKind::GeneralAndConstFn,
260+
UnsafetyViolationKind::General,
270261
UnsafetyViolationDetails::AccessToUnionField,
271262
)
272263
}
@@ -277,6 +268,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
277268

278269
impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
279270
fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) {
271+
// Violations can turn out to be `UnsafeFn` during analysis, but they should not start out as such.
272+
assert_ne!(kind, UnsafetyViolationKind::UnsafeFn);
273+
280274
let source_info = self.source_info;
281275
let lint_root = self.body.source_scopes[self.source_info.scope]
282276
.local_data
@@ -304,8 +298,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
304298
Safety::Safe => {
305299
for violation in violations {
306300
match violation.kind {
307-
UnsafetyViolationKind::GeneralAndConstFn
308-
| UnsafetyViolationKind::General => {}
301+
UnsafetyViolationKind::General => {}
309302
UnsafetyViolationKind::UnsafeFn => {
310303
bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context")
311304
}
@@ -334,29 +327,6 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
334327
if !violations.is_empty() {
335328
self.used_unsafe.insert(hir_id);
336329
}
337-
// only some unsafety is allowed in const fn
338-
if self.min_const_fn {
339-
for violation in violations {
340-
match violation.kind {
341-
// these unsafe things are stable in const fn
342-
UnsafetyViolationKind::GeneralAndConstFn => {}
343-
// these things are forbidden in const fns
344-
UnsafetyViolationKind::General => {
345-
let mut violation = *violation;
346-
// const fns don't need to be backwards compatible and can
347-
// emit these violations as a hard error instead of a backwards
348-
// compat lint
349-
violation.kind = UnsafetyViolationKind::General;
350-
if !self.violations.contains(&violation) {
351-
self.violations.push(violation)
352-
}
353-
}
354-
UnsafetyViolationKind::UnsafeFn => bug!(
355-
"`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context"
356-
),
357-
}
358-
}
359-
}
360330
true
361331
}
362332
};
@@ -394,7 +364,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
394364
} else {
395365
continue;
396366
};
397-
self.require_unsafe(UnsafetyViolationKind::GeneralAndConstFn, details);
367+
self.require_unsafe(UnsafetyViolationKind::General, details);
398368
}
399369
}
400370
}
@@ -412,7 +382,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
412382
// Is `callee_features` a subset of `calling_features`?
413383
if !callee_features.iter().all(|feature| self_features.contains(feature)) {
414384
self.require_unsafe(
415-
UnsafetyViolationKind::GeneralAndConstFn,
385+
UnsafetyViolationKind::General,
416386
UnsafetyViolationDetails::CallToFunctionWith,
417387
)
418388
}
@@ -494,15 +464,12 @@ fn unsafety_check_result<'tcx>(
494464
let param_env = tcx.param_env(def.did);
495465

496466
let id = tcx.hir().local_def_id_to_hir_id(def.did);
497-
let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) {
498-
hir::BodyOwnerKind::Closure => (false, false),
499-
hir::BodyOwnerKind::Fn => {
500-
(tcx.is_const_fn_raw(def.did.to_def_id()), is_min_const_fn(tcx, def.did.to_def_id()))
501-
}
502-
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false),
467+
let const_context = match tcx.hir().body_owner_kind(id) {
468+
hir::BodyOwnerKind::Closure => false,
469+
hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def.did.to_def_id()),
470+
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => true,
503471
};
504-
let mut checker =
505-
UnsafetyChecker::new(const_context, min_const_fn, body, def.did, tcx, param_env);
472+
let mut checker = UnsafetyChecker::new(const_context, body, def.did, tcx, param_env);
506473
checker.visit_body(&body);
507474

508475
check_unused_unsafe(tcx, def.did, &checker.used_unsafe, &mut checker.inherited_blocks);
@@ -577,7 +544,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
577544
if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" };
578545

579546
match kind {
580-
UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => {
547+
UnsafetyViolationKind::General => {
581548
// once
582549
struct_span_err!(
583550
tcx.sess,

library/alloc/src/raw_vec.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,11 @@ pub struct RawVec<T, A: Allocator = Global> {
5353
}
5454

5555
impl<T> RawVec<T, Global> {
56-
/// HACK(Centril): This exists because `#[unstable]` `const fn`s needn't conform
57-
/// to `min_const_fn` and so they cannot be called in `min_const_fn`s either.
56+
/// HACK(Centril): This exists because stable `const fn` can only call stable `const fn`, so
57+
/// they cannot call `Self::new()`.
5858
///
59-
/// If you change `RawVec<T>::new` or dependencies, please take care to not
60-
/// introduce anything that would truly violate `min_const_fn`.
61-
///
62-
/// NOTE: We could avoid this hack and check conformance with some
63-
/// `#[rustc_force_min_const_fn]` attribute which requires conformance
64-
/// with `min_const_fn` but does not necessarily allow calling it in
65-
/// `stable(...) const fn` / user code not enabling `foo` when
66-
/// `#[rustc_const_unstable(feature = "foo", issue = "01234")]` is present.
59+
/// If you change `RawVec<T>::new` or dependencies, please take care to not introduce anything
60+
/// that would truly const-call something unstable.
6761
pub const NEW: Self = Self::new();
6862

6963
/// Creates the biggest possible `RawVec` (on the system heap)

src/librustdoc/clean/inline.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use rustc_hir::def_id::DefId;
1010
use rustc_hir::Mutability;
1111
use rustc_metadata::creader::LoadedMacro;
1212
use rustc_middle::ty::{self, TyCtxt};
13-
use rustc_mir::const_eval::is_min_const_fn;
1413
use rustc_span::hygiene::MacroKind;
1514
use rustc_span::symbol::{kw, sym, Symbol};
1615
use rustc_span::Span;
@@ -210,7 +209,7 @@ fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Functi
210209
let sig = cx.tcx.fn_sig(did);
211210

212211
let constness =
213-
if is_min_const_fn(cx.tcx, did) { hir::Constness::Const } else { hir::Constness::NotConst };
212+
if cx.tcx.is_const_fn_raw(did) { hir::Constness::Const } else { hir::Constness::NotConst };
214213
let asyncness = cx.tcx.asyncness(did);
215214
let predicates = cx.tcx.predicates_of(did);
216215
let (generics, decl) = clean::enter_impl_trait(cx, |cx| {

src/librustdoc/clean/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc_middle::middle::resolve_lifetime as rl;
2222
use rustc_middle::ty::fold::TypeFolder;
2323
use rustc_middle::ty::subst::{InternalSubsts, Subst};
2424
use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt};
25-
use rustc_mir::const_eval::{is_const_fn, is_min_const_fn, is_unstable_const_fn};
25+
use rustc_mir::const_eval::{is_const_fn, is_unstable_const_fn};
2626
use rustc_span::hygiene::{AstPass, MacroKind};
2727
use rustc_span::symbol::{kw, sym, Ident, Symbol};
2828
use rustc_span::{self, ExpnKind};
@@ -1048,7 +1048,7 @@ impl Clean<Item> for ty::AssocItem {
10481048
ty::TraitContainer(_) => self.defaultness.has_value(),
10491049
};
10501050
if provided {
1051-
let constness = if is_min_const_fn(tcx, self.def_id) {
1051+
let constness = if tcx.is_const_fn_raw(self.def_id) {
10521052
hir::Constness::Const
10531053
} else {
10541054
hir::Constness::NotConst
+18-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
11
// gate-test-const_raw_ptr_to_usize_cast
2+
// revisions: with_feature without_feature
3+
4+
#![cfg_attr(with_feature, feature(const_raw_ptr_to_usize_cast))]
25

36
fn main() {
4-
const X: u32 = unsafe {
5-
main as u32 //~ ERROR casting pointers to integers in constants is unstable
7+
const X: usize = unsafe {
8+
main as usize //[without_feature]~ ERROR casting pointers to integers in constants is unstable
69
};
710
const Y: u32 = 0;
8-
const Z: u32 = unsafe {
9-
&Y as *const u32 as u32 //~ ERROR is unstable
11+
const Z: usize = unsafe {
12+
&Y as *const u32 as usize //[without_feature]~ ERROR is unstable
13+
};
14+
// Cast in `const` without `unsafe` block
15+
const SAFE: usize = {
16+
&Y as *const u32 as usize //[without_feature]~ ERROR is unstable
17+
//[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe
1018
};
1119
}
20+
21+
// Cast in `const fn` without `unsafe` block
22+
const fn test() -> usize {
23+
&0 as *const i32 as usize //[without_feature]~ ERROR is unstable
24+
//[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe
25+
}

src/test/ui/cast/cast-ptr-to-int-const.stderr

-21
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
2+
--> $DIR/cast-ptr-to-int-const.rs:16:9
3+
|
4+
LL | &Y as *const u32 as usize
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
6+
|
7+
= note: casting pointers to integers in constants
8+
9+
error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
10+
--> $DIR/cast-ptr-to-int-const.rs:23:5
11+
|
12+
LL | &0 as *const i32 as usize
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
14+
|
15+
= note: casting pointers to integers in constants
16+
17+
error: aborting due to 2 previous errors
18+
19+
For more information about this error, try `rustc --explain E0133`.

0 commit comments

Comments
 (0)