Skip to content

Commit ed6c7ef

Browse files
Use enum for status of non-const ops
1 parent 9b41541 commit ed6c7ef

File tree

1 file changed

+61
-51
lines changed
  • compiler/rustc_mir/src/transform/check_consts

1 file changed

+61
-51
lines changed

compiler/rustc_mir/src/transform/check_consts/ops.rs

Lines changed: 61 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,32 @@ use super::ConstCx;
1414
pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
1515
debug!("illegal_op: op={:?}", op);
1616

17-
if op.is_allowed_in_item(ccx) {
18-
return;
19-
}
17+
let gate = match op.status_in_item(ccx) {
18+
Status::Allowed => return,
19+
Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => return,
20+
Status::Unstable(gate) => Some(gate),
21+
Status::Forbidden => None,
22+
};
2023

2124
if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
22-
ccx.tcx.sess.miri_unleashed_feature(span, O::feature_gate());
25+
ccx.tcx.sess.miri_unleashed_feature(span, gate);
2326
return;
2427
}
2528

2629
op.emit_error(ccx, span);
2730
}
2831

32+
pub enum Status {
33+
Allowed,
34+
Unstable(Symbol),
35+
Forbidden,
36+
}
37+
2938
/// An operation that is not *always* allowed in a const context.
3039
pub trait NonConstOp: std::fmt::Debug {
31-
/// Returns the `Symbol` corresponding to the feature gate that would enable this operation,
32-
/// or `None` if such a feature gate does not exist.
33-
fn feature_gate() -> Option<Symbol> {
34-
None
35-
}
36-
37-
/// Returns `true` if this operation is allowed in the given item.
38-
///
39-
/// This check should assume that we are not in a non-const `fn`, where all operations are
40-
/// legal.
41-
///
42-
/// By default, it returns `true` if and only if this operation has a corresponding feature
43-
/// gate and that gate is enabled.
44-
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
45-
Self::feature_gate().map_or(false, |gate| ccx.tcx.features().enabled(gate))
40+
/// Returns an enum indicating whether this operation is allowed within the given item.
41+
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
42+
Status::Forbidden
4643
}
4744

4845
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -53,9 +50,13 @@ pub trait NonConstOp: std::fmt::Debug {
5350
"{} contains unimplemented expression type",
5451
ccx.const_kind()
5552
);
56-
if let Some(feat) = Self::feature_gate() {
57-
err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feat));
53+
54+
if let Status::Unstable(gate) = self.status_in_item(ccx) {
55+
if !ccx.tcx.features().enabled(gate) && nightly_options::is_nightly_build() {
56+
err.help(&format!("add `#![feature({})]` to the crate attributes to enable", gate));
57+
}
5858
}
59+
5960
if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
6061
err.note(
6162
"A function call isn't allowed in the const's initialization expression \
@@ -182,14 +183,13 @@ impl NonConstOp for CellBorrow {
182183
#[derive(Debug)]
183184
pub struct MutBorrow;
184185
impl NonConstOp for MutBorrow {
185-
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
186-
// Forbid everywhere except in const fn
187-
ccx.const_kind() == hir::ConstContext::ConstFn
188-
&& ccx.tcx.features().enabled(Self::feature_gate().unwrap())
189-
}
190-
191-
fn feature_gate() -> Option<Symbol> {
192-
Some(sym::const_mut_refs)
186+
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
187+
// Forbid everywhere except in const fn with a feature gate
188+
if ccx.const_kind() == hir::ConstContext::ConstFn {
189+
Status::Unstable(sym::const_mut_refs)
190+
} else {
191+
Status::Forbidden
192+
}
193193
}
194194

195195
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -201,15 +201,16 @@ impl NonConstOp for MutBorrow {
201201
&format!("mutable references are not allowed in {}s", ccx.const_kind()),
202202
)
203203
} else {
204-
struct_span_err!(
204+
let mut err = struct_span_err!(
205205
ccx.tcx.sess,
206206
span,
207207
E0764,
208208
"mutable references are not allowed in {}s",
209209
ccx.const_kind(),
210-
)
210+
);
211+
err.span_label(span, format!("`&mut` is only allowed in `const fn`"));
212+
err
211213
};
212-
err.span_label(span, "`&mut` is only allowed in `const fn`".to_string());
213214
if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
214215
err.note(
215216
"References in statics and constants may only refer \
@@ -226,11 +227,17 @@ impl NonConstOp for MutBorrow {
226227
}
227228
}
228229

