-
-/// All implementers of `NonConstOp`.
-pub mod ops {
- use super::*;
-
- /// A `Downcast` projection.
- #[derive(Debug)]
- pub struct Downcast;
- impl NonConstOp for Downcast {}
-
- /// A function call where the callee is a pointer.
- #[derive(Debug)]
- pub struct FnCallIndirect;
- impl NonConstOp for FnCallIndirect {
- const IS_SUPPORTED_IN_MIRI: bool = false;
-
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- let mut err = item.tcx.sess.struct_span_err(
- span,
- &format!("function pointers are not allowed in const fn"));
- err.emit();
- }
- }
-
- /// A function call where the callee is not marked as `const`.
- #[derive(Debug)]
- pub struct FnCallNonConst(pub DefId);
- impl NonConstOp for FnCallNonConst {
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- let mut err = struct_span_err!(
- item.tcx.sess,
- span,
- E0015,
- "calls in {}s are limited to constant functions, \
- tuple structs and tuple variants",
- item.mode,
- );
- err.emit();
- }
- }
-
- /// A function call where the callee is not a function definition or function pointer, e.g. a
- /// closure.
- ///
- /// This can be subdivided in the future to produce a better error message.
- #[derive(Debug)]
- pub struct FnCallOther;
- impl NonConstOp for FnCallOther {
- const IS_SUPPORTED_IN_MIRI: bool = false;
- }
-
- /// A call to a `#[unstable]` const fn or `#[rustc_const_unstable]` function.
- ///
- /// Contains the name of the feature that would allow the use of this function.
- #[derive(Debug)]
- pub struct FnCallUnstable(pub DefId, pub Symbol);
- impl NonConstOp for FnCallUnstable {
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- let FnCallUnstable(def_id, feature) = *self;
-
- let mut err = item.tcx.sess.struct_span_err(span,
- &format!("`{}` is not yet stable as a const fn",
- item.tcx.def_path_str(def_id)));
- if nightly_options::is_nightly_build() {
- help!(&mut err,
- "add `#![feature({})]` to the \
- crate attributes to enable",
- feature);
- }
- err.emit();
- }
- }
-
- #[derive(Debug)]
- pub struct HeapAllocation;
- impl NonConstOp for HeapAllocation {
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- let mut err = struct_span_err!(item.tcx.sess, span, E0010,
- "allocations are not allowed in {}s", item.mode);
- err.span_label(span, format!("allocation not allowed in {}s", item.mode));
- if item.tcx.sess.teach(&err.get_code().unwrap()) {
- err.note(
- "The value of statics and constants must be known at compile time, \
- and they live for the entire lifetime of a program. Creating a boxed \
- value allocates memory on the heap at runtime, and therefore cannot \
- be done at compile time."
- );
- }
- err.emit();
- }
- }
-
- #[derive(Debug)]
- pub struct IfOrMatch;
- impl NonConstOp for IfOrMatch {}
-
- #[derive(Debug)]
- pub struct LiveDrop;
- impl NonConstOp for LiveDrop {
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- struct_span_err!(item.tcx.sess, span, E0493,
- "destructors cannot be evaluated at compile-time")
- .span_label(span, format!("{}s cannot evaluate destructors",
- item.mode))
- .emit();
- }
- }
-
- #[derive(Debug)]
- pub struct Loop;
- impl NonConstOp for Loop {}
-
- #[derive(Debug)]
- pub struct MutBorrow(pub BorrowKind);
- impl NonConstOp for MutBorrow {
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- let kind = self.0;
- if let BorrowKind::Mut { .. } = kind {
- let mut err = struct_span_err!(item.tcx.sess, span, E0017,
- "references in {}s may only refer \
- to immutable values", item.mode);
- err.span_label(span, format!("{}s require immutable values",
- item.mode));
- if item.tcx.sess.teach(&err.get_code().unwrap()) {
- err.note("References in statics and constants may only refer \
- to immutable values.\n\n\
- Statics are shared everywhere, and if they refer to \
- mutable data one might violate memory safety since \
- holding multiple mutable references to shared data \
- is not allowed.\n\n\
- If you really want global mutable state, try using \
- static mut or a global UnsafeCell.");
- }
- err.emit();
- } else {
- span_err!(item.tcx.sess, span, E0492,
- "cannot borrow a constant which may contain \
- interior mutability, create a static instead");
- }
- }
- }
-
- #[derive(Debug)]
- pub struct MutDeref;
- impl NonConstOp for MutDeref {}
-
- #[derive(Debug)]
- pub struct Panic;
- impl NonConstOp for Panic {
- fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
- Some(tcx.features().const_panic)
- }
-
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- emit_feature_err(
- &item.tcx.sess.parse_sess,
- sym::const_panic,
- span,
- GateIssue::Language,
- &format!("panicking in {}s is unstable", item.mode),
- );
- }
- }
-
- #[derive(Debug)]
- pub struct RawPtrComparison;
- impl NonConstOp for RawPtrComparison {
- fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
- Some(tcx.features().const_compare_raw_pointers)
- }
-
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- emit_feature_err(
- &item.tcx.sess.parse_sess,
- sym::const_compare_raw_pointers,
- span,
- GateIssue::Language,
- &format!("comparing raw pointers inside {}", item.mode),
- );
- }
- }
-
- #[derive(Debug)]
- pub struct RawPtrDeref;
- impl NonConstOp for RawPtrDeref {
- fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
- Some(tcx.features().const_raw_ptr_deref)
- }
-
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- emit_feature_err(
- &item.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
- span, GateIssue::Language,
- &format!(
- "dereferencing raw pointers in {}s is unstable",
- item.mode,
- ),
- );
- }
- }
-
- #[derive(Debug)]
- pub struct RawPtrToIntCast;
- impl NonConstOp for RawPtrToIntCast {
- fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
- Some(tcx.features().const_raw_ptr_to_usize_cast)
- }
-
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- emit_feature_err(
- &item.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast,
- span, GateIssue::Language,
- &format!(
- "casting pointers to integers in {}s is unstable",
- item.mode,
- ),
- );
- }
- }
-
- /// An access to a (non-thread-local) `static`.
- #[derive(Debug)]
- pub struct StaticAccess;
- impl NonConstOp for StaticAccess {
- fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
- item.mode.is_static()
- }
-
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- let mut err = struct_span_err!(item.tcx.sess, span, E0013,
- "{}s cannot refer to statics, use \
- a constant instead", item.mode);
- if item.tcx.sess.teach(&err.get_code().unwrap()) {
- err.note(
- "Static and const variables can refer to other const variables. \
- But a const variable cannot refer to a static variable."
- );
- err.help(
- "To fix this, the value can be extracted as a const and then used."
- );
- }
- err.emit();
- }
- }
-
- /// An access to a thread-local `static`.
- #[derive(Debug)]
- pub struct ThreadLocalAccess;
- impl NonConstOp for ThreadLocalAccess {
- const IS_SUPPORTED_IN_MIRI: bool = false;
-
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- span_err!(item.tcx.sess, span, E0625,
- "thread-local statics cannot be \
- accessed at compile-time");
- }
- }
-
- #[derive(Debug)]
- pub struct Transmute;
- impl NonConstOp for Transmute {
- fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
- Some(tcx.features().const_transmute)
- }
-
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- emit_feature_err(
- &item.tcx.sess.parse_sess, sym::const_transmute,
- span, GateIssue::Language,
- &format!("The use of std::mem::transmute() \
- is gated in {}s", item.mode));
- }
- }
-
- #[derive(Debug)]
- pub struct UnionAccess;
- impl NonConstOp for UnionAccess {
- fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
- // Union accesses are stable in all contexts except `const fn`.
- item.mode != Mode::ConstFn || Self::feature_gate(item.tcx).unwrap()
- }
-
- fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
- Some(tcx.features().const_fn_union)
- }
-
- fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- emit_feature_err(
- &item.tcx.sess.parse_sess, sym::const_fn_union,
- span, GateIssue::Language,
- "unions in const fn are unstable",
- );
- }
- }
-}