]>
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}; | |
923072b8 | 12 | use rustc_span::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 | ||
a2a8927a | 31 | impl<'mir, 'tcx> 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 | ||
04454e1e FG |
64 | fn is_async(&self) -> bool { |
65 | self.tcx.asyncness(self.def_id()) == hir::IsAsync::Async | |
1b1a35ee XL |
66 | } |
67 | } | |
68 | ||
04454e1e FG |
69 | pub fn rustc_allow_const_fn_unstable( |
70 | tcx: TyCtxt<'_>, | |
71 | def_id: LocalDefId, | |
72 | feature_gate: Symbol, | |
73 | ) -> bool { | |
74 | let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id)); | |
6a06907d | 75 | attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate) |
1b1a35ee XL |
76 | } |
77 | ||
78 | // Returns `true` if the given `const fn` is "const-stable". | |
79 | // | |
80 | // Panics if the given `DefId` does not refer to a `const fn`. | |
81 | // | |
82 | // Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable" | |
83 | // functions can be called in a const-context by users of the stable compiler. "const-stable" | |
84 | // functions are subject to more stringent restrictions than "const-unstable" functions: They | |
85 | // cannot use unstable features and can only call other "const-stable" functions. | |
a2a8927a | 86 | pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { |
923072b8 | 87 | // A default body in a `#[const_trait]` is not const-stable because const |
94222f64 XL |
88 | // trait fns currently cannot be const-stable. We shouldn't |
89 | // restrict default bodies to only call const-stable functions. | |
923072b8 | 90 | if tcx.is_const_default_method(def_id) { |
94222f64 XL |
91 | return false; |
92 | } | |
93 | ||
1b1a35ee XL |
94 | // Const-stability is only relevant for `const fn`. |
95 | assert!(tcx.is_const_fn_raw(def_id)); | |
96 | ||
923072b8 FG |
97 | // A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs |
98 | // to is const-stable. | |
1b1a35ee | 99 | match tcx.lookup_const_stability(def_id) { |
923072b8 FG |
100 | Some(stab) => stab.is_const_stable(), |
101 | None if is_parent_const_stable_trait(tcx, def_id) => { | |
102 | // Remove this when `#![feature(const_trait_impl)]` is stabilized, | |
103 | // returning `true` unconditionally. | |
104 | tcx.sess.delay_span_bug( | |
105 | tcx.def_span(def_id), | |
106 | "trait implementations cannot be const stable yet", | |
107 | ); | |
108 | true | |
109 | } | |
110 | None => false, // By default, items are not const stable. | |
1b1a35ee | 111 | } |
923072b8 FG |
112 | } |
113 | ||
114 | fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | |
115 | let local_def_id = def_id.expect_local(); | |
116 | let hir_id = tcx.local_def_id_to_hir_id(local_def_id); | |
117 | ||
118 | let Some(parent) = tcx.hir().find_parent_node(hir_id) else { return false }; | |
119 | let parent_def = tcx.hir().get(parent); | |
1b1a35ee | 120 | |
923072b8 FG |
121 | if !matches!( |
122 | parent_def, | |
123 | hir::Node::Item(hir::Item { | |
124 | kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }), | |
125 | .. | |
126 | }) | |
127 | ) { | |
1b1a35ee XL |
128 | return false; |
129 | } | |
130 | ||
923072b8 | 131 | tcx.lookup_const_stability(parent.owner).map_or(false, |stab| stab.is_const_stable()) |
1b1a35ee | 132 | } |