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::feature_err;
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 {
56 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
57 Some(tcx.features().const_if_match)
61 /// A function call where the callee is a pointer.
63 pub struct FnCallIndirect;
64 impl NonConstOp for FnCallIndirect {
65 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
66 let mut err = item.tcx.sess.struct_span_err(
68 &format!("function pointers are not allowed in const fn"));
73 /// A function call where the callee is not marked as `const`.
75 pub struct FnCallNonConst(pub DefId);
76 impl NonConstOp for FnCallNonConst {
77 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
78 let mut err = struct_span_err!(
82 "calls in {}s are limited to constant functions, \
83 tuple structs and tuple variants",
90 /// A function call where the callee is not a function definition or function pointer, e.g. a
93 /// This can be subdivided in the future to produce a better error message.
95 pub struct FnCallOther;
96 impl NonConstOp for FnCallOther {
97 const IS_SUPPORTED_IN_MIRI: bool = false;
100 /// A call to a `#[unstable]` const fn or `#[rustc_const_unstable]` function.
102 /// Contains the name of the feature that would allow the use of this function.
104 pub struct FnCallUnstable(pub DefId, pub Symbol);
105 impl NonConstOp for FnCallUnstable {
106 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
107 let FnCallUnstable(def_id, feature) = *self;
109 let mut err = item.tcx.sess.struct_span_err(span,
110 &format!("`{}` is not yet stable as a const fn",
111 item.tcx.def_path_str(def_id)));
112 if nightly_options::is_nightly_build() {
114 "add `#![feature({})]` to the \
115 crate attributes to enable",
123 pub struct HeapAllocation;
124 impl NonConstOp for HeapAllocation {
125 const IS_SUPPORTED_IN_MIRI: bool = false;
127 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
128 let mut err = struct_span_err!(item.tcx.sess, span, E0010,
129 "allocations are not allowed in {}s", item.const_kind());
130 err.span_label(span, format!("allocation not allowed in {}s", item.const_kind()));
131 if item.tcx.sess.teach(&err.get_code().unwrap()) {
133 "The value of statics and constants must be known at compile time, \
134 and they live for the entire lifetime of a program. Creating a boxed \
135 value allocates memory on the heap at runtime, and therefore cannot \
136 be done at compile time."
144 pub struct IfOrMatch;
145 impl NonConstOp for IfOrMatch {
146 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
147 Some(tcx.features().const_if_match)
150 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
151 // This should be caught by the HIR const-checker.
152 item.tcx.sess.delay_span_bug(
154 "complex control flow is forbidden in a const context",
161 impl NonConstOp for LiveDrop {
162 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
163 struct_span_err!(item.tcx.sess, span, E0493,
164 "destructors cannot be evaluated at compile-time")
165 .span_label(span, format!("{}s cannot evaluate destructors",
173 impl NonConstOp for Loop {
174 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
175 // This should be caught by the HIR const-checker.
176 item.tcx.sess.delay_span_bug(
178 "complex control flow is forbidden in a const context",
184 pub struct MutBorrow(pub BorrowKind);
185 impl NonConstOp for MutBorrow {
186 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
188 if let BorrowKind::Mut { .. } = kind {
189 let mut err = struct_span_err!(item.tcx.sess, span, E0017,
190 "references in {}s may only refer \
191 to immutable values", item.const_kind());
192 err.span_label(span, format!("{}s require immutable values",
194 if item.tcx.sess.teach(&err.get_code().unwrap()) {
195 err.note("References in statics and constants may only refer \
196 to immutable values.\n\n\
197 Statics are shared everywhere, and if they refer to \
198 mutable data one might violate memory safety since \
199 holding multiple mutable references to shared data \
201 If you really want global mutable state, try using \
202 static mut or a global UnsafeCell.");
206 span_err!(item.tcx.sess, span, E0492,
207 "cannot borrow a constant which may contain \
208 interior mutability, create a static instead");
215 impl NonConstOp for MutDeref {}
219 impl NonConstOp for Panic {
220 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
221 Some(tcx.features().const_panic)
224 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
226 &item.tcx.sess.parse_sess,
229 &format!("panicking in {}s is unstable", item.const_kind()),
236 pub struct RawPtrComparison;
237 impl NonConstOp for RawPtrComparison {
238 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
239 Some(tcx.features().const_compare_raw_pointers)
242 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
244 &item.tcx.sess.parse_sess,
245 sym::const_compare_raw_pointers,
247 &format!("comparing raw pointers inside {}", item.const_kind()),
254 pub struct RawPtrDeref;
255 impl NonConstOp for RawPtrDeref {
256 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
257 Some(tcx.features().const_raw_ptr_deref)
260 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
262 &item.tcx.sess.parse_sess, sym::const_raw_ptr_deref, span,
264 "dereferencing raw pointers in {}s is unstable",
273 pub struct RawPtrToIntCast;
274 impl NonConstOp for RawPtrToIntCast {
275 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
276 Some(tcx.features().const_raw_ptr_to_usize_cast)
279 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
281 &item.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast, span,
283 "casting pointers to integers in {}s is unstable",
291 /// An access to a (non-thread-local) `static`.
293 pub struct StaticAccess;
294 impl NonConstOp for StaticAccess {
295 fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
296 item.const_kind().is_static()
299 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
300 let mut err = struct_span_err!(item.tcx.sess, span, E0013,
301 "{}s cannot refer to statics, use \
302 a constant instead", item.const_kind());
303 if item.tcx.sess.teach(&err.get_code().unwrap()) {
305 "Static and const variables can refer to other const variables. \
306 But a const variable cannot refer to a static variable."
309 "To fix this, the value can be extracted as a const and then used."
316 /// An access to a thread-local `static`.
318 pub struct ThreadLocalAccess;
319 impl NonConstOp for ThreadLocalAccess {
320 const IS_SUPPORTED_IN_MIRI: bool = false;
322 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
323 span_err!(item.tcx.sess, span, E0625,
324 "thread-local statics cannot be \
325 accessed at compile-time");
330 pub struct UnionAccess;
331 impl NonConstOp for UnionAccess {
332 fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
333 // Union accesses are stable in all contexts except `const fn`.
334 item.const_kind() != ConstKind::ConstFn || Self::feature_gate(item.tcx).unwrap()
337 fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
338 Some(tcx.features().const_fn_union)
341 fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
343 &item.tcx.sess.parse_sess, sym::const_fn_union, span,
344 "unions in const fn are unstable",