]>
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; | |
9c376795 | 11 | use rustc_middle::ty::{self, PolyFnSig, 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 | 64 | fn is_async(&self) -> bool { |
487cf647 | 65 | self.tcx.asyncness(self.def_id()).is_async() |
1b1a35ee | 66 | } |
9c376795 FG |
67 | |
68 | pub fn fn_sig(&self) -> PolyFnSig<'tcx> { | |
69 | let did = self.def_id().to_def_id(); | |
70 | if self.tcx.is_closure(did) { | |
9ffffee4 | 71 | let ty = self.tcx.type_of(did).subst_identity(); |
9c376795 FG |
72 | let ty::Closure(_, substs) = ty.kind() else { bug!("type_of closure not ty::Closure") }; |
73 | substs.as_closure().sig() | |
74 | } else { | |
9ffffee4 | 75 | self.tcx.fn_sig(did).subst_identity() |
9c376795 FG |
76 | } |
77 | } | |
1b1a35ee XL |
78 | } |
79 | ||
04454e1e FG |
80 | pub fn rustc_allow_const_fn_unstable( |
81 | tcx: TyCtxt<'_>, | |
82 | def_id: LocalDefId, | |
83 | feature_gate: Symbol, | |
84 | ) -> bool { | |
85 | let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id)); | |
6a06907d | 86 | attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate) |
1b1a35ee XL |
87 | } |
88 | ||
487cf647 FG |
89 | /// Returns `true` if the given `const fn` is "const-stable". |
90 | /// | |
91 | /// Panics if the given `DefId` does not refer to a `const fn`. | |
92 | /// | |
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. | |
a2a8927a | 97 | pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { |
923072b8 | 98 | // A default body in a `#[const_trait]` is not const-stable because const |
94222f64 XL |
99 | // trait fns currently cannot be const-stable. We shouldn't |
100 | // restrict default bodies to only call const-stable functions. | |
923072b8 | 101 | if tcx.is_const_default_method(def_id) { |
94222f64 XL |
102 | return false; |
103 | } | |
104 | ||
1b1a35ee XL |
105 | // Const-stability is only relevant for `const fn`. |
106 | assert!(tcx.is_const_fn_raw(def_id)); | |
107 | ||
923072b8 FG |
108 | // A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs |
109 | // to is const-stable. | |
1b1a35ee | 110 | match tcx.lookup_const_stability(def_id) { |
923072b8 FG |
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", | |
118 | ); | |
119 | true | |
120 | } | |
121 | None => false, // By default, items are not const stable. | |
1b1a35ee | 122 | } |
923072b8 FG |
123 | } |
124 | ||
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); | |
128 | ||
9c376795 | 129 | let Some(parent) = tcx.hir().opt_parent_id(hir_id) else { return false }; |
923072b8 | 130 | let parent_def = tcx.hir().get(parent); |
1b1a35ee | 131 | |
923072b8 FG |
132 | if !matches!( |
133 | parent_def, | |
134 | hir::Node::Item(hir::Item { | |
135 | kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }), | |
136 | .. | |
137 | }) | |
138 | ) { | |
1b1a35ee XL |
139 | return false; |
140 | } | |
141 | ||
49aad941 | 142 | tcx.lookup_const_stability(parent.owner).is_some_and(|stab| stab.is_const_stable()) |
1b1a35ee | 143 | } |