Add structured errors for qualify_min_const_fn
checks
This commit is contained in:
parent
bfc10a89c3
commit
5ee5429e00
1 changed files with 220 additions and 3 deletions
|
@ -98,6 +98,34 @@ pub trait NonConstOp: std::fmt::Debug {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Abort;
|
||||||
|
impl NonConstOp for Abort {
|
||||||
|
const STOPS_CONST_CHECKING: bool = true;
|
||||||
|
|
||||||
|
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
|
mcf_status_in_item(ccx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
mcf_emit_error(ccx, span, "abort is not stable in const fn")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NonPrimitiveOp;
|
||||||
|
impl NonConstOp for NonPrimitiveOp {
|
||||||
|
const STOPS_CONST_CHECKING: bool = true;
|
||||||
|
|
||||||
|
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
|
mcf_status_in_item(ccx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
mcf_emit_error(ccx, span, "only int, `bool` and `char` operations are stable in const fn")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A function call where the callee is a pointer.
|
/// A function call where the callee is a pointer.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FnCallIndirect;
|
pub struct FnCallIndirect;
|
||||||
|
@ -130,7 +158,8 @@ impl NonConstOp for FnCallNonConst {
|
||||||
///
|
///
|
||||||
/// Contains the name of the feature that would allow the use of this function.
|
/// Contains the name of the feature that would allow the use of this function.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FnCallUnstable(pub DefId, pub Symbol);
|
pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
|
||||||
|
|
||||||
impl NonConstOp for FnCallUnstable {
|
impl NonConstOp for FnCallUnstable {
|
||||||
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
let FnCallUnstable(def_id, feature) = *self;
|
let FnCallUnstable(def_id, feature) = *self;
|
||||||
|
@ -139,13 +168,51 @@ impl NonConstOp for FnCallUnstable {
|
||||||
span,
|
span,
|
||||||
&format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)),
|
&format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)),
|
||||||
);
|
);
|
||||||
if nightly_options::is_nightly_build() {
|
|
||||||
err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
|
if ccx.is_const_stable_const_fn() {
|
||||||
|
err.help("Const-stable functions can only call other const-stable functions");
|
||||||
|
} else if nightly_options::is_nightly_build() {
|
||||||
|
if let Some(feature) = feature {
|
||||||
|
err.help(&format!(
|
||||||
|
"add `#![feature({})]` to the crate attributes to enable",
|
||||||
|
feature
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FnPtrCast;
|
||||||
|
impl NonConstOp for FnPtrCast {
|
||||||
|
const STOPS_CONST_CHECKING: bool = true;
|
||||||
|
|
||||||
|
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
|
mcf_status_in_item(ccx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
mcf_emit_error(ccx, span, "function pointer casts are not allowed in const fn");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Generator;
|
||||||
|
impl NonConstOp for Generator {
|
||||||
|
const STOPS_CONST_CHECKING: bool = true;
|
||||||
|
|
||||||
|
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
|
// FIXME: This means generator-only MIR is only forbidden in const fn. This is for
|
||||||
|
// compatibility with the old code. Such MIR should be forbidden everywhere.
|
||||||
|
mcf_status_in_item(ccx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
mcf_emit_error(ccx, span, "const fn generators are unstable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HeapAllocation;
|
pub struct HeapAllocation;
|
||||||
impl NonConstOp for HeapAllocation {
|
impl NonConstOp for HeapAllocation {
|
||||||
|
@ -408,6 +475,24 @@ impl NonConstOp for ThreadLocalAccess {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Transmute;
|
||||||
|
impl NonConstOp for Transmute {
|
||||||
|
const STOPS_CONST_CHECKING: bool = true;
|
||||||
|
|
||||||
|
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
|
if ccx.const_kind() != hir::ConstContext::ConstFn {
|
||||||
|
Status::Allowed
|
||||||
|
} else {
|
||||||
|
Status::Unstable(sym::const_fn_transmute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
mcf_emit_error(ccx, span, "can only call `transmute` from const items, not `const fn`");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UnionAccess;
|
pub struct UnionAccess;
|
||||||
impl NonConstOp for UnionAccess {
|
impl NonConstOp for UnionAccess {
|
||||||
|
@ -430,3 +515,135 @@ impl NonConstOp for UnionAccess {
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [#64992].
|
||||||
|
///
|
||||||
|
/// [#64992]: https://github.com/rust-lang/rust/issues/64992
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UnsizingCast;
|
||||||
|
impl NonConstOp for UnsizingCast {
|
||||||
|
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
|
if ccx.const_kind() != hir::ConstContext::ConstFn {
|
||||||
|
Status::Allowed
|
||||||
|
} else {
|
||||||
|
Status::Unstable(sym::const_fn_transmute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
mcf_emit_error(
|
||||||
|
ccx,
|
||||||
|
span,
|
||||||
|
"unsizing casts to types besides slices are not allowed in const fn",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod ty {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MutRef;
|
||||||
|
impl NonConstOp for MutRef {
|
||||||
|
const STOPS_CONST_CHECKING: bool = true;
|
||||||
|
|
||||||
|
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
|
Status::Unstable(sym::const_mut_refs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
mcf_emit_error(ccx, span, "mutable references in const fn are unstable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FnPtr;
|
||||||
|
impl NonConstOp for FnPtr {
|
||||||
|
const STOPS_CONST_CHECKING: bool = true;
|
||||||
|
|
||||||
|
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
|
// FIXME: This attribute a hack to allow the specialization of the `futures` API. See
|
||||||
|
// #59739. We should have a proper feature gate for this.
|
||||||
|
if ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_allow_const_fn_ptr) {
|
||||||
|
Status::Allowed
|
||||||
|
} else {
|
||||||
|
mcf_status_in_item(ccx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
mcf_emit_error(ccx, span, "function pointers in const fn are unstable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ImplTrait;
|
||||||
|
impl NonConstOp for ImplTrait {
|
||||||
|
const STOPS_CONST_CHECKING: bool = true;
|
||||||
|
|
||||||
|
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
|
mcf_status_in_item(ccx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
mcf_emit_error(ccx, span, "`impl Trait` in const fn is unstable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TraitBound;
|
||||||
|
impl NonConstOp for TraitBound {
|
||||||
|
const STOPS_CONST_CHECKING: bool = true;
|
||||||
|
|
||||||
|
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
|
mcf_status_in_item(ccx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
mcf_emit_error(
|
||||||
|
ccx,
|
||||||
|
span,
|
||||||
|
"trait bounds other than `Sized` on const fn parameters are unstable",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait bound with the `?const Trait` opt-out
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TraitBoundNotConst;
|
||||||
|
impl NonConstOp for TraitBoundNotConst {
|
||||||
|
const STOPS_CONST_CHECKING: bool = true;
|
||||||
|
|
||||||
|
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||||
|
Status::Unstable(sym::const_trait_bound_opt_out)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
|
||||||
|
feature_err(
|
||||||
|
&ccx.tcx.sess.parse_sess,
|
||||||
|
sym::const_trait_bound_opt_out,
|
||||||
|
span,
|
||||||
|
"`?const Trait` syntax is unstable",
|
||||||
|
)
|
||||||
|
.emit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mcf_status_in_item(ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
|
if ccx.const_kind() != hir::ConstContext::ConstFn {
|
||||||
|
Status::Allowed
|
||||||
|
} else {
|
||||||
|
Status::Unstable(sym::const_fn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mcf_emit_error(ccx: &ConstCx<'_, '_>, span: Span, msg: &str) {
|
||||||
|
struct_span_err!(ccx.tcx.sess, span, E0723, "{}", msg)
|
||||||
|
.note(
|
||||||
|
"see issue #57563 <https://github.com/rust-lang/rust/issues/57563> \
|
||||||
|
for more information",
|
||||||
|
)
|
||||||
|
.help("add `#![feature(const_fn)]` to the crate attributes to enable")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue