1 //! Check the bodies of `const`s, `static`s and `const fn`s for illegal operations.
3 //! This module will eventually replace the parts of `qualify_consts.rs` that check whether a local
4 //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when
5 //! it finds operations that are invalid in a certain context.
7 use rustc_attr
as attr
;
9 use rustc_hir
::def_id
::{DefId, LocalDefId}
;
10 use rustc_middle
::mir
;
11 use rustc_middle
::ty
::{self, PolyFnSig, TyCtxt}
;
12 use rustc_span
::Symbol
;
14 pub use self::qualifs
::Qualif
;
18 pub mod post_drop_elaboration
;
22 /// Information about the item currently being const-checked, as well as a reference to the global
24 pub struct ConstCx
<'mir
, 'tcx
> {
25 pub body
: &'mir mir
::Body
<'tcx
>,
26 pub tcx
: TyCtxt
<'tcx
>,
27 pub param_env
: ty
::ParamEnv
<'tcx
>,
28 pub const_kind
: Option
<hir
::ConstContext
>,
31 impl<'mir
, 'tcx
> ConstCx
<'mir
, 'tcx
> {
32 pub fn new(tcx
: TyCtxt
<'tcx
>, body
: &'mir mir
::Body
<'tcx
>) -> Self {
33 let def_id
= body
.source
.def_id().expect_local();
34 let param_env
= tcx
.param_env(def_id
);
35 Self::new_with_param_env(tcx
, body
, param_env
)
38 pub fn new_with_param_env(
40 body
: &'mir mir
::Body
<'tcx
>,
41 param_env
: ty
::ParamEnv
<'tcx
>,
43 let const_kind
= tcx
.hir().body_const_context(body
.source
.def_id().expect_local());
44 ConstCx { body, tcx, param_env, const_kind }
47 pub fn def_id(&self) -> LocalDefId
{
48 self.body
.source
.def_id().expect_local()
51 /// Returns the kind of const context this `Item` represents (`const`, `static`, etc.).
53 /// Panics if this `Item` is not const.
54 pub fn const_kind(&self) -> hir
::ConstContext
{
55 self.const_kind
.expect("`const_kind` must not be called on a non-const fn")
58 pub fn is_const_stable_const_fn(&self) -> bool
{
59 self.const_kind
== Some(hir
::ConstContext
::ConstFn
)
60 && self.tcx
.features().staged_api
61 && is_const_stable_const_fn(self.tcx
, self.def_id().to_def_id())
64 fn is_async(&self) -> bool
{
65 self.tcx
.asyncness(self.def_id()).is_async()
68 pub fn fn_sig(&self) -> PolyFnSig
<'tcx
> {
69 let did
= self.def_id().to_def_id();
70 if self.tcx
.is_closure(did
) {
71 let ty
= self.tcx
.type_of(did
).subst_identity();
72 let ty
::Closure(_
, substs
) = ty
.kind() else { bug!("type_of closure not ty::Closure") }
;
73 substs
.as_closure().sig()
75 self.tcx
.fn_sig(did
).subst_identity()
80 pub fn rustc_allow_const_fn_unstable(
85 let attrs
= tcx
.hir().attrs(tcx
.hir().local_def_id_to_hir_id(def_id
));
86 attr
::rustc_allow_const_fn_unstable(&tcx
.sess
, attrs
).any(|name
| name
== feature_gate
)
89 /// Returns `true` if the given `const fn` is "const-stable".
91 /// Panics if the given `DefId` does not refer to a `const fn`.
93 /// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable"
94 /// functions can be called in a const-context by users of the stable compiler. "const-stable"
95 /// functions are subject to more stringent restrictions than "const-unstable" functions: They
96 /// cannot use unstable features and can only call other "const-stable" functions.
97 pub fn is_const_stable_const_fn(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> bool
{
98 // A default body in a `#[const_trait]` is not const-stable because const
99 // trait fns currently cannot be const-stable. We shouldn't
100 // restrict default bodies to only call const-stable functions.
101 if tcx
.is_const_default_method(def_id
) {
105 // Const-stability is only relevant for `const fn`.
106 assert
!(tcx
.is_const_fn_raw(def_id
));
108 // A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs
109 // to is const-stable.
110 match tcx
.lookup_const_stability(def_id
) {
111 Some(stab
) => stab
.is_const_stable(),
112 None
if is_parent_const_stable_trait(tcx
, def_id
) => {
113 // Remove this when `#![feature(const_trait_impl)]` is stabilized,
114 // returning `true` unconditionally.
115 tcx
.sess
.delay_span_bug(
116 tcx
.def_span(def_id
),
117 "trait implementations cannot be const stable yet",
121 None
=> false, // By default, items are not const stable.
125 fn is_parent_const_stable_trait(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> bool
{
126 let local_def_id
= def_id
.expect_local();
127 let hir_id
= tcx
.local_def_id_to_hir_id(local_def_id
);
129 let Some(parent
) = tcx
.hir().opt_parent_id(hir_id
) else { return false }
;
130 let parent_def
= tcx
.hir().get(parent
);
134 hir
::Node
::Item(hir
::Item
{
135 kind
: hir
::ItemKind
::Impl(hir
::Impl { constness: hir::Constness::Const, .. }
),
142 tcx
.lookup_const_stability(parent
.owner
).is_some_and(|stab
| stab
.is_const_stable())