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