]>
Commit | Line | Data |
---|---|---|
1b1a35ee XL |
1 | //! Check the bodies of `const`s, `static`s and `const fn`s for illegal operations. |
2 | //! | |
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. | |
6 | ||
7 | use rustc_attr as attr; | |
8 | use rustc_hir as hir; | |
9 | use rustc_hir::def_id::{DefId, LocalDefId}; | |
10 | use rustc_middle::mir; | |
11 | use rustc_middle::ty::{self, TyCtxt}; | |
94222f64 | 12 | use rustc_span::{sym, Symbol}; |
1b1a35ee XL |
13 | |
14 | pub use self::qualifs::Qualif; | |
15 | ||
94222f64 | 16 | pub mod check; |
1b1a35ee XL |
17 | mod ops; |
18 | pub mod post_drop_elaboration; | |
19 | pub mod qualifs; | |
20 | mod resolver; | |
1b1a35ee XL |
21 | |
22 | /// Information about the item currently being const-checked, as well as a reference to the global | |
23 | /// context. | |
24 | pub struct ConstCx<'mir, 'tcx> { | |
25 | pub body: &'mir mir::Body<'tcx>, | |
26 | pub tcx: TyCtxt<'tcx>, | |
1b1a35ee XL |
27 | pub param_env: ty::ParamEnv<'tcx>, |
28 | pub const_kind: Option<hir::ConstContext>, | |
29 | } | |
30 | ||
31 | impl ConstCx<'mir, 'tcx> { | |
29967ef6 XL |
32 | pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self { |
33 | let def_id = body.source.def_id().expect_local(); | |
1b1a35ee | 34 | let param_env = tcx.param_env(def_id); |
29967ef6 | 35 | Self::new_with_param_env(tcx, body, param_env) |
1b1a35ee XL |
36 | } |
37 | ||
38 | pub fn new_with_param_env( | |
39 | tcx: TyCtxt<'tcx>, | |
1b1a35ee XL |
40 | body: &'mir mir::Body<'tcx>, |
41 | param_env: ty::ParamEnv<'tcx>, | |
42 | ) -> Self { | |
29967ef6 XL |
43 | let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local()); |
44 | ConstCx { body, tcx, param_env, const_kind } | |
45 | } | |
46 | ||
47 | pub fn def_id(&self) -> LocalDefId { | |
48 | self.body.source.def_id().expect_local() | |
1b1a35ee XL |
49 | } |
50 | ||
51 | /// Returns the kind of const context this `Item` represents (`const`, `static`, etc.). | |
52 | /// | |
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") | |
56 | } | |
57 | ||
58 | pub fn is_const_stable_const_fn(&self) -> bool { | |
59 | self.const_kind == Some(hir::ConstContext::ConstFn) | |
60 | && self.tcx.features().staged_api | |
29967ef6 | 61 | && is_const_stable_const_fn(self.tcx, self.def_id().to_def_id()) |
1b1a35ee XL |
62 | } |
63 | ||
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. | |
67 | // | |
68 | // FIXME: Is this still an issue? | |
69 | let hir_map = self.tcx.hir(); | |
29967ef6 | 70 | let hir_id = hir_map.local_def_id_to_hir_id(self.def_id()); |
1b1a35ee XL |
71 | hir_map.fn_sig_by_hir_id(hir_id) |
72 | } | |
73 | } | |
74 | ||
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 { | |
29967ef6 XL |
77 | Some(def_id) == tcx.lang_items().panic_fn() |
78 | || Some(def_id) == tcx.lang_items().panic_str() | |
c295e0f8 | 79 | || Some(def_id) == tcx.lang_items().panic_display() |
29967ef6 | 80 | || Some(def_id) == tcx.lang_items().begin_panic_fn() |
94222f64 XL |
81 | || Some(def_id) == tcx.lang_items().panic_fmt() |
82 | || Some(def_id) == tcx.lang_items().begin_panic_fmt() | |
1b1a35ee XL |
83 | } |
84 | ||
c295e0f8 XL |
85 | /// Returns `true` if this `DefId` points to one of the lang items that will be handled differently |
86 | /// in const_eval. | |
87 | pub fn is_lang_special_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { | |
88 | // We can allow calls to these functions because `hook_special_const_fn` in | |
89 | // `const_eval/machine.rs` ensures the calls are handled specially. | |
90 | // Keep in sync with what that function handles! | |
91 | is_lang_panic_fn(tcx, def_id) || Some(def_id) == tcx.lang_items().const_eval_select() | |
92 | } | |
93 | ||
29967ef6 XL |
94 | pub fn rustc_allow_const_fn_unstable( |
95 | tcx: TyCtxt<'tcx>, | |
96 | def_id: DefId, | |
97 | feature_gate: Symbol, | |
98 | ) -> bool { | |
1b1a35ee | 99 | let attrs = tcx.get_attrs(def_id); |
6a06907d | 100 | attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate) |
1b1a35ee XL |
101 | } |
102 | ||
103 | // Returns `true` if the given `const fn` is "const-stable". | |
104 | // | |
105 | // Panics if the given `DefId` does not refer to a `const fn`. | |
106 | // | |
107 | // Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable" | |
108 | // functions can be called in a const-context by users of the stable compiler. "const-stable" | |
109 | // functions are subject to more stringent restrictions than "const-unstable" functions: They | |
110 | // cannot use unstable features and can only call other "const-stable" functions. | |
111 | pub fn is_const_stable_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { | |
112 | use attr::{ConstStability, Stability, StabilityLevel}; | |
113 | ||
94222f64 XL |
114 | // A default body marked const is not const-stable because const |
115 | // trait fns currently cannot be const-stable. We shouldn't | |
116 | // restrict default bodies to only call const-stable functions. | |
117 | if tcx.has_attr(def_id, sym::default_method_body_is_const) { | |
118 | return false; | |
119 | } | |
120 | ||
1b1a35ee XL |
121 | // Const-stability is only relevant for `const fn`. |
122 | assert!(tcx.is_const_fn_raw(def_id)); | |
123 | ||
124 | // Functions with `#[rustc_const_unstable]` are const-unstable. | |
125 | match tcx.lookup_const_stability(def_id) { | |
126 | Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false, | |
127 | Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true, | |
128 | None => {} | |
129 | } | |
130 | ||
131 | // Functions with `#[unstable]` are const-unstable. | |
132 | // | |
133 | // FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability | |
134 | // attributes. `#[unstable]` should be irrelevant. | |
135 | if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) = | |
136 | tcx.lookup_stability(def_id) | |
137 | { | |
138 | return false; | |
139 | } | |
140 | ||
141 | true | |
142 | } |