1 //! Concrete error types for all operations which may be invalid in a certain const context.
3 use rustc::hir::def_id::DefId;
4 use rustc::mir::BorrowKind;
5 use rustc::session::config::nightly_options;
7 use syntax::feature_gate::{emit_feature_err, GateIssue};
8 use syntax::symbol::sym;
9 use syntax_pos::{Span, Symbol};
11 use super::{ConstKind, Item};
13 use rustc_error_codes::*;
15 /// An operation that is not *always* allowed in a const context.
16 pub trait NonConstOp: std::fmt::Debug {
17 /// Whether this operation can be evaluated by miri.
18 const IS_SUPPORTED_IN_MIRI: bool = true;
20 /// Returns a boolean indicating whether the feature gate that would allow this operation is
21 /// enabled, or `None` if such a feature gate does not exist.
22 fn feature_gate(_tcx: TyCtxt<'tcx>) -> Option<bool> {
26 /// Returns `true` if this operation is allowed in the given item.
28 /// This check should assume that we are not in a non-const `fn`, where all operations are
30 fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
31 Self::feature_gate(item.tcx).unwrap_or(false)
34 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
35 let mut err = struct_span_err!(
39 "{} contains unimplemented expression type",
42 if item.tcx.sess.teach(&err.get_code().unwrap()) {
43 err.note("A function call isn't allowed in the const's initialization expression \
44 because the expression's value must be known at compile-time.");
45 err.note("Remember: you can't use a function call inside a const's initialization \
46 expression! However, you can use it anywhere else.");
52 /// A `Downcast` projection.
55 impl NonConstOp for Downcast {}
57 /// A function call where the callee is a pointer.
59 pub struct FnCallIndirect;
60 impl NonConstOp for FnCallIndirect {
61 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
62 let mut err = item.tcx.sess.struct_span_err(
64 &format!("function pointers are not allowed in const fn"));
69 /// A function call where the callee is not marked as `const`.
71 pub struct FnCallNonConst(pub DefId);
72 impl NonConstOp for FnCallNonConst {
73 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
74 let mut err = struct_span_err!(
78 "calls in {}s are limited to constant functions, \
79 tuple structs and tuple variants",
86 /// A function call where the callee is not a function definition or function pointer, e.g. a
89 /// This can be subdivided in the future to produce a better error message.
91 pub struct FnCallOther;
92 impl NonConstOp for FnCallOther {
93 const IS_SUPPORTED_IN_MIRI: bool = false;
96 /// A call to a `#[unstable]` const fn or `#[rustc_const_unstable]` function.
98 /// Contains the name of the feature that would allow the use of this function.
100 pub struct FnCallUnstable(pub DefId, pub Symbol);
101 impl NonConstOp for FnCallUnstable {
102 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
103 let FnCallUnstable(def_id, feature) = *self;
105 let mut err = item.tcx.sess.struct_span_err(span,
106 &format!("`{}` is not yet stable as a const fn",
107 item.tcx.def_path_str(def_id)));
108 if nightly_options::is_nightly_build() {
110 "add `#![feature({})]` to the \
111 crate attributes to enable",
119 pub struct HeapAllocation;
120 impl NonConstOp for HeapAllocation {
121 const IS_SUPPORTED_IN_MIRI: bool = false;
123 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
124 let mut err = struct_span_err!(item.tcx.sess, span, E0010,
125 "allocations are not allowed in {}s", item.const_kind());
126 err.span_label(span, format!("allocation not allowed in {}s", item.const_kind()));
127 if item.tcx.sess.teach(&err.get_code().unwrap()) {
129 "The value of statics and constants must be known at compile time, \
130 and they live for the entire lifetime of a program. Creating a boxed \
131 value allocates memory on the heap at runtime, and therefore cannot \
132 be done at compile time."
140 pub struct IfOrMatch;
141 impl NonConstOp for IfOrMatch {}
145 impl NonConstOp for LiveDrop {
146 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
147 struct_span_err!(item.tcx.sess, span, E0493,
148 "destructors cannot be evaluated at compile-time")
149 .span_label(span, format!("{}s cannot evaluate destructors",
157 impl NonConstOp for Loop {}
160 pub struct MutBorrow(pub BorrowKind);
161 impl NonConstOp for MutBorrow {
162 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
164 if let BorrowKind::Mut { .. } = kind {
165 let mut err = struct_span_err!(item.tcx.sess, span, E0017,
166 "references in {}s may only refer \
167 to immutable values", item.const_kind());
168 err.span_label(span, format!("{}s require immutable values",
170 if item.tcx.sess.teach(&err.get_code().unwrap()) {
171 err.note("References in statics and constants may only refer \
172 to immutable values.\n\n\
173 Statics are shared everywhere, and if they refer to \
174 mutable data one might violate memory safety since \
175 holding multiple mutable references to shared data \
177 If you really want global mutable state, try using \
178 static mut or a global UnsafeCell.");
182 span_err!(item.tcx.sess, span, E0492,
183 "cannot borrow a constant which may contain \
184 interior mutability, create a static instead");
191 impl NonConstOp for MutDeref {}
195 impl NonConstOp for Panic {
196 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
197 Some(tcx.features().const_panic)
200 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
202 &item.tcx.sess.parse_sess,
206 &format!("panicking in {}s is unstable", item.const_kind()),
212 pub struct RawPtrComparison;
213 impl NonConstOp for RawPtrComparison {
214 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
215 Some(tcx.features().const_compare_raw_pointers)
218 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
220 &item.tcx.sess.parse_sess,
221 sym::const_compare_raw_pointers,
224 &format!("comparing raw pointers inside {}", item.const_kind()),
230 pub struct RawPtrDeref;
231 impl NonConstOp for RawPtrDeref {
232 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
233 Some(tcx.features().const_raw_ptr_deref)
236 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
238 &item.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
239 span, GateIssue::Language,
241 "dereferencing raw pointers in {}s is unstable",
249 pub struct RawPtrToIntCast;
250 impl NonConstOp for RawPtrToIntCast {
251 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
252 Some(tcx.features().const_raw_ptr_to_usize_cast)
255 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
257 &item.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast,
258 span, GateIssue::Language,
260 "casting pointers to integers in {}s is unstable",
267 /// An access to a (non-thread-local) `static`.
269 pub struct StaticAccess;
270 impl NonConstOp for StaticAccess {
271 fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
272 item.const_kind().is_static()
275 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
276 let mut err = struct_span_err!(item.tcx.sess, span, E0013,
277 "{}s cannot refer to statics, use \
278 a constant instead", item.const_kind());
279 if item.tcx.sess.teach(&err.get_code().unwrap()) {
281 "Static and const variables can refer to other const variables. \
282 But a const variable cannot refer to a static variable."
285 "To fix this, the value can be extracted as a const and then used."
292 /// An access to a thread-local `static`.
294 pub struct ThreadLocalAccess;
295 impl NonConstOp for ThreadLocalAccess {
296 const IS_SUPPORTED_IN_MIRI: bool = false;
298 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
299 span_err!(item.tcx.sess, span, E0625,
300 "thread-local statics cannot be \
301 accessed at compile-time");
306 pub struct Transmute;
307 impl NonConstOp for Transmute {
308 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
309 Some(tcx.features().const_transmute)
312 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
314 &item.tcx.sess.parse_sess, sym::const_transmute,
315 span, GateIssue::Language,
316 &format!("The use of std::mem::transmute() \
317 is gated in {}s", item.const_kind()));
322 pub struct UnionAccess;
323 impl NonConstOp for UnionAccess {
324 fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
325 // Union accesses are stable in all contexts except `const fn`.
326 item.const_kind() != ConstKind::ConstFn || Self::feature_gate(item.tcx).unwrap()
329 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
330 Some(tcx.features().const_fn_union)
333 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
335 &item.tcx.sess.parse_sess, sym::const_fn_union,
336 span, GateIssue::Language,
337 "unions in const fn are unstable",