230+
// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues.
229231
#[derive(Debug)]
230232
pub struct MutAddressOf;
231233
impl NonConstOp for MutAddressOf {
232-
fn feature_gate() -> Option<Symbol> {
233-
Some(sym::const_mut_refs)
234+
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
235+
// Forbid everywhere except in const fn with a feature gate
236+
if ccx.const_kind() == hir::ConstContext::ConstFn {
237+
Status::Unstable(sym::const_mut_refs)
238+
} else {
239+
Status::Forbidden
240+
}
234241
}
235242

236243
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -247,16 +254,16 @@ impl NonConstOp for MutAddressOf {
247254
#[derive(Debug)]
248255
pub struct MutDeref;
249256
impl NonConstOp for MutDeref {
250-
fn feature_gate() -> Option<Symbol> {
251-
Some(sym::const_mut_refs)
257+
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
258+
Status::Unstable(sym::const_mut_refs)
252259
}
253260
}
254261

255262
#[derive(Debug)]
256263
pub struct Panic;
257264
impl NonConstOp for Panic {
258-
fn feature_gate() -> Option<Symbol> {
259-
Some(sym::const_panic)
265+
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
266+
Status::Unstable(sym::const_panic)
260267
}
261268

262269
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -289,8 +296,8 @@ impl NonConstOp for RawPtrComparison {
289296
#[derive(Debug)]
290297
pub struct RawPtrDeref;
291298
impl NonConstOp for RawPtrDeref {
292-
fn feature_gate() -> Option<Symbol> {
293-
Some(sym::const_raw_ptr_deref)
299+
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
300+
Status::Unstable(sym::const_raw_ptr_deref)
294301
}
295302

296303
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -307,8 +314,8 @@ impl NonConstOp for RawPtrDeref {
307314
#[derive(Debug)]
308315
pub struct RawPtrToIntCast;
309316
impl NonConstOp for RawPtrToIntCast {
310-
fn feature_gate() -> Option<Symbol> {
311-
Some(sym::const_raw_ptr_to_usize_cast)
317+
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
318+
Status::Unstable(sym::const_raw_ptr_to_usize_cast)
312319
}
313320

314321
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -326,8 +333,12 @@ impl NonConstOp for RawPtrToIntCast {
326333
#[derive(Debug)]
327334
pub struct StaticAccess;
328335
impl NonConstOp for StaticAccess {
329-
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
330-
matches!(ccx.const_kind(), hir::ConstContext::Static(_))
336+
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
337+
if let hir::ConstContext::Static(_) = ccx.const_kind() {
338+
Status::Allowed
339+
} else {
340+
Status::Forbidden
341+
}
331342
}
332343

333344
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -371,14 +382,13 @@ impl NonConstOp for ThreadLocalAccess {
371382
#[derive(Debug)]
372383
pub struct UnionAccess;
373384
impl NonConstOp for UnionAccess {
374-
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
385+
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
375386
// Union accesses are stable in all contexts except `const fn`.
376-
ccx.const_kind() != hir::ConstContext::ConstFn
377-
|| ccx.tcx.features().enabled(Self::feature_gate().unwrap())
378-
}
379-
380-
fn feature_gate() -> Option<Symbol> {
381-
Some(sym::const_fn_union)
387+
if ccx.const_kind() != hir::ConstContext::ConstFn {
388+
Status::Allowed
389+
} else {
390+
Status::Unstable(sym::const_fn_union)
391+
}
382392
}
383393

384394
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {

0 commit comments

Comments
 (0)