Skip to content

Commit 1e6c199

Browse files
authored
Rollup merge of #71989 - ecstatic-morse:const-context-enum, r=oli-obk
Use a single enum for the kind of a const context This adds a `ConstContext` enum to the `rustc_hir` crate and method that can be called via `tcx.hir()` to get the `ConstContext` for a given body owner. This arose from discussion in #71824. r? @oli-obk
2 parents a51e004 + e356d5c commit 1e6c199

File tree

8 files changed

+101
-134
lines changed

8 files changed

+101
-134
lines changed

src/librustc_hir/hir.rs

+47
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,53 @@ impl BodyOwnerKind {
12911291
}
12921292
}
12931293

1294+
/// The kind of an item that requires const-checking.
1295+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1296+
pub enum ConstContext {
1297+
/// A `const fn`.
1298+
ConstFn,
1299+
1300+
/// A `static` or `static mut`.
1301+
Static(Mutability),
1302+
1303+
/// A `const`, associated `const`, or other const context.
1304+
///
1305+
/// Other contexts include:
1306+
/// - Array length expressions
1307+
/// - Enum discriminants
1308+
/// - Const generics
1309+
///
1310+
/// For the most part, other contexts are treated just like a regular `const`, so they are
1311+
/// lumped into the same category.
1312+
Const,
1313+
}
1314+
1315+
impl ConstContext {
1316+
/// A description of this const context that can appear between backticks in an error message.
1317+
///
1318+
/// E.g. `const` or `static mut`.
1319+
pub fn keyword_name(self) -> &'static str {
1320+
match self {
1321+
Self::Const => "const",
1322+
Self::Static(Mutability::Not) => "static",
1323+
Self::Static(Mutability::Mut) => "static mut",
1324+
Self::ConstFn => "const fn",
1325+
}
1326+
}
1327+
}
1328+
1329+
/// A colloquial, trivially pluralizable description of this const context for use in error
1330+
/// messages.
1331+
impl fmt::Display for ConstContext {
1332+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1333+
match *self {
1334+
Self::Const => write!(f, "constant"),
1335+
Self::Static(_) => write!(f, "static"),
1336+
Self::ConstFn => write!(f, "constant function"),
1337+
}
1338+
}
1339+
}
1340+
12941341
/// A literal.
12951342
pub type Lit = Spanned<LitKind>;
12961343

src/librustc_middle/hir/map/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,9 @@ impl<'hir> Map<'hir> {
408408
})
409409
}
410410

