]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/transform/check_consts/ops.rs
New upstream version 1.44.1+dfsg1
[rustc.git] / src / librustc_mir / transform / check_consts / ops.rs
CommitLineData
e74abb32
XL
1//! Concrete error types for all operations which may be invalid in a certain const context.
2
dfeec247
XL
3use rustc_errors::struct_span_err;
4use rustc_hir::def_id::DefId;
ba9703b0
XL
5use rustc_session::config::nightly_options;
6use rustc_session::parse::feature_err;
dfeec247
XL
7use rustc_span::symbol::sym;
8use rustc_span::{Span, Symbol};
e74abb32
XL
9
10use super::{ConstKind, Item};
11
12/// An operation that is not *always* allowed in a const context.
13pub trait NonConstOp: std::fmt::Debug {
14 /// Whether this operation can be evaluated by miri.
15 const IS_SUPPORTED_IN_MIRI: bool = true;
16
ba9703b0
XL
17 /// Returns the `Symbol` corresponding to the feature gate that would enable this operation,
18 /// or `None` if such a feature gate does not exist.
19 fn feature_gate() -> Option<Symbol> {
e74abb32
XL
20 None
21 }
22
23 /// Returns `true` if this operation is allowed in the given item.
24 ///
25 /// This check should assume that we are not in a non-const `fn`, where all operations are
26 /// legal.
ba9703b0
XL
27 ///
28 /// By default, it returns `true` if and only if this operation has a corresponding feature
29 /// gate and that gate is enabled.
e74abb32 30 fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
ba9703b0 31 Self::feature_gate().map_or(false, |gate| item.tcx.features().enabled(gate))
e74abb32
XL
32 }
33
34 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
35 let mut err = struct_span_err!(
36 item.tcx.sess,
37 span,
38 E0019,
39 "{} contains unimplemented expression type",
40 item.const_kind()
41 );
42 if item.tcx.sess.teach(&err.get_code().unwrap()) {
dfeec247
XL
43 err.note(
44 "A function call isn't allowed in the const's initialization expression \
45 because the expression's value must be known at compile-time.",
46 );
47 err.note(
48 "Remember: you can't use a function call inside a const's initialization \
49 expression! However, you can use it anywhere else.",
50 );
e74abb32
XL
51 }
52 err.emit();
53 }
54}
55
56/// A `Downcast` projection.
57#[derive(Debug)]
58pub struct Downcast;
60c5eb7d 59impl NonConstOp for Downcast {
ba9703b0
XL
60 fn feature_gate() -> Option<Symbol> {
61 Some(sym::const_if_match)
60c5eb7d
XL
62 }
63}
e74abb32
XL
64
65/// A function call where the callee is a pointer.
66#[derive(Debug)]
67pub struct FnCallIndirect;
68impl NonConstOp for FnCallIndirect {
69 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
74b04a01
XL
70 let mut err =
71 item.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn");
e74abb32
XL
72 err.emit();
73 }
74}
75
76/// A function call where the callee is not marked as `const`.
77#[derive(Debug)]
78pub struct FnCallNonConst(pub DefId);
79impl NonConstOp for FnCallNonConst {
80 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
81 let mut err = struct_span_err!(
82 item.tcx.sess,
83 span,
84 E0015,
85 "calls in {}s are limited to constant functions, \
86 tuple structs and tuple variants",
87 item.const_kind(),
88 );
89 err.emit();
90 }
91}
92
e74abb32
XL
93/// A call to a `#[unstable]` const fn or `#[rustc_const_unstable]` function.
94///
95/// Contains the name of the feature that would allow the use of this function.
96#[derive(Debug)]
97pub struct FnCallUnstable(pub DefId, pub Symbol);
98impl NonConstOp for FnCallUnstable {
99 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
100 let FnCallUnstable(def_id, feature) = *self;
101
dfeec247
XL
102 let mut err = item.tcx.sess.struct_span_err(
103 span,
104 &format!("`{}` is not yet stable as a const fn", item.tcx.def_path_str(def_id)),
105 );
e74abb32 106 if nightly_options::is_nightly_build() {
dfeec247 107 err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
e74abb32
XL
108 }
109 err.emit();
110 }
111}
112
113#[derive(Debug)]
114pub struct HeapAllocation;
115impl NonConstOp for HeapAllocation {
e74abb32 116 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
dfeec247
XL
117 let mut err = struct_span_err!(
118 item.tcx.sess,
119 span,
120 E0010,
121 "allocations are not allowed in {}s",
122 item.const_kind()
123 );
e74abb32
XL
124 err.span_label(span, format!("allocation not allowed in {}s", item.const_kind()));
125 if item.tcx.sess.teach(&err.get_code().unwrap()) {
126 err.note(
127 "The value of statics and constants must be known at compile time, \
128 and they live for the entire lifetime of a program. Creating a boxed \
129 value allocates memory on the heap at runtime, and therefore cannot \
dfeec247 130 be done at compile time.",
e74abb32
XL
131 );
132 }
133 err.emit();
134 }
135}
136
137#[derive(Debug)]
138pub struct IfOrMatch;
60c5eb7d 139impl NonConstOp for IfOrMatch {
ba9703b0
XL
140 fn feature_gate() -> Option<Symbol> {
141 Some(sym::const_if_match)
60c5eb7d
XL
142 }
143
144 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
145 // This should be caught by the HIR const-checker.
dfeec247 146 item.tcx.sess.delay_span_bug(span, "complex control flow is forbidden in a const context");
60c5eb7d
XL
147 }
148}
e74abb32
XL
149
150#[derive(Debug)]
151pub struct LiveDrop;
152impl NonConstOp for LiveDrop {
153 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
dfeec247
XL
154 struct_span_err!(
155 item.tcx.sess,
156 span,
157 E0493,
158 "destructors cannot be evaluated at compile-time"
159 )
160 .span_label(span, format!("{}s cannot evaluate destructors", item.const_kind()))
161 .emit();
e74abb32
XL
162 }
163}
164
165#[derive(Debug)]
166pub struct Loop;
60c5eb7d 167impl NonConstOp for Loop {
ba9703b0
XL
168 fn feature_gate() -> Option<Symbol> {
169 Some(sym::const_loop)
60c5eb7d
XL
170 }
171
172 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
173 // This should be caught by the HIR const-checker.
dfeec247 174 item.tcx.sess.delay_span_bug(span, "complex control flow is forbidden in a const context");
60c5eb7d
XL
175 }
176}
177
178#[derive(Debug)]
179pub struct CellBorrow;
180impl NonConstOp for CellBorrow {
181 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
dfeec247
XL
182 struct_span_err!(
183 item.tcx.sess,
184 span,
185 E0492,
60c5eb7d 186 "cannot borrow a constant which may contain \
dfeec247
XL
187 interior mutability, create a static instead"
188 )
189 .emit();
60c5eb7d
XL
190 }
191}
e74abb32
XL
192
193#[derive(Debug)]
60c5eb7d 194pub struct MutBorrow;
e74abb32 195impl NonConstOp for MutBorrow {
ba9703b0
XL
196 fn feature_gate() -> Option<Symbol> {
197 Some(sym::const_mut_refs)
60c5eb7d
XL
198 }
199
e74abb32 200 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
60c5eb7d
XL
201 let mut err = feature_err(
202 &item.tcx.sess.parse_sess,
203 sym::const_mut_refs,
204 span,
dfeec247
XL
205 &format!(
206 "references in {}s may only refer \
207 to immutable values",
208 item.const_kind()
209 ),
60c5eb7d 210 );
dfeec247 211 err.span_label(span, format!("{}s require immutable values", item.const_kind()));
60c5eb7d 212 if item.tcx.sess.teach(&err.get_code().unwrap()) {
dfeec247
XL
213 err.note(
214 "References in statics and constants may only refer \
60c5eb7d
XL
215 to immutable values.\n\n\
216 Statics are shared everywhere, and if they refer to \
217 mutable data one might violate memory safety since \
218 holding multiple mutable references to shared data \
219 is not allowed.\n\n\
220 If you really want global mutable state, try using \
dfeec247
XL
221 static mut or a global UnsafeCell.",
222 );
e74abb32 223 }
60c5eb7d 224 err.emit();
e74abb32
XL
225 }
226}
227
dfeec247
XL
228#[derive(Debug)]
229pub struct MutAddressOf;
230impl NonConstOp for MutAddressOf {
ba9703b0
XL
231 fn feature_gate() -> Option<Symbol> {
232 Some(sym::const_mut_refs)
dfeec247
XL
233 }
234
235 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
236 feature_err(
237 &item.tcx.sess.parse_sess,
238 sym::const_mut_refs,
239 span,
240 &format!("`&raw mut` is not allowed in {}s", item.const_kind()),
241 )
242 .emit();
243 }
244}
245
e74abb32
XL
246#[derive(Debug)]
247pub struct MutDeref;
60c5eb7d 248impl NonConstOp for MutDeref {
ba9703b0
XL
249 fn feature_gate() -> Option<Symbol> {
250 Some(sym::const_mut_refs)
60c5eb7d
XL
251 }
252}
e74abb32
XL
253
254#[derive(Debug)]
255pub struct Panic;
256impl NonConstOp for Panic {
ba9703b0
XL
257 fn feature_gate() -> Option<Symbol> {
258 Some(sym::const_panic)
e74abb32
XL
259 }
260
261 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
60c5eb7d 262 feature_err(
e74abb32
XL
263 &item.tcx.sess.parse_sess,
264 sym::const_panic,
265 span,
e74abb32 266 &format!("panicking in {}s is unstable", item.const_kind()),
60c5eb7d
XL
267 )
268 .emit();
e74abb32
XL
269 }
270}
271
272#[derive(Debug)]
273pub struct RawPtrComparison;
274impl NonConstOp for RawPtrComparison {
ba9703b0
XL
275 fn feature_gate() -> Option<Symbol> {
276 Some(sym::const_compare_raw_pointers)
e74abb32
XL
277 }
278
279 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
60c5eb7d 280 feature_err(
e74abb32
XL
281 &item.tcx.sess.parse_sess,
282 sym::const_compare_raw_pointers,
283 span,
e74abb32 284 &format!("comparing raw pointers inside {}", item.const_kind()),
60c5eb7d
XL
285 )
286 .emit();
e74abb32
XL
287 }
288}
289
290#[derive(Debug)]
291pub struct RawPtrDeref;
292impl NonConstOp for RawPtrDeref {
ba9703b0
XL
293 fn feature_gate() -> Option<Symbol> {
294 Some(sym::const_raw_ptr_deref)
e74abb32
XL
295 }
296
297 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
60c5eb7d 298 feature_err(
dfeec247
XL
299 &item.tcx.sess.parse_sess,
300 sym::const_raw_ptr_deref,
301 span,
302 &format!("dereferencing raw pointers in {}s is unstable", item.const_kind(),),
60c5eb7d
XL
303 )
304 .emit();
e74abb32
XL
305 }
306}
307
308#[derive(Debug)]
309pub struct RawPtrToIntCast;
310impl NonConstOp for RawPtrToIntCast {
ba9703b0
XL
311 fn feature_gate() -> Option<Symbol> {
312 Some(sym::const_raw_ptr_to_usize_cast)
e74abb32
XL
313 }
314
315 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
60c5eb7d 316 feature_err(
dfeec247
XL
317 &item.tcx.sess.parse_sess,
318 sym::const_raw_ptr_to_usize_cast,
319 span,
320 &format!("casting pointers to integers in {}s is unstable", item.const_kind(),),
60c5eb7d
XL
321 )
322 .emit();
e74abb32
XL
323 }
324}
325
326/// An access to a (non-thread-local) `static`.
327#[derive(Debug)]
328pub struct StaticAccess;
329impl NonConstOp for StaticAccess {
330 fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
331 item.const_kind().is_static()
332 }
333
334 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
dfeec247
XL
335 let mut err = struct_span_err!(
336 item.tcx.sess,
337 span,
338 E0013,
339 "{}s cannot refer to statics",
340 item.const_kind()
341 );
342 err.help(
343 "consider extracting the value of the `static` to a `const`, and referring to that",
344 );
e74abb32
XL
345 if item.tcx.sess.teach(&err.get_code().unwrap()) {
346 err.note(
dfeec247
XL
347 "`static` and `const` variables can refer to other `const` variables. \
348 A `const` variable, however, cannot refer to a `static` variable.",
e74abb32 349 );
dfeec247 350 err.help("To fix this, the value can be extracted to a `const` and then used.");
e74abb32
XL
351 }
352 err.emit();
353 }
354}
355
356/// An access to a thread-local `static`.
357#[derive(Debug)]
358pub struct ThreadLocalAccess;
359impl NonConstOp for ThreadLocalAccess {
360 const IS_SUPPORTED_IN_MIRI: bool = false;
361
362 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
dfeec247
XL
363 struct_span_err!(
364 item.tcx.sess,
365 span,
366 E0625,
e74abb32 367 "thread-local statics cannot be \
dfeec247
XL
368 accessed at compile-time"
369 )
370 .emit();
e74abb32
XL
371 }
372}
373
e74abb32
XL
374#[derive(Debug)]
375pub struct UnionAccess;
376impl NonConstOp for UnionAccess {
377 fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
378 // Union accesses are stable in all contexts except `const fn`.
ba9703b0
XL
379 item.const_kind() != ConstKind::ConstFn
380 || item.tcx.features().enabled(Self::feature_gate().unwrap())
e74abb32
XL
381 }
382
ba9703b0
XL
383 fn feature_gate() -> Option<Symbol> {
384 Some(sym::const_fn_union)
e74abb32
XL
385 }
386
387 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
60c5eb7d 388 feature_err(
dfeec247
XL
389 &item.tcx.sess.parse_sess,
390 sym::const_fn_union,
391 span,
e74abb32 392 "unions in const fn are unstable",
60c5eb7d
XL
393 )
394 .emit();
e74abb32
XL
395 }
396}