Use enum for status of non-const ops
This commit is contained in:
parent
9b4154193e
commit
ed6c7efd87
@ -14,35 +14,32 @@ use super::ConstCx;
|
||||
pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
|
||||
debug!("illegal_op: op={:?}", op);
|
||||
|
||||
if op.is_allowed_in_item(ccx) {
|
||||
return;
|
||||
}
|
||||
let gate = match op.status_in_item(ccx) {
|
||||
Status::Allowed => return,
|
||||
Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => return,
|
||||
Status::Unstable(gate) => Some(gate),
|
||||
Status::Forbidden => None,
|
||||
};
|
||||
|
||||
if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
|
||||
ccx.tcx.sess.miri_unleashed_feature(span, O::feature_gate());
|
||||
ccx.tcx.sess.miri_unleashed_feature(span, gate);
|
||||
return;
|
||||
}
|
||||
|
||||
op.emit_error(ccx, span);
|
||||
}
|
||||
|
||||
pub enum Status {
|
||||
Allowed,
|
||||
Unstable(Symbol),
|
||||
Forbidden,
|
||||
}
|
||||
|
||||
/// An operation that is not *always* allowed in a const context.
|
||||
pub trait NonConstOp: std::fmt::Debug {
|
||||
/// Returns the `Symbol` corresponding to the feature gate that would enable this operation,
|
||||
/// or `None` if such a feature gate does not exist.
|
||||
fn feature_gate() -> Option<Symbol> {
|
||||
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.
|
||||
///
|
||||
/// By default, it returns `true` if and only if this operation has a corresponding feature
|
||||
/// gate and that gate is enabled.
|
||||
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
|
||||
Self::feature_gate().map_or(false, |gate| ccx.tcx.features().enabled(gate))
|
||||
/// Returns an enum indicating whether this operation is allowed within the given item.
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
|
||||
Status::Forbidden
|
||||
}
|
||||
|
||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||
@ -53,9 +50,13 @@ pub trait NonConstOp: std::fmt::Debug {
|
||||
"{} contains unimplemented expression type",
|
||||
ccx.const_kind()
|
||||
);
|
||||
if let Some(feat) = Self::feature_gate() {
|
||||
err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feat));
|
||||
|
||||
if let Status::Unstable(gate) = self.status_in_item(ccx) {
|
||||
if !ccx.tcx.features().enabled(gate) && nightly_options::is_nightly_build() {
|
||||
err.help(&format!("add `#![feature({})]` to the crate attributes to enable", gate));
|
||||
}
|
||||
}
|
||||
|
||||
if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note(
|
||||
"A function call isn't allowed in the const's initialization expression \
|
||||
@ -182,14 +183,13 @@ impl NonConstOp for CellBorrow {
|
||||
#[derive(Debug)]
|
||||
pub struct MutBorrow;
|
||||
impl NonConstOp for MutBorrow {
|
||||
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
|
||||
// Forbid everywhere except in const fn
|
||||
ccx.const_kind() == hir::ConstContext::ConstFn
|
||||
&& ccx.tcx.features().enabled(Self::feature_gate().unwrap())
|
||||
}
|
||||
|
||||
fn feature_gate() -> Option<Symbol> {
|
||||
Some(sym::const_mut_refs)
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||
// Forbid everywhere except in const fn with a feature gate
|
||||
if ccx.const_kind() == hir::ConstContext::ConstFn {
|
||||
Status::Unstable(sym::const_mut_refs)
|
||||
} else {
|
||||
Status::Forbidden
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||
@ -201,15 +201,16 @@ impl NonConstOp for MutBorrow {
|
||||
&format!("mutable references are not allowed in {}s", ccx.const_kind()),
|
||||
)
|
||||
} else {
|
||||
struct_span_err!(
|
||||
let mut err = struct_span_err!(
|
||||
ccx.tcx.sess,
|
||||
span,
|
||||
E0764,
|
||||
"mutable references are not allowed in {}s",
|
||||
ccx.const_kind(),
|
||||
)
|
||||
);
|
||||
err.span_label(span, format!("`&mut` is only allowed in `const fn`"));
|
||||
err
|
||||
};
|
||||
err.span_label(span, "`&mut` is only allowed in `const fn`".to_string());
|
||||
if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note(
|
||||
"References in statics and constants may only refer \
|
||||
@ -226,11 +227,17 @@ impl NonConstOp for MutBorrow {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues.
|
||||
#[derive(Debug)]
|
||||
pub struct MutAddressOf;
|
||||
impl NonConstOp for MutAddressOf {
|
||||
fn feature_gate() -> Option<Symbol> {
|
||||
Some(sym::const_mut_refs)
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||
// Forbid everywhere except in const fn with a feature gate
|
||||
if ccx.const_kind() == hir::ConstContext::ConstFn {
|
||||
Status::Unstable(sym::const_mut_refs)
|
||||
} else {
|
||||
Status::Forbidden
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||
@ -247,16 +254,16 @@ impl NonConstOp for MutAddressOf {
|
||||
#[derive(Debug)]
|
||||
pub struct MutDeref;
|
||||
impl NonConstOp for MutDeref {
|
||||
fn feature_gate() -> Option<Symbol> {
|
||||
Some(sym::const_mut_refs)
|
||||
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||
Status::Unstable(sym::const_mut_refs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Panic;
|
||||
impl NonConstOp for Panic {
|
||||
fn feature_gate() -> Option<Symbol> {
|
||||
Some(sym::const_panic)
|
||||
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||
Status::Unstable(sym::const_panic)
|
||||
}
|
||||
|
||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||
@ -289,8 +296,8 @@ impl NonConstOp for RawPtrComparison {
|
||||
#[derive(Debug)]
|
||||
pub struct RawPtrDeref;
|
||||
impl NonConstOp for RawPtrDeref {
|
||||
fn feature_gate() -> Option<Symbol> {
|
||||
Some(sym::const_raw_ptr_deref)
|
||||
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||
Status::Unstable(sym::const_raw_ptr_deref)
|
||||
}
|
||||
|
||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||
@ -307,8 +314,8 @@ impl NonConstOp for RawPtrDeref {
|
||||
#[derive(Debug)]
|
||||
pub struct RawPtrToIntCast;
|
||||
impl NonConstOp for RawPtrToIntCast {
|
||||
fn feature_gate() -> Option<Symbol> {
|
||||
Some(sym::const_raw_ptr_to_usize_cast)
|
||||
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||
Status::Unstable(sym::const_raw_ptr_to_usize_cast)
|
||||
}
|
||||
|
||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||
@ -326,8 +333,12 @@ impl NonConstOp for RawPtrToIntCast {
|
||||
#[derive(Debug)]
|
||||
pub struct StaticAccess;
|
||||
impl NonConstOp for StaticAccess {
|
||||
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
|
||||
matches!(ccx.const_kind(), hir::ConstContext::Static(_))
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||
if let hir::ConstContext::Static(_) = ccx.const_kind() {
|
||||
Status::Allowed
|
||||
} else {
|
||||
Status::Forbidden
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||
@ -371,14 +382,13 @@ impl NonConstOp for ThreadLocalAccess {
|
||||
#[derive(Debug)]
|
||||
pub struct UnionAccess;
|
||||
impl NonConstOp for UnionAccess {
|
||||
fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||
// Union accesses are stable in all contexts except `const fn`.
|
||||
ccx.const_kind() != hir::ConstContext::ConstFn
|
||||
|| ccx.tcx.features().enabled(Self::feature_gate().unwrap())
|
||||
}
|
||||
|
||||
fn feature_gate() -> Option<Symbol> {
|
||||
Some(sym::const_fn_union)
|
||||
if ccx.const_kind() != hir::ConstContext::ConstFn {
|
||||
Status::Allowed
|
||||
} else {
|
||||
Status::Unstable(sym::const_fn_union)
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user