411+
/// Returns the `BodyOwnerKind` of this `LocalDefId`.
412+
///
413+
/// Panics if `LocalDefId` does not have an associated body.
411414
pub fn body_owner_kind(&self, id: HirId) -> BodyOwnerKind {
412415
match self.get(id) {
413416
Node::Item(&Item { kind: ItemKind::Const(..), .. })
@@ -424,6 +427,23 @@ impl<'hir> Map<'hir> {
424427
}
425428
}
426429

430+
/// Returns the `ConstContext` of the body associated with this `LocalDefId`.
431+
///
432+
/// Panics if `LocalDefId` does not have an associated body.
433+
pub fn body_const_context(&self, did: LocalDefId) -> Option<ConstContext> {
434+
let hir_id = self.local_def_id_to_hir_id(did);
435+
let ccx = match self.body_owner_kind(hir_id) {
436+
BodyOwnerKind::Const => ConstContext::Const,
437+
BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
438+
439+
BodyOwnerKind::Fn if self.tcx.is_constructor(did.to_def_id()) => return None,
440+
BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(did.to_def_id()) => ConstContext::ConstFn,
441+
BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None,
442+
};
443+
444+
Some(ccx)
445+
}
446+
427447
pub fn ty_param_owner(&self, id: HirId) -> HirId {
428448
match self.get(id) {
429449
Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => id,

src/librustc_mir/transform/check_consts/mod.rs

+3-65
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ use rustc_hir::def_id::{DefId, LocalDefId};
99
use rustc_middle::mir;
1010
use rustc_middle::ty::{self, TyCtxt};
1111

12-
use std::fmt;
13-
1412
pub use self::qualifs::Qualif;
1513

1614
mod ops;
@@ -25,7 +23,7 @@ pub struct ConstCx<'mir, 'tcx> {
2523
pub tcx: TyCtxt<'tcx>,
2624
pub def_id: DefId,
2725
pub param_env: ty::ParamEnv<'tcx>,
28-
pub const_kind: Option<ConstKind>,
26+
pub const_kind: Option<hir::ConstContext>,
2927
}
3028

3129
impl ConstCx<'mir, 'tcx> {
@@ -40,78 +38,18 @@ impl ConstCx<'mir, 'tcx> {
4038
body: &'mir mir::Body<'tcx>,
4139
param_env: ty::ParamEnv<'tcx>,
4240
) -> Self {
43-
let const_kind = ConstKind::for_item(tcx, def_id);
44-
41+
let const_kind = tcx.hir().body_const_context(def_id);
4542
ConstCx { body, tcx, def_id: def_id.to_def_id(), param_env, const_kind }
4643
}
4744

4845
/// Returns the kind of const context this `Item` represents (`const`, `static`, etc.).
4946
///
5047
/// Panics if this `Item` is not const.
51-
pub fn const_kind(&self) -> ConstKind {
48+
pub fn const_kind(&self) -> hir::ConstContext {
5249
self.const_kind.expect("`const_kind` must not be called on a non-const fn")
5350
}
5451
}
5552

56-
/// The kinds of items which require compile-time evaluation.
57-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
58-
pub enum ConstKind {
59-
/// A `static` item.
60-
Static,
61-
/// A `static mut` item.
62-
StaticMut,
63-
/// A `const fn` item.
64-
ConstFn,
65-
/// A `const` item or an anonymous constant (e.g. in array lengths).
66-
Const,
67-
}
68-
69-
impl ConstKind {
70-
/// Returns the validation mode for the item with the given `DefId`, or `None` if this item
71-
/// does not require validation (e.g. a non-const `fn`).
72-
pub fn for_item(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<Self> {
73-
use hir::BodyOwnerKind as HirKind;
74-
75-
let hir_id = tcx.hir().as_local_hir_id(def_id);
76-
77-
let mode = match tcx.hir().body_owner_kind(hir_id) {
78-
HirKind::Closure => return None,
79-
80-
// Note: this is deliberately checking for `is_const_fn_raw`, as the `is_const_fn`
81-
// checks take into account the `rustc_const_unstable` attribute combined with enabled
82-
// feature gates. Otherwise, const qualification would _not check_ whether this
83-
// function body follows the `const fn` rules, as an unstable `const fn` would
84-
// be considered "not const". More details are available in issue #67053.
85-
HirKind::Fn if tcx.is_const_fn_raw(def_id) => ConstKind::ConstFn,
86-
HirKind::Fn => return None,
87-
88-
HirKind::Const => ConstKind::Const,
89-
90-
HirKind::Static(hir::Mutability::Not) => ConstKind::Static,
91-
HirKind::Static(hir::Mutability::Mut) => ConstKind::StaticMut,
92-
};
93-
94-
Some(mode)
95-
}
96-
97-
pub fn is_static(self) -> bool {
98-
match self {
99-
ConstKind::Static | ConstKind::StaticMut => true,
100-
ConstKind::ConstFn | ConstKind::Const => false,
101-
}
102-
}
103-
}
104-
105-
impl fmt::Display for ConstKind {
106-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107-
match *self {
108-
ConstKind::Const => write!(f, "constant"),
109-
ConstKind::Static | ConstKind::StaticMut => write!(f, "static"),
110-
ConstKind::ConstFn => write!(f, "constant function"),
111-
}
112-
}
113-
}
114-
11553
/// Returns `true` if this `DefId` points to one of the official `panic` lang items.
11654
pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
11755
Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn()

src/librustc_mir/transform/check_consts/ops.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
//! Concrete error types for all operations which may be invalid in a certain const context.
22
33
use rustc_errors::struct_span_err;
4+
use rustc_hir as hir;
45
use rustc_hir::def_id::DefId;
56
use rustc_session::config::nightly_options;
67
use rustc_session::parse::feature_err;
78
use rustc_span::symbol::sym;
89
use rustc_span::{Span, Symbol};
910

10-
use super::{ConstCx, ConstKind};
11+
use super::ConstCx;
1112

1213
/// An operation that is not *always* allowed in a const context.
1314
pub trait NonConstOp: std::fmt::Debug {
@@ -326,7 +327,7 @@ impl NonConstOp for RawPtrToIntCast {
326327
pub struct StaticAccess;
327328
impl NonConstOp for StaticAccess {
328329
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
329-
ccx.const_kind().is_static()
330+
matches!(ccx.const_kind(), hir::ConstContext::Static(_))
330331
}
331332

332333
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -374,7 +375,7 @@ pub struct UnionAccess;
374375
impl NonConstOp for UnionAccess {
375376
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
376377
// Union accesses are stable in all contexts except `const fn`.
377-
ccx.const_kind() != ConstKind::ConstFn
378+
ccx.const_kind() != hir::ConstContext::ConstFn
378379
|| ccx.tcx.features().enabled(Self::feature_gate().unwrap())
379380
}
380381

src/librustc_mir/transform/check_consts/validation.rs

+12-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
22
33
use rustc_errors::struct_span_err;
4-
use rustc_hir::lang_items;
4+
use rustc_hir::{self as hir, lang_items};
55
use rustc_hir::{def_id::DefId, HirId};
66
use rustc_infer::infer::TyCtxtInferExt;
77
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
@@ -18,7 +18,7 @@ use std::ops::Deref;
1818
use super::ops::{self, NonConstOp};
1919
use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
2020
use super::resolver::FlowSensitiveAnalysis;
21-
use super::{is_lang_panic_fn, ConstCx, ConstKind, Qualif};
21+
use super::{is_lang_panic_fn, ConstCx, Qualif};
2222
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
2323
use crate::dataflow::impls::MaybeMutBorrowedLocals;
2424
use crate::dataflow::{self, Analysis};
@@ -145,17 +145,13 @@ impl Qualifs<'mir, 'tcx> {
145145
// We don't care whether a `const fn` returns a value that is not structurally
146146
// matchable. Functions calls are opaque and always use type-based qualification, so
147147
// this value should never be used.
148-
ConstKind::ConstFn => true,
148+
hir::ConstContext::ConstFn => true,
149149

150150
// If we know that all values of the return type are structurally matchable, there's no
151151
// need to run dataflow.
152-
ConstKind::Const | ConstKind::Static | ConstKind::StaticMut
153-
if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) =>
154-
{
155-
false
156-
}
152+
_ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false,
157153

158-
ConstKind::Const | ConstKind::Static | ConstKind::StaticMut => {
154+
hir::ConstContext::Const | hir::ConstContext::Static(_) => {
159155
let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
160156
.into_engine(ccx.tcx, &ccx.body, ccx.def_id)
161157
.iterate_to_fixpoint()
@@ -198,7 +194,7 @@ impl Validator<'mir, 'tcx> {
198194
pub fn check_body(&mut self) {
199195
let ConstCx { tcx, body, def_id, const_kind, .. } = *self.ccx;
200196

201-
let use_min_const_fn_checks = (const_kind == Some(ConstKind::ConstFn)
197+
let use_min_const_fn_checks = (const_kind == Some(hir::ConstContext::ConstFn)
202198
&& crate::const_eval::is_min_const_fn(tcx, def_id))
203199
&& !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
204200

@@ -222,8 +218,9 @@ impl Validator<'mir, 'tcx> {
222218
self.visit_body(&body);
223219

224220
// Ensure that the end result is `Sync` in a non-thread local `static`.
225-
let should_check_for_sync =
226-
const_kind == Some(ConstKind::Static) && !tcx.is_thread_local_static(def_id);
221+
let should_check_for_sync = const_kind
222+
== Some(hir::ConstContext::Static(hir::Mutability::Not))
223+
&& !tcx.is_thread_local_static(def_id);
227224

228225
if should_check_for_sync {
229226
let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
@@ -351,7 +348,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
351348
let ty = place.ty(self.body, self.tcx).ty;
352349
let is_allowed = match ty.kind {
353350
// Inside a `static mut`, `&mut [...]` is allowed.
354-
ty::Array(..) | ty::Slice(_) if self.const_kind() == ConstKind::StaticMut => {
351+
ty::Array(..) | ty::Slice(_)
352+
if self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut) =>
353+
{
355354
true
356355
}
357356

src/librustc_mir/transform/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ pub fn run_passes(
182182
}
183183

184184
fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
185-
let const_kind = check_consts::ConstKind::for_item(tcx, def_id.expect_local());
185+
let const_kind = tcx.hir().body_const_context(def_id.expect_local());
186186

187187
// No need to const-check a non-const `fn`.
188188
if const_kind.is_none() {

src/librustc_mir/transform/promote_consts.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//! move analysis runs after promotion on broken MIR.
1414
1515
use rustc_ast::ast::LitKind;
16+
use rustc_hir as hir;
1617
use rustc_hir::def_id::DefId;
1718
use rustc_middle::mir::traversal::ReversePostorder;
1819
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
@@ -30,7 +31,7 @@ use std::cell::Cell;
3031
use std::{cmp, iter, mem};
3132

3233
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
33-
use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx, ConstKind};
34+
use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx};
3435
use crate::transform::{MirPass, MirSource};
3536

3637
/// A `MirPass` for promotion.
@@ -352,7 +353,9 @@ impl<'tcx> Validator<'_, 'tcx> {
352353
// In theory, any zero-sized value could be borrowed
353354
// mutably without consequences. However, only &mut []
354355
// is allowed right now, and only in functions.
355-
if self.const_kind == Some(ConstKind::StaticMut) {
356+
if self.const_kind
357+
== Some(hir::ConstContext::Static(hir::Mutability::Mut))
358+
{
356359
// Inside a `static mut`, &mut [...] is also allowed.
357360
match ty.kind {
358361
ty::Array(..) | ty::Slice(_) => {}
@@ -517,7 +520,7 @@ impl<'tcx> Validator<'_, 'tcx> {
517520
if let Some(def_id) = c.check_static_ptr(self.tcx) {
518521
// Only allow statics (not consts) to refer to other statics.
519522
// FIXME(eddyb) does this matter at all for promotion?
520-
let is_static = self.const_kind.map_or(false, |k| k.is_static());
523+
let is_static = matches!(self.const_kind, Some(hir::ConstContext::Static(_)));
521524
if !is_static {
522525
return Err(Unpromotable);
523526
}
@@ -607,7 +610,7 @@ impl<'tcx> Validator<'_, 'tcx> {
607610
// In theory, any zero-sized value could be borrowed
608611
// mutably without consequences. However, only &mut []
609612
// is allowed right now, and only in functions.
610-
if self.const_kind == Some(ConstKind::StaticMut) {
613+
if self.const_kind == Some(hir::ConstContext::Static(hir::Mutability::Mut)) {
611614
// Inside a `static mut`, &mut [...] is also allowed.
612615
match ty.kind {
613616
ty::Array(..) | ty::Slice(_) => {}

0 commit comments

Comments
 (0)