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, TyCtxt}
;
12 use rustc_span
::{sym, 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 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 /// Returns the function signature of the item being const-checked if it is a `fn` or `const fn`.
65 pub fn fn_sig(&self) -> Option
<&'tcx hir
::FnSig
<'tcx
>> {
66 // Get this from the HIR map instead of a query to avoid cycle errors.
68 // FIXME: Is this still an issue?
69 let hir_map
= self.tcx
.hir();
70 let hir_id
= hir_map
.local_def_id_to_hir_id(self.def_id());
71 hir_map
.fn_sig_by_hir_id(hir_id
)
75 /// Returns `true` if this `DefId` points to one of the official `panic` lang items.
76 pub fn is_lang_panic_fn(tcx
: TyCtxt
<'tcx
>, def_id
: DefId
) -> bool
{
77 // We can allow calls to these functions because `hook_panic_fn` in
78 // `const_eval/machine.rs` ensures the calls are handled specially.
79 // Keep in sync with what that function handles!
80 Some(def_id
) == tcx
.lang_items().panic_fn()
81 || Some(def_id
) == tcx
.lang_items().panic_str()
82 || Some(def_id
) == tcx
.lang_items().begin_panic_fn()
83 || Some(def_id
) == tcx
.lang_items().panic_fmt()
84 || Some(def_id
) == tcx
.lang_items().begin_panic_fmt()
87 pub fn rustc_allow_const_fn_unstable(
92 let attrs
= tcx
.get_attrs(def_id
);
93 attr
::rustc_allow_const_fn_unstable(&tcx
.sess
, attrs
).any(|name
| name
== feature_gate
)
96 // Returns `true` if the given `const fn` is "const-stable".
98 // Panics if the given `DefId` does not refer to a `const fn`.
100 // Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable"
101 // functions can be called in a const-context by users of the stable compiler. "const-stable"
102 // functions are subject to more stringent restrictions than "const-unstable" functions: They
103 // cannot use unstable features and can only call other "const-stable" functions.
104 pub fn is_const_stable_const_fn(tcx
: TyCtxt
<'tcx
>, def_id
: DefId
) -> bool
{
105 use attr
::{ConstStability, Stability, StabilityLevel}
;
107 // A default body marked const is not const-stable because const
108 // trait fns currently cannot be const-stable. We shouldn't
109 // restrict default bodies to only call const-stable functions.
110 if tcx
.has_attr(def_id
, sym
::default_method_body_is_const
) {
114 // Const-stability is only relevant for `const fn`.
115 assert
!(tcx
.is_const_fn_raw(def_id
));
117 // Functions with `#[rustc_const_unstable]` are const-unstable.
118 match tcx
.lookup_const_stability(def_id
) {
119 Some(ConstStability { level: StabilityLevel::Unstable { .. }
, .. }) => return false,
120 Some(ConstStability { level: StabilityLevel::Stable { .. }
, .. }) => return true,
124 // Functions with `#[unstable]` are const-unstable.
126 // FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability
127 // attributes. `#[unstable]` should be irrelevant.
128 if let Some(Stability { level: StabilityLevel::Unstable { .. }
, .. }) =
129 tcx
.lookup_stability(def_id
)