Move non-const ops into their own module
This commit is contained in:
parent
e296436ee0
commit
b3e59bb291
4 changed files with 342 additions and 337 deletions
|
@ -4,8 +4,9 @@ use rustc::ty::{self, TyCtxt};
|
|||
|
||||
pub use self::qualifs::Qualif;
|
||||
|
||||
mod resolver;
|
||||
pub mod ops;
|
||||
mod qualifs;
|
||||
mod resolver;
|
||||
pub mod validation;
|
||||
|
||||
/// Information about the item currently being validated, as well as a reference to the global
|
||||
|
|
337
src/librustc_mir/transform/check_consts/ops.rs
Normal file
337
src/librustc_mir/transform/check_consts/ops.rs
Normal file
|
@ -0,0 +1,337 @@
|
|||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::BorrowKind;
|
||||
use rustc::session::config::nightly_options;
|
||||
use rustc::ty::TyCtxt;
|
||||
use syntax::feature_gate::{emit_feature_err, GateIssue};
|
||||
use syntax::symbol::sym;
|
||||
use syntax_pos::{Span, Symbol};
|
||||
|
||||
use super::Item;
|
||||
use super::validation::Mode;
|
||||
|
||||
/// An operation that is not *always* allowed in a const context.
|
||||
pub trait NonConstOp {
|
||||
/// Whether this operation can be evaluated by miri.
|
||||
const IS_SUPPORTED_IN_MIRI: bool = true;
|
||||
|
||||
/// Returns a boolean indicating whether the feature gate that would allow this operation is
|
||||
/// enabled, or `None` if such a feature gate does not exist.
|
||||
fn feature_gate(_tcx: TyCtxt<'tcx>) -> Option<bool> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns `true` if this operation is allowed in the given item.
|
||||
///
|
||||
/// This check should assume that we are not in a non-const `fn`, where all operations are
|
||||
/// legal.
|
||||
fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
|
||||
Self::feature_gate(item.tcx).unwrap_or(false)
|
||||
}
|
||||
|
||||
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
|
||||
let mut err = struct_span_err!(
|
||||
item.tcx.sess,
|
||||
span,
|
||||
E0019,
|
||||
"{} contains unimplemented expression type",
|
||||
item.mode
|
||||
);
|
||||
if item.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note("A function call isn't allowed in the const's initialization expression \
|
||||
because the expression's value must be known at compile-time.");
|
||||
err.note("Remember: you can't use a function call inside a const's initialization \
|
||||
expression! However, you can use it anywhere else.");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
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 {
|
||||
const IS_SUPPORTED_IN_MIRI: bool = false;
|
||||
|
||||
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",
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,14 +1,12 @@
|
|||
use rustc::hir::{self, def_id::DefId};
|
||||
use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
|
||||
use rustc::mir::*;
|
||||
use rustc::session::config::nightly_options;
|
||||
use rustc::ty::cast::CastTy;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc_data_structures::bit_set::BitSet;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::feature_gate::{emit_feature_err, GateIssue};
|
||||
use syntax::symbol::sym;
|
||||
use syntax_pos::{Span, Symbol};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
|
@ -19,6 +17,7 @@ use crate::dataflow as old_dataflow;
|
|||
use super::{Item, Qualif, is_lang_panic_fn};
|
||||
use super::resolver::{QualifResolver, FlowSensitiveResolver};
|
||||
use super::qualifs::{HasMutInterior, NeedsDrop};
|
||||
use super::ops::{self, NonConstOp};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum CheckOpResult {
|
||||
|
@ -91,43 +90,6 @@ impl fmt::Display for Mode {
|
|||
}
|
||||
}
|
||||
|
||||
/// An operation that is not *always* allowed in a const context.
|
||||
pub trait NonConstOp {
|
||||
/// Whether this operation can be evaluated by miri.
|
||||
const IS_SUPPORTED_IN_MIRI: bool = true;
|
||||
|
||||
/// Returns a boolean indicating whether the feature gate that would allow this operation is
|
||||
/// enabled, or `None` if such a feature gate does not exist.
|
||||
fn feature_gate(_tcx: TyCtxt<'tcx>) -> Option<bool> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns `true` if this operation is allowed in the given item.
|
||||
///
|
||||
/// This check should assume that we are not in a non-const `fn`, where all operations are
|
||||
/// legal.
|
||||
fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
|
||||
Self::feature_gate(item.tcx).unwrap_or(false)
|
||||
}
|
||||
|
||||
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
|
||||
let mut err = struct_span_err!(
|
||||
item.tcx.sess,
|
||||
span,
|
||||
E0019,
|
||||
"{} contains unimplemented expression type",
|
||||
item.mode
|
||||
);
|
||||
if item.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note("A function call isn't allowed in the const's initialization expression \
|
||||
because the expression's value must be known at compile-time.");
|
||||
err.note("Remember: you can't use a function call inside a const's initialization \
|
||||
expression! However, you can use it anywhere else.");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Qualifs<'a, 'mir, 'tcx> {
|
||||
has_mut_interior: FlowSensitiveResolver<'a, 'mir, 'tcx, HasMutInterior>,
|
||||
needs_drop: FlowSensitiveResolver<'a, 'mir, 'tcx, NeedsDrop>,
|
||||
|
@ -622,298 +584,3 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
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 {
|
||||
const IS_SUPPORTED_IN_MIRI: bool = false;
|
||||
|
||||
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",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ use std::usize;
|
|||
use rustc::hir::HirId;
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
use super::promote_consts::{self, Candidate, TempState};
|
||||
use crate::transform::check_consts::validation::{ops, NonConstOp};
|
||||
use crate::transform::check_consts::ops::{self, NonConstOp};
|
||||
|
||||
/// What kind of item we are in.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
|
Loading…
Reference in a new issue