Auto merge of #76850 - ecstatic-morse:const-checking-refactor, r=oli-obk
Remove `qualify_min_const_fn` ~~Blocked on #76807 (the first six commits).~~ With this PR, all checks in `qualify_min_const_fn` are replicated in `check_consts`, and the former is no longer invoked. My goal was to have as few changes to test output as possible, since making sweeping changes to the code *while* doing big batches of diagnostics updates turned out to be a headache. To this end, there's a few `HACK`s in `check_consts` to achieve parity with `qualify_min_const_fn`. The new system that replaces `is_min_const_fn` is referred to as "const-stability" My end goal for the const-stability rules is this: * Const-stability is only applicable to functions defined in `staged_api` crates. * All functions not marked `rustc_const_unstable` are considered "const-stable". - NB. This is currently not implemented. `#[unstable]` functions are also const-unstable. This causes problems when searching for feature gates. - All "const-unstable" functions have an associated feature gate * const-stable functions can only call other const-stable functions - `allow_internal_unstable` can be used to circumvent this. * All const-stable functions are subject to some additional checks (the ones that were unique to `qualify_min_const_fn`) The plan is to remove each `HACK` individually in subsequent PRs. That way, changes to error message output can be reviewed in isolation.
This commit is contained in:
commit
f6d59207ad
54 changed files with 789 additions and 257 deletions
|
@ -7,6 +7,7 @@
|
||||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(const_fn)] // For the `transmute` in `P::new`
|
#![feature(const_fn)] // For the `transmute` in `P::new`
|
||||||
|
#![feature(const_fn_transmute)]
|
||||||
#![feature(const_panic)]
|
#![feature(const_panic)]
|
||||||
#![feature(crate_visibility_modifier)]
|
#![feature(crate_visibility_modifier)]
|
||||||
#![feature(label_break_value)]
|
#![feature(label_break_value)]
|
||||||
|
|
|
@ -51,6 +51,12 @@ impl ConstCx<'mir, 'tcx> {
|
||||||
pub fn const_kind(&self) -> hir::ConstContext {
|
pub fn const_kind(&self) -> hir::ConstContext {
|
||||||
self.const_kind.expect("`const_kind` must not be called on a non-const fn")
|
self.const_kind.expect("`const_kind` must not be called on a non-const fn")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_const_stable_const_fn(&self) -> bool {
|
||||||
|
self.const_kind == Some(hir::ConstContext::ConstFn)
|
||||||
|
&& self.tcx.features().staged_api
|
||||||
|
&& is_const_stable_const_fn(self.tcx, self.def_id.to_def_id())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if this `DefId` points to one of the official `panic` lang items.
|
/// Returns `true` if this `DefId` points to one of the official `panic` lang items.
|
||||||
|
@ -63,3 +69,37 @@ pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: S
|
||||||
attr::allow_internal_unstable(&tcx.sess, attrs)
|
attr::allow_internal_unstable(&tcx.sess, attrs)
|
||||||
.map_or(false, |mut features| features.any(|name| name == feature_gate))
|
.map_or(false, |mut features| features.any(|name| name == feature_gate))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns `true` if the given `const fn` is "const-stable".
|
||||||
|
//
|
||||||
|
// Panics if the given `DefId` does not refer to a `const fn`.
|
||||||
|
//
|
||||||
|
// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable"
|
||||||
|
// functions can be called in a const-context by users of the stable compiler. "const-stable"
|
||||||
|
// functions are subject to more stringent restrictions than "const-unstable" functions: They
|
||||||
|
// cannot use unstable features and can only call other "const-stable" functions.
|
||||||
|
pub fn is_const_stable_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
|
||||||
|
use attr::{ConstStability, Stability, StabilityLevel};
|
||||||
|
|
||||||
|
// Const-stability is only relevant for `const fn`.
|
||||||
|
assert!(tcx.is_const_fn_raw(def_id));
|
||||||
|
|
||||||
|
// Functions with `#[rustc_const_unstable]` are const-unstable.
|
||||||
|
match tcx.lookup_const_stability(def_id) {
|
||||||
|
Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false,
|
||||||
|
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true,
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions with `#[unstable]` are const-unstable.
|
||||||
|
//
|
||||||
|
// FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability
|
||||||
|
// attributes. `#[unstable]` should be irrelevant.
|
||||||
|
if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) =
|
||||||
|
tcx.lookup_stability(def_id)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
|
@ -10,33 +10,34 @@ use rustc_span::{Span, Symbol};
|
||||||
|
|
||||||
use super::ConstCx;
|
use super::ConstCx;
|
||||||
|
|
||||||
/// Emits an error if `op` is not allowed in the given const context.
|
/// Emits an error and returns `true` if `op` is not allowed in the given const context.
|
||||||
pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
|
pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) -> bool {
|
||||||
debug!("illegal_op: op={:?}", op);
|
debug!("illegal_op: op={:?}", op);
|
||||||
|
|
||||||
let gate = match op.status_in_item(ccx) {
|
let gate = match op.status_in_item(ccx) {
|
||||||
Status::Allowed => return,
|
Status::Allowed => return false,
|
||||||
|
|
||||||
Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => {
|
Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => {
|
||||||
let unstable_in_stable = ccx.const_kind() == hir::ConstContext::ConstFn
|
let unstable_in_stable = ccx.is_const_stable_const_fn()
|
||||||
&& ccx.tcx.features().enabled(sym::staged_api)
|
|
||||||
&& !ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_const_unstable)
|
|
||||||
&& !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate);
|
&& !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate);
|
||||||
|
|
||||||
if unstable_in_stable {
|
if unstable_in_stable {
|
||||||
ccx.tcx.sess
|
ccx.tcx.sess
|
||||||
.struct_span_err(span, &format!("`#[feature({})]` cannot be depended on in a const-stable function", gate.as_str()))
|
.struct_span_err(
|
||||||
|
span,
|
||||||
|
&format!("const-stable function cannot use `#[feature({})]`", gate.as_str()),
|
||||||
|
)
|
||||||
.span_suggestion(
|
.span_suggestion(
|
||||||
ccx.body.span,
|
ccx.body.span,
|
||||||
"if it is not part of the public API, make this function unstably const",
|
"if it is not part of the public API, make this function unstably const",
|
||||||
concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(),
|
concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(),
|
||||||
Applicability::HasPlaceholders,
|
Applicability::HasPlaceholders,
|
||||||
)
|
)
|
||||||
.help("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks")
|
.note("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks")
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return unstable_in_stable;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status::Unstable(gate) => Some(gate),
|
Status::Unstable(gate) => Some(gate),
|
||||||
|
@ -45,12 +46,14 @@ pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
|
||||||
|
|
||||||
if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
|
if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
|
||||||
ccx.tcx.sess.miri_unleashed_feature(span, gate);
|
ccx.tcx.sess.miri_unleashed_feature(span, gate);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
op.emit_error(ccx, span);
|
op.emit_error(ccx, span);
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
Allowed,
|
Allowed,
|
||||||
Unstable(Symbol),
|
Unstable(Symbol),
|
||||||
|
@ -59,6 +62,8 @@ pub enum Status {
|
||||||
|
|
||||||
/// An operation that is not *always* allowed in a const context.
|
/// An operation that is not *always* allowed in a const context.
|
||||||
pub trait NonConstOp: std::fmt::Debug {
|
pub trait NonConstOp: std::fmt::Debug {
|
||||||
|
const STOPS_CONST_CHECKING: bool = false;
|
||||||
|
|
||||||
/// Returns an enum indicating whether this operation is allowed within the given item.
|
/// Returns an enum indicating whether this operation is allowed within the given item.
|
||||||
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
|
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
|
||||||
Status::Forbidden
|
Status::Forbidden
|
||||||
|
@ -93,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;
|
||||||
|
@ -125,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;
|
||||||
|
@ -134,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 {
|
||||||
|
@ -403,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 {
|
||||||
|
@ -425,3 +515,131 @@ 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 {
|
||||||
|
mcf_status_in_item(ccx)
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_middle::mir::visit::Visitor;
|
use rustc_middle::mir::visit::Visitor;
|
||||||
use rustc_middle::mir::{self, BasicBlock, Location};
|
use rustc_middle::mir::{self, BasicBlock, Location};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::{sym, Span};
|
use rustc_span::Span;
|
||||||
|
|
||||||
use super::ops;
|
use super::ops;
|
||||||
use super::qualifs::{NeedsDrop, Qualif};
|
use super::qualifs::{NeedsDrop, Qualif};
|
||||||
|
@ -11,13 +11,13 @@ use super::ConstCx;
|
||||||
|
|
||||||
/// Returns `true` if we should use the more precise live drop checker that runs after drop
|
/// Returns `true` if we should use the more precise live drop checker that runs after drop
|
||||||
/// elaboration.
|
/// elaboration.
|
||||||
pub fn checking_enabled(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
|
pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool {
|
||||||
// Const-stable functions must always use the stable live drop checker.
|
// Const-stable functions must always use the stable live drop checker.
|
||||||
if tcx.features().staged_api && !tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable) {
|
if ccx.is_const_stable_const_fn() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcx.features().const_precise_live_drops
|
ccx.tcx.features().const_precise_live_drops
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Look for live drops in a const context.
|
/// Look for live drops in a const context.
|
||||||
|
@ -30,12 +30,11 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body<
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !checking_enabled(tcx, def_id) {
|
let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) };
|
||||||
|
if !checking_enabled(&ccx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) };
|
|
||||||
|
|
||||||
let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() };
|
let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() };
|
||||||
|
|
||||||
visitor.visit_body(body);
|
visitor.visit_body(body);
|
||||||
|
|
|
@ -7,19 +7,21 @@ use rustc_infer::infer::TyCtxtInferExt;
|
||||||
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
|
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::cast::CastTy;
|
use rustc_middle::ty::cast::CastTy;
|
||||||
use rustc_middle::ty::{self, Instance, InstanceDef, TyCtxt};
|
use rustc_middle::ty::subst::GenericArgKind;
|
||||||
use rustc_span::Span;
|
use rustc_middle::ty::{
|
||||||
|
self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut,
|
||||||
|
};
|
||||||
|
use rustc_span::{sym, Span};
|
||||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::{self, TraitEngine};
|
use rustc_trait_selection::traits::{self, TraitEngine};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use super::ops::{self, NonConstOp};
|
use super::ops::{self, NonConstOp};
|
||||||
use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
|
use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
|
||||||
use super::resolver::FlowSensitiveAnalysis;
|
use super::resolver::FlowSensitiveAnalysis;
|
||||||
use super::{is_lang_panic_fn, ConstCx, Qualif};
|
use super::{is_lang_panic_fn, ConstCx, Qualif};
|
||||||
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
|
use crate::const_eval::is_unstable_const_fn;
|
||||||
use crate::dataflow::impls::MaybeMutBorrowedLocals;
|
use crate::dataflow::impls::MaybeMutBorrowedLocals;
|
||||||
use crate::dataflow::{self, Analysis};
|
use crate::dataflow::{self, Analysis};
|
||||||
|
|
||||||
|
@ -176,6 +178,8 @@ pub struct Validator<'mir, 'tcx> {
|
||||||
|
|
||||||
/// The span of the current statement.
|
/// The span of the current statement.
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
||||||
|
const_checking_stopped: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Validator<'mir, 'tcx> {
|
impl Deref for Validator<'mir, 'tcx> {
|
||||||
|
@ -188,30 +192,60 @@ impl Deref for Validator<'mir, 'tcx> {
|
||||||
|
|
||||||
impl Validator<'mir, 'tcx> {
|
impl Validator<'mir, 'tcx> {
|
||||||
pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
|
pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
|
||||||
Validator { span: ccx.body.span, ccx, qualifs: Default::default() }
|
Validator {
|
||||||
|
span: ccx.body.span,
|
||||||
|
ccx,
|
||||||
|
qualifs: Default::default(),
|
||||||
|
const_checking_stopped: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_body(&mut self) {
|
pub fn check_body(&mut self) {
|
||||||
let ConstCx { tcx, body, def_id, const_kind, .. } = *self.ccx;
|
let ConstCx { tcx, body, def_id, .. } = *self.ccx;
|
||||||
|
|
||||||
let use_min_const_fn_checks = (const_kind == Some(hir::ConstContext::ConstFn)
|
// HACK: This function has side-effects???? Make sure we call it.
|
||||||
&& crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id()))
|
let _ = crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id());
|
||||||
&& !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
|
|
||||||
|
|
||||||
if use_min_const_fn_checks {
|
// The local type and predicate checks are not free and only relevant for `const fn`s.
|
||||||
// Enforce `min_const_fn` for stable `const fn`s.
|
if self.const_kind() == hir::ConstContext::ConstFn {
|
||||||
use crate::transform::qualify_min_const_fn::is_min_const_fn;
|
// Prevent const trait methods from being annotated as `stable`.
|
||||||
if let Err((span, err)) = is_min_const_fn(tcx, def_id.to_def_id(), &body) {
|
// FIXME: Do this as part of stability checking.
|
||||||
error_min_const_fn_violation(tcx, span, err);
|
if self.is_const_stable_const_fn() {
|
||||||
return;
|
let hir_id = tcx.hir().local_def_id_to_hir_id(self.def_id);
|
||||||
|
if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) {
|
||||||
|
struct_span_err!(
|
||||||
|
self.ccx.tcx.sess,
|
||||||
|
self.span,
|
||||||
|
E0723,
|
||||||
|
"trait methods cannot be stable const fn"
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.check_item_predicates();
|
||||||
|
|
||||||
|
for local in &body.local_decls {
|
||||||
|
if local.internal {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.span = local.source_info.span;
|
||||||
|
self.check_local_or_return_ty(local.ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl trait is gone in MIR, so check the return type of a const fn by its signature
|
||||||
|
// instead of the type of the return place.
|
||||||
|
self.span = body.local_decls[RETURN_PLACE].source_info.span;
|
||||||
|
let return_ty = tcx.fn_sig(def_id).output();
|
||||||
|
self.check_local_or_return_ty(return_ty.skip_binder());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_body(&body);
|
self.visit_body(&body);
|
||||||
|
|
||||||
// Ensure that the end result is `Sync` in a non-thread local `static`.
|
// Ensure that the end result is `Sync` in a non-thread local `static`.
|
||||||
let should_check_for_sync = const_kind
|
let should_check_for_sync = self.const_kind()
|
||||||
== Some(hir::ConstContext::Static(hir::Mutability::Not))
|
== hir::ConstContext::Static(hir::Mutability::Not)
|
||||||
&& !tcx.is_thread_local_static(def_id.to_def_id());
|
&& !tcx.is_thread_local_static(def_id.to_def_id());
|
||||||
|
|
||||||
if should_check_for_sync {
|
if should_check_for_sync {
|
||||||
|
@ -226,13 +260,22 @@ impl Validator<'mir, 'tcx> {
|
||||||
|
|
||||||
/// Emits an error if an expression cannot be evaluated in the current context.
|
/// Emits an error if an expression cannot be evaluated in the current context.
|
||||||
pub fn check_op(&mut self, op: impl NonConstOp) {
|
pub fn check_op(&mut self, op: impl NonConstOp) {
|
||||||
ops::non_const(self.ccx, op, self.span);
|
self.check_op_spanned(op, self.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emits an error at the given `span` if an expression cannot be evaluated in the current
|
/// Emits an error at the given `span` if an expression cannot be evaluated in the current
|
||||||
/// context.
|
/// context.
|
||||||
pub fn check_op_spanned(&mut self, op: impl NonConstOp, span: Span) {
|
pub fn check_op_spanned<O: NonConstOp>(&mut self, op: O, span: Span) {
|
||||||
ops::non_const(self.ccx, op, span);
|
// HACK: This is for strict equivalence with the old `qualify_min_const_fn` pass, which
|
||||||
|
// only emitted one error per function. It should be removed and the test output updated.
|
||||||
|
if self.const_checking_stopped {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let err_emitted = ops::non_const(self.ccx, op, span);
|
||||||
|
if err_emitted && O::STOPS_CONST_CHECKING {
|
||||||
|
self.const_checking_stopped = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_static(&mut self, def_id: DefId, span: Span) {
|
fn check_static(&mut self, def_id: DefId, span: Span) {
|
||||||
|
@ -242,6 +285,100 @@ impl Validator<'mir, 'tcx> {
|
||||||
);
|
);
|
||||||
self.check_op_spanned(ops::StaticAccess, span)
|
self.check_op_spanned(ops::StaticAccess, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>) {
|
||||||
|
for ty in ty.walk() {
|
||||||
|
let ty = match ty.unpack() {
|
||||||
|
GenericArgKind::Type(ty) => ty,
|
||||||
|
|
||||||
|
// No constraints on lifetimes or constants, except potentially
|
||||||
|
// constants' types, but `walk` will get to them as well.
|
||||||
|
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
match *ty.kind() {
|
||||||
|
ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef),
|
||||||
|
ty::Opaque(..) => self.check_op(ops::ty::ImplTrait),
|
||||||
|
ty::FnPtr(..) => self.check_op(ops::ty::FnPtr),
|
||||||
|
|
||||||
|
ty::Dynamic(preds, _) => {
|
||||||
|
for pred in preds.iter() {
|
||||||
|
match pred.skip_binder() {
|
||||||
|
ty::ExistentialPredicate::AutoTrait(_)
|
||||||
|
| ty::ExistentialPredicate::Projection(_) => {
|
||||||
|
self.check_op(ops::ty::TraitBound)
|
||||||
|
}
|
||||||
|
ty::ExistentialPredicate::Trait(trait_ref) => {
|
||||||
|
if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() {
|
||||||
|
self.check_op(ops::ty::TraitBound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_item_predicates(&mut self) {
|
||||||
|
let ConstCx { tcx, def_id, .. } = *self.ccx;
|
||||||
|
|
||||||
|
let mut current = def_id.to_def_id();
|
||||||
|
loop {
|
||||||
|
let predicates = tcx.predicates_of(current);
|
||||||
|
for (predicate, _) in predicates.predicates {
|
||||||
|
match predicate.skip_binders() {
|
||||||
|
ty::PredicateAtom::RegionOutlives(_)
|
||||||
|
| ty::PredicateAtom::TypeOutlives(_)
|
||||||
|
| ty::PredicateAtom::WellFormed(_)
|
||||||
|
| ty::PredicateAtom::Projection(_)
|
||||||
|
| ty::PredicateAtom::ConstEvaluatable(..)
|
||||||
|
| ty::PredicateAtom::ConstEquate(..)
|
||||||
|
| ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue,
|
||||||
|
ty::PredicateAtom::ObjectSafe(_) => {
|
||||||
|
bug!("object safe predicate on function: {:#?}", predicate)
|
||||||
|
}
|
||||||
|
ty::PredicateAtom::ClosureKind(..) => {
|
||||||
|
bug!("closure kind predicate on function: {:#?}", predicate)
|
||||||
|
}
|
||||||
|
ty::PredicateAtom::Subtype(_) => {
|
||||||
|
bug!("subtype predicate on function: {:#?}", predicate)
|
||||||
|
}
|
||||||
|
ty::PredicateAtom::Trait(pred, constness) => {
|
||||||
|
if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match pred.self_ty().kind() {
|
||||||
|
ty::Param(p) => {
|
||||||
|
let generics = tcx.generics_of(current);
|
||||||
|
let def = generics.type_param(p, tcx);
|
||||||
|
let span = tcx.def_span(def.def_id);
|
||||||
|
|
||||||
|
if constness == hir::Constness::Const {
|
||||||
|
self.check_op_spanned(ops::ty::TraitBound, span);
|
||||||
|
} else if !tcx.features().const_fn
|
||||||
|
|| self.ccx.is_const_stable_const_fn()
|
||||||
|
{
|
||||||
|
// HACK: We shouldn't need the conditional above, but trait
|
||||||
|
// bounds on containing impl blocks are wrongly being marked as
|
||||||
|
// "not-const".
|
||||||
|
self.check_op_spanned(ops::ty::TraitBound, span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// other kinds of bounds are either tautologies
|
||||||
|
// or cause errors in other passes
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match predicates.parent {
|
||||||
|
Some(parent) => current = parent,
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
|
@ -309,11 +446,6 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
|
|
||||||
Rvalue::Use(_)
|
Rvalue::Use(_)
|
||||||
| Rvalue::Repeat(..)
|
| Rvalue::Repeat(..)
|
||||||
| Rvalue::UnaryOp(UnOp::Neg, _)
|
|
||||||
| Rvalue::UnaryOp(UnOp::Not, _)
|
|
||||||
| Rvalue::NullaryOp(NullOp::SizeOf, _)
|
|
||||||
| Rvalue::CheckedBinaryOp(..)
|
|
||||||
| Rvalue::Cast(CastKind::Pointer(_), ..)
|
|
||||||
| Rvalue::Discriminant(..)
|
| Rvalue::Discriminant(..)
|
||||||
| Rvalue::Len(_)
|
| Rvalue::Len(_)
|
||||||
| Rvalue::Aggregate(..) => {}
|
| Rvalue::Aggregate(..) => {}
|
||||||
|
@ -363,6 +495,35 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rvalue::Cast(
|
||||||
|
CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
) => {}
|
||||||
|
|
||||||
|
Rvalue::Cast(
|
||||||
|
CastKind::Pointer(
|
||||||
|
PointerCast::UnsafeFnPointer
|
||||||
|
| PointerCast::ClosureFnPointer(_)
|
||||||
|
| PointerCast::ReifyFnPointer,
|
||||||
|
),
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
) => self.check_op(ops::FnPtrCast),
|
||||||
|
|
||||||
|
Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, cast_ty) => {
|
||||||
|
if let Some(TypeAndMut { ty, .. }) = cast_ty.builtin_deref(true) {
|
||||||
|
let unsized_ty = self.tcx.struct_tail_erasing_lifetimes(ty, self.param_env);
|
||||||
|
|
||||||
|
// Casting/coercing things to slices is fine.
|
||||||
|
if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.check_op(ops::UnsizingCast);
|
||||||
|
}
|
||||||
|
|
||||||
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
|
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
|
||||||
let operand_ty = operand.ty(self.body, self.tcx);
|
let operand_ty = operand.ty(self.body, self.tcx);
|
||||||
let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
|
let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
|
||||||
|
@ -373,8 +534,23 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::BinaryOp(op, ref lhs, _) => {
|
Rvalue::NullaryOp(NullOp::SizeOf, _) => {}
|
||||||
if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() {
|
Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation),
|
||||||
|
|
||||||
|
Rvalue::UnaryOp(_, ref operand) => {
|
||||||
|
let ty = operand.ty(self.body, self.tcx);
|
||||||
|
if !(ty.is_integral() || ty.is_bool()) {
|
||||||
|
self.check_op(ops::NonPrimitiveOp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rvalue::BinaryOp(op, ref lhs, ref rhs)
|
||||||
|
| Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
|
||||||
|
let lhs_ty = lhs.ty(self.body, self.tcx);
|
||||||
|
let rhs_ty = rhs.ty(self.body, self.tcx);
|
||||||
|
|
||||||
|
if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() {
|
||||||
|
assert_eq!(lhs_ty, rhs_ty);
|
||||||
assert!(
|
assert!(
|
||||||
op == BinOp::Eq
|
op == BinOp::Eq
|
||||||
|| op == BinOp::Ne
|
|| op == BinOp::Ne
|
||||||
|
@ -387,10 +563,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
|
|
||||||
self.check_op(ops::RawPtrComparison);
|
self.check_op(ops::RawPtrComparison);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Rvalue::NullaryOp(NullOp::Box, _) => {
|
if !(lhs_ty.is_integral() || lhs_ty.is_bool() || lhs_ty.is_char())
|
||||||
self.check_op(ops::HeapAllocation);
|
|| !(rhs_ty.is_integral() || rhs_ty.is_bool() || rhs_ty.is_char())
|
||||||
|
{
|
||||||
|
self.check_op(ops::NonPrimitiveOp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -491,14 +669,19 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
||||||
|
use rustc_target::spec::abi::Abi::RustIntrinsic;
|
||||||
|
|
||||||
trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
|
trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
|
||||||
self.super_terminator(terminator, location);
|
self.super_terminator(terminator, location);
|
||||||
|
|
||||||
match &terminator.kind {
|
match &terminator.kind {
|
||||||
TerminatorKind::Call { func, .. } => {
|
TerminatorKind::Call { func, .. } => {
|
||||||
let fn_ty = func.ty(self.body, self.tcx);
|
let ConstCx { tcx, body, def_id: caller, param_env, .. } = *self.ccx;
|
||||||
|
let caller = caller.to_def_id();
|
||||||
|
|
||||||
let (def_id, substs) = match *fn_ty.kind() {
|
let fn_ty = func.ty(body, tcx);
|
||||||
|
|
||||||
|
let (mut callee, substs) = match *fn_ty.kind() {
|
||||||
ty::FnDef(def_id, substs) => (def_id, substs),
|
ty::FnDef(def_id, substs) => (def_id, substs),
|
||||||
|
|
||||||
ty::FnPtr(_) => {
|
ty::FnPtr(_) => {
|
||||||
|
@ -510,38 +693,80 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// At this point, we are calling a function whose `DefId` is known...
|
// Resolve a trait method call to its concrete implementation, which may be in a
|
||||||
if is_const_fn(self.tcx, def_id) {
|
// `const` trait impl.
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if this is a trait method for a concrete type whose impl of that trait is
|
|
||||||
// `const`.
|
|
||||||
if self.tcx.features().const_trait_impl {
|
if self.tcx.features().const_trait_impl {
|
||||||
let instance = Instance::resolve(self.tcx, self.param_env, def_id, substs);
|
let instance = Instance::resolve(tcx, param_env, callee, substs);
|
||||||
debug!("Resolving ({:?}) -> {:?}", def_id, instance);
|
debug!("Resolving ({:?}) -> {:?}", callee, instance);
|
||||||
if let Ok(Some(func)) = instance {
|
if let Ok(Some(func)) = instance {
|
||||||
if let InstanceDef::Item(def) = func.def {
|
if let InstanceDef::Item(def) = func.def {
|
||||||
if is_const_fn(self.tcx, def.did) {
|
callee = def.did;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_lang_panic_fn(self.tcx, def_id) {
|
// At this point, we are calling a function, `callee`, whose `DefId` is known...
|
||||||
|
|
||||||
|
if is_lang_panic_fn(tcx, callee) {
|
||||||
self.check_op(ops::Panic);
|
self.check_op(ops::Panic);
|
||||||
} else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) {
|
return;
|
||||||
// Exempt unstable const fns inside of macros or functions with
|
}
|
||||||
// `#[allow_internal_unstable]`.
|
|
||||||
use crate::transform::qualify_min_const_fn::lib_feature_allowed;
|
// HACK: This is to "unstabilize" the `transmute` intrinsic
|
||||||
if !self.span.allows_unstable(feature)
|
// within const fns. `transmute` is allowed in all other const contexts.
|
||||||
&& !lib_feature_allowed(self.tcx, self.def_id.to_def_id(), feature)
|
// This won't really scale to more intrinsics or functions. Let's allow const
|
||||||
{
|
// transmutes in const fn before we add more hacks to this.
|
||||||
self.check_op(ops::FnCallUnstable(def_id, feature));
|
if tcx.fn_sig(callee).abi() == RustIntrinsic
|
||||||
|
&& tcx.item_name(callee) == sym::transmute
|
||||||
|
{
|
||||||
|
self.check_op(ops::Transmute);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tcx.is_const_fn_raw(callee) {
|
||||||
|
self.check_op(ops::FnCallNonConst(callee));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the `const fn` we are trying to call is not const-stable, ensure that we have
|
||||||
|
// the proper feature gate enabled.
|
||||||
|
if let Some(gate) = is_unstable_const_fn(tcx, callee) {
|
||||||
|
if self.span.allows_unstable(gate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calling an unstable function *always* requires that the corresponding gate
|
||||||
|
// be enabled, even if the function has `#[allow_internal_unstable(the_gate)]`.
|
||||||
|
if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) {
|
||||||
|
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this crate is not using stability attributes, or the caller is not claiming to be a
|
||||||
|
// stable `const fn`, that is all that is required.
|
||||||
|
if !self.ccx.is_const_stable_const_fn() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we are something const-stable calling a const-unstable fn.
|
||||||
|
|
||||||
|
if super::allow_internal_unstable(tcx, caller, gate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that
|
||||||
|
// have no `rustc_const_stable` attributes to be const-unstable as well. This
|
||||||
|
// should be fixed later.
|
||||||
|
let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
|
||||||
|
&& tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable());
|
||||||
|
if callee_is_unstable_unmarked {
|
||||||
|
if self.ccx.is_const_stable_const_fn() {
|
||||||
|
self.check_op(ops::FnCallUnstable(callee, None));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.check_op(ops::FnCallNonConst(def_id));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,7 +776,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
| TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
|
| TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
|
||||||
// If we are checking live drops after drop-elaboration, don't emit duplicate
|
// If we are checking live drops after drop-elaboration, don't emit duplicate
|
||||||
// errors here.
|
// errors here.
|
||||||
if super::post_drop_elaboration::checking_enabled(self.tcx, self.def_id) {
|
if super::post_drop_elaboration::checking_enabled(self.ccx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,37 +807,25 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::InlineAsm { .. } => {
|
TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
|
||||||
self.check_op(ops::InlineAsm);
|
TerminatorKind::Abort => self.check_op(ops::Abort),
|
||||||
|
|
||||||
|
TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
|
||||||
|
self.check_op(ops::Generator)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Some of these are only caught by `min_const_fn`, but should error here
|
TerminatorKind::Assert { .. }
|
||||||
// instead.
|
|
||||||
TerminatorKind::Abort
|
|
||||||
| TerminatorKind::Assert { .. }
|
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
| TerminatorKind::FalseUnwind { .. }
|
||||||
| TerminatorKind::GeneratorDrop
|
|
||||||
| TerminatorKind::Goto { .. }
|
| TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::SwitchInt { .. }
|
| TerminatorKind::SwitchInt { .. }
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable => {}
|
||||||
| TerminatorKind::Yield { .. } => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_min_const_fn_violation(tcx: TyCtxt<'_>, span: Span, msg: Cow<'_, str>) {
|
|
||||||
struct_span_err!(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();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) {
|
fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) {
|
||||||
let ty = body.return_ty();
|
let ty = body.return_ty();
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
tcx.infer_ctxt().enter(|infcx| {
|
||||||
|
|
|
@ -217,6 +217,7 @@ impl<B: ?Sized + ToOwned> Cow<'_, B> {
|
||||||
/// assert!(!bull.is_borrowed());
|
/// assert!(!bull.is_borrowed());
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "cow_is_borrowed", issue = "65143")]
|
#[unstable(feature = "cow_is_borrowed", issue = "65143")]
|
||||||
|
#[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")]
|
||||||
pub const fn is_borrowed(&self) -> bool {
|
pub const fn is_borrowed(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Borrowed(_) => true,
|
Borrowed(_) => true,
|
||||||
|
@ -239,6 +240,7 @@ impl<B: ?Sized + ToOwned> Cow<'_, B> {
|
||||||
/// assert!(!bull.is_owned());
|
/// assert!(!bull.is_owned());
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "cow_is_borrowed", issue = "65143")]
|
#[unstable(feature = "cow_is_borrowed", issue = "65143")]
|
||||||
|
#[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")]
|
||||||
pub const fn is_owned(&self) -> bool {
|
pub const fn is_owned(&self) -> bool {
|
||||||
!self.is_borrowed()
|
!self.is_borrowed()
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,9 +86,11 @@
|
||||||
#![feature(cfg_target_has_atomic)]
|
#![feature(cfg_target_has_atomic)]
|
||||||
#![feature(coerce_unsized)]
|
#![feature(coerce_unsized)]
|
||||||
#![feature(const_btree_new)]
|
#![feature(const_btree_new)]
|
||||||
|
#![feature(const_fn)]
|
||||||
#![feature(const_generics)]
|
#![feature(const_generics)]
|
||||||
#![feature(const_in_array_repeat_expressions)]
|
#![feature(const_in_array_repeat_expressions)]
|
||||||
#![feature(cow_is_borrowed)]
|
#![feature(cow_is_borrowed)]
|
||||||
|
#![feature(const_cow_is_borrowed)]
|
||||||
#![feature(dispatch_from_dyn)]
|
#![feature(dispatch_from_dyn)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(dropck_eyepatch)]
|
#![feature(dropck_eyepatch)]
|
||||||
|
|
|
@ -150,6 +150,7 @@ impl<T> RawVec<T, Global> {
|
||||||
impl<T, A: AllocRef> RawVec<T, A> {
|
impl<T, A: AllocRef> RawVec<T, A> {
|
||||||
/// Like `new`, but parameterized over the choice of allocator for
|
/// Like `new`, but parameterized over the choice of allocator for
|
||||||
/// the returned `RawVec`.
|
/// the returned `RawVec`.
|
||||||
|
#[allow_internal_unstable(const_fn)]
|
||||||
pub const fn new_in(alloc: A) -> Self {
|
pub const fn new_in(alloc: A) -> Self {
|
||||||
// `cap: 0` means "unallocated". zero-sized types are ignored.
|
// `cap: 0` means "unallocated". zero-sized types are ignored.
|
||||||
Self { ptr: Unique::dangling(), cap: 0, alloc }
|
Self { ptr: Unique::dangling(), cap: 0, alloc }
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![feature(allocator_api)]
|
#![feature(allocator_api)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(cow_is_borrowed)]
|
#![feature(cow_is_borrowed)]
|
||||||
|
#![feature(const_cow_is_borrowed)]
|
||||||
#![feature(drain_filter)]
|
#![feature(drain_filter)]
|
||||||
#![feature(exact_size_is_empty)]
|
#![feature(exact_size_is_empty)]
|
||||||
#![feature(new_uninit)]
|
#![feature(new_uninit)]
|
||||||
|
|
|
@ -177,6 +177,7 @@ impl Layout {
|
||||||
/// sentinel value. Types that lazily allocate must track initialization by
|
/// sentinel value. Types that lazily allocate must track initialization by
|
||||||
/// some other means.
|
/// some other means.
|
||||||
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
|
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
|
||||||
|
#[rustc_const_unstable(feature = "alloc_layout_extra", issue = "55724")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn dangling(&self) -> NonNull<u8> {
|
pub const fn dangling(&self) -> NonNull<u8> {
|
||||||
// SAFETY: align is guaranteed to be non-zero
|
// SAFETY: align is guaranteed to be non-zero
|
||||||
|
|
|
@ -56,6 +56,7 @@ unsafe impl Sync for ResumeTy {}
|
||||||
#[lang = "from_generator"]
|
#[lang = "from_generator"]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[unstable(feature = "gen_future", issue = "50547")]
|
#[unstable(feature = "gen_future", issue = "50547")]
|
||||||
|
#[rustc_const_unstable(feature = "gen_future", issue = "50547")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
|
pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
|
||||||
where
|
where
|
||||||
|
|
|
@ -75,11 +75,13 @@
|
||||||
#![feature(const_float_bits_conv)]
|
#![feature(const_float_bits_conv)]
|
||||||
#![feature(const_overflowing_int_methods)]
|
#![feature(const_overflowing_int_methods)]
|
||||||
#![feature(const_int_unchecked_arith)]
|
#![feature(const_int_unchecked_arith)]
|
||||||
|
#![feature(const_mut_refs)]
|
||||||
#![feature(const_int_pow)]
|
#![feature(const_int_pow)]
|
||||||
#![feature(constctlz)]
|
#![feature(constctlz)]
|
||||||
#![feature(const_panic)]
|
#![feature(const_panic)]
|
||||||
#![feature(const_pin)]
|
#![feature(const_pin)]
|
||||||
#![feature(const_fn_union)]
|
#![feature(const_fn_union)]
|
||||||
|
#![feature(const_fn)]
|
||||||
#![feature(const_generics)]
|
#![feature(const_generics)]
|
||||||
#![feature(const_option)]
|
#![feature(const_option)]
|
||||||
#![feature(const_precise_live_drops)]
|
#![feature(const_precise_live_drops)]
|
||||||
|
|
|
@ -401,6 +401,7 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
|
impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
|
||||||
|
#[allow_internal_unstable(const_fn)]
|
||||||
pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
|
pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
|
||||||
extern "C" fn run(
|
extern "C" fn run(
|
||||||
bridge: Bridge<'_>,
|
bridge: Bridge<'_>,
|
||||||
|
@ -413,6 +414,7 @@ impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
|
impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
|
||||||
|
#[allow_internal_unstable(const_fn)]
|
||||||
pub const fn expand2(
|
pub const fn expand2(
|
||||||
f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
|
f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -457,6 +459,7 @@ impl ProcMacro {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow_internal_unstable(const_fn)]
|
||||||
pub const fn custom_derive(
|
pub const fn custom_derive(
|
||||||
trait_name: &'static str,
|
trait_name: &'static str,
|
||||||
attributes: &'static [&'static str],
|
attributes: &'static [&'static str],
|
||||||
|
@ -465,6 +468,7 @@ impl ProcMacro {
|
||||||
ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
|
ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow_internal_unstable(const_fn)]
|
||||||
pub const fn attr(
|
pub const fn attr(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
|
expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
|
||||||
|
@ -472,6 +476,7 @@ impl ProcMacro {
|
||||||
ProcMacro::Attr { name, client: Client::expand2(expand) }
|
ProcMacro::Attr { name, client: Client::expand2(expand) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow_internal_unstable(const_fn)]
|
||||||
pub const fn bang(
|
pub const fn bang(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
expand: fn(crate::TokenStream) -> crate::TokenStream,
|
expand: fn(crate::TokenStream) -> crate::TokenStream,
|
||||||
|
|
|
@ -35,6 +35,7 @@ impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> {
|
||||||
pub struct ScopedCell<T: LambdaL>(Cell<<T as ApplyL<'static>>::Out>);
|
pub struct ScopedCell<T: LambdaL>(Cell<<T as ApplyL<'static>>::Out>);
|
||||||
|
|
||||||
impl<T: LambdaL> ScopedCell<T> {
|
impl<T: LambdaL> ScopedCell<T> {
|
||||||
|
#[allow_internal_unstable(const_fn)]
|
||||||
pub const fn new(value: <T as ApplyL<'static>>::Out) -> Self {
|
pub const fn new(value: <T as ApplyL<'static>>::Out) -> Self {
|
||||||
ScopedCell(Cell::new(value))
|
ScopedCell(Cell::new(value))
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
)]
|
)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
|
#![feature(const_fn)]
|
||||||
#![feature(allow_internal_unstable)]
|
#![feature(allow_internal_unstable)]
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
#![feature(extern_types)]
|
#![feature(extern_types)]
|
||||||
|
|
|
@ -237,6 +237,7 @@
|
||||||
#![feature(concat_idents)]
|
#![feature(concat_idents)]
|
||||||
#![feature(const_cstr_unchecked)]
|
#![feature(const_cstr_unchecked)]
|
||||||
#![feature(const_fn_transmute)]
|
#![feature(const_fn_transmute)]
|
||||||
|
#![feature(const_fn)]
|
||||||
#![feature(const_ipv6)]
|
#![feature(const_ipv6)]
|
||||||
#![feature(const_raw_ptr_deref)]
|
#![feature(const_raw_ptr_deref)]
|
||||||
#![feature(const_ipv4)]
|
#![feature(const_ipv4)]
|
||||||
|
@ -306,6 +307,7 @@
|
||||||
#![feature(str_internals)]
|
#![feature(str_internals)]
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
#![feature(thread_local)]
|
#![feature(thread_local)]
|
||||||
|
#![feature(thread_local_internals)]
|
||||||
#![feature(toowned_clone_into)]
|
#![feature(toowned_clone_into)]
|
||||||
#![feature(total_cmp)]
|
#![feature(total_cmp)]
|
||||||
#![feature(trace_macros)]
|
#![feature(trace_macros)]
|
||||||
|
|
|
@ -117,6 +117,7 @@ pub struct Key {
|
||||||
pub const INIT: StaticKey = StaticKey::new(None);
|
pub const INIT: StaticKey = StaticKey::new(None);
|
||||||
|
|
||||||
impl StaticKey {
|
impl StaticKey {
|
||||||
|
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
|
||||||
pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey {
|
pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey {
|
||||||
StaticKey { key: atomic::AtomicUsize::new(0), dtor }
|
StaticKey { key: atomic::AtomicUsize::new(0), dtor }
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,6 +225,7 @@ impl<T: 'static> LocalKey<T> {
|
||||||
reason = "recently added to create a key",
|
reason = "recently added to create a key",
|
||||||
issue = "none"
|
issue = "none"
|
||||||
)]
|
)]
|
||||||
|
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
|
||||||
pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey<T> {
|
pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey<T> {
|
||||||
LocalKey { inner }
|
LocalKey { inner }
|
||||||
}
|
}
|
||||||
|
@ -497,6 +498,7 @@ pub mod os {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> Key<T> {
|
impl<T: 'static> Key<T> {
|
||||||
|
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
|
||||||
pub const fn new() -> Key<T> {
|
pub const fn new() -> Key<T> {
|
||||||
Key { os: OsStaticKey::new(Some(destroy_value::<T>)), marker: marker::PhantomData }
|
Key { os: OsStaticKey::new(Some(destroy_value::<T>)), marker: marker::PhantomData }
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,7 @@ const X : usize = 2;
|
||||||
const fn f(x: usize) -> usize {
|
const fn f(x: usize) -> usize {
|
||||||
let mut sum = 0;
|
let mut sum = 0;
|
||||||
for i in 0..x {
|
for i in 0..x {
|
||||||
//~^ ERROR E0015
|
//~^ ERROR mutable references
|
||||||
//~| ERROR E0015
|
|
||||||
//~| ERROR E0658
|
|
||||||
//~| ERROR E0080
|
//~| ERROR E0080
|
||||||
//~| ERROR E0744
|
//~| ERROR E0744
|
||||||
sum += i;
|
sum += i;
|
||||||
|
|
|
@ -7,7 +7,7 @@ extern "C" {
|
||||||
const extern fn bar() {
|
const extern fn bar() {
|
||||||
unsafe {
|
unsafe {
|
||||||
regular_in_block();
|
regular_in_block();
|
||||||
//~^ ERROR: can only call other `const fn` within a `const fn`
|
//~^ ERROR: calls in constant functions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ extern fn regular() {}
|
||||||
const extern fn foo() {
|
const extern fn foo() {
|
||||||
unsafe {
|
unsafe {
|
||||||
regular();
|
regular();
|
||||||
//~^ ERROR: can only call other `const fn` within a `const fn`
|
//~^ ERROR: calls in constant functions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,15 @@
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `regular_in_block` is not stable as `const fn`
|
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
--> $DIR/const-extern-fn-call-extern-fn.rs:9:9
|
--> $DIR/const-extern-fn-call-extern-fn.rs:9:9
|
||||||
|
|
|
|
||||||
LL | regular_in_block();
|
LL | regular_in_block();
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
= 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
|
|
||||||
|
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `regular` is not stable as `const fn`
|
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
--> $DIR/const-extern-fn-call-extern-fn.rs:18:9
|
--> $DIR/const-extern-fn-call-extern-fn.rs:18:9
|
||||||
|
|
|
|
||||||
LL | regular();
|
LL | regular();
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
= 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
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0723`.
|
For more information about this error, try `rustc --explain E0015`.
|
||||||
|
|
|
@ -6,7 +6,7 @@ const unsafe extern "C" fn closure() -> fn() { || {} }
|
||||||
const unsafe extern fn use_float() { 1.0 + 1.0; }
|
const unsafe extern fn use_float() { 1.0 + 1.0; }
|
||||||
//~^ ERROR only int, `bool` and `char` operations are stable in const fn
|
//~^ ERROR only int, `bool` and `char` operations are stable in const fn
|
||||||
const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
|
const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
|
||||||
//~^ ERROR casting pointers to ints is unstable in const fn
|
//~^ ERROR casting pointers to integers
|
||||||
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -16,15 +16,16 @@ LL | const unsafe extern fn use_float() { 1.0 + 1.0; }
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= 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
|
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0723]: casting pointers to ints is unstable in const fn
|
error[E0658]: casting pointers to integers in constant functions is unstable
|
||||||
--> $DIR/const-extern-fn-min-const-fn.rs:8:48
|
--> $DIR/const-extern-fn-min-const-fn.rs:8:48
|
||||||
|
|
|
|
||||||
LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
|
LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
= help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0723`.
|
Some errors have detailed explanations: E0658, E0723.
|
||||||
|
For more information about an error, try `rustc --explain E0658`.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Test that we can't call random fns in a const fn or do other bad things.
|
// Test that we can't call random fns in a const fn or do other bad things.
|
||||||
|
|
||||||
#![feature(const_fn, const_transmute)]
|
#![feature(const_fn, const_fn_transmute)]
|
||||||
|
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ fn main() {
|
||||||
foo(&mut 5);
|
foo(&mut 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn are unstable
|
const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn
|
||||||
*x + 1
|
*x + 1
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ struct S {
|
||||||
|
|
||||||
impl S {
|
impl S {
|
||||||
const fn foo(&mut self, x: u32) {
|
const fn foo(&mut self, x: u32) {
|
||||||
|
//~^ ERROR mutable references
|
||||||
self.state = x;
|
self.state = x;
|
||||||
//~^ contains unimplemented expression
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
error[E0019]: constant function contains unimplemented expression type
|
error[E0723]: mutable references in const fn are unstable
|
||||||
--> $DIR/const_let_assign3.rs:9:9
|
--> $DIR/const_let_assign3.rs:8:18
|
||||||
|
|
|
|
||||||
LL | self.state = x;
|
LL | const fn foo(&mut self, x: u32) {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
= 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
|
||||||
|
|
||||||
error[E0764]: mutable references are not allowed in constants
|
error[E0764]: mutable references are not allowed in constants
|
||||||
--> $DIR/const_let_assign3.rs:16:5
|
--> $DIR/const_let_assign3.rs:16:5
|
||||||
|
@ -28,5 +29,5 @@ LL | *y = 42;
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0019, E0764.
|
Some errors have detailed explanations: E0019, E0723, E0764.
|
||||||
For more information about an error, try `rustc --explain E0019`.
|
For more information about an error, try `rustc --explain E0019`.
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
const fn foo(a: i32) -> Vec<i32> {
|
const fn foo(a: i32) -> Vec<i32> {
|
||||||
vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn
|
vec![1, 2, 3]
|
||||||
|
//~^ ERROR allocations are not allowed
|
||||||
|
//~| ERROR unimplemented expression type
|
||||||
|
//~| ERROR calls in constant functions
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,13 +1,29 @@
|
||||||
error[E0723]: heap allocations are not allowed in const fn
|
error[E0010]: allocations are not allowed in constant functions
|
||||||
|
--> $DIR/bad_const_fn_body_ice.rs:2:5
|
||||||
|
|
|
||||||
|
LL | vec![1, 2, 3]
|
||||||
|
| ^^^^^^^^^^^^^ allocation not allowed in constant functions
|
||||||
|
|
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0019]: constant function contains unimplemented expression type
|
||||||
--> $DIR/bad_const_fn_body_ice.rs:2:5
|
--> $DIR/bad_const_fn_body_ice.rs:2:5
|
||||||
|
|
|
|
||||||
LL | vec![1, 2, 3]
|
LL | vec![1, 2, 3]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
|
--> $DIR/bad_const_fn_body_ice.rs:2:5
|
||||||
|
|
|
||||||
|
LL | vec![1, 2, 3]
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0723`.
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0010, E0015, E0019.
|
||||||
|
For more information about an error, try `rustc --explain E0010`.
|
||||||
|
|
|
@ -78,25 +78,25 @@ const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
|
||||||
const fn foo11_2<T: Send>(t: T) -> T { t }
|
const fn foo11_2<T: Send>(t: T) -> T { t }
|
||||||
//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
|
//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
|
||||||
const fn foo19(f: f32) -> f32 { f * 2.0 }
|
const fn foo19(f: f32) -> f32 { f * 2.0 }
|
||||||
//~^ ERROR only int, `bool` and `char` operations are stable in const fn
|
//~^ ERROR int, `bool` and `char` operations
|
||||||
const fn foo19_2(f: f32) -> f32 { 2.0 - f }
|
const fn foo19_2(f: f32) -> f32 { 2.0 - f }
|
||||||
//~^ ERROR only int, `bool` and `char` operations are stable in const fn
|
//~^ ERROR int, `bool` and `char` operations
|
||||||
const fn foo19_3(f: f32) -> f32 { -f }
|
const fn foo19_3(f: f32) -> f32 { -f }
|
||||||
//~^ ERROR only int and `bool` operations are stable in const fn
|
//~^ ERROR int, `bool` and `char` operations
|
||||||
const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
|
const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
|
||||||
//~^ ERROR only int, `bool` and `char` operations are stable in const fn
|
//~^ ERROR int, `bool` and `char` operations
|
||||||
|
|
||||||
static BAR: u32 = 42;
|
static BAR: u32 = 42;
|
||||||
const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
|
const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics
|
||||||
const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
|
const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot refer to statics
|
||||||
const fn foo30(x: *const u32) -> usize { x as usize }
|
const fn foo30(x: *const u32) -> usize { x as usize }
|
||||||
//~^ ERROR casting pointers to ints is unstable
|
//~^ ERROR casting pointers to integers
|
||||||
const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
|
const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
|
||||||
//~^ ERROR casting pointers to ints is unstable
|
//~^ ERROR casting pointers to integers
|
||||||
const fn foo30_2(x: *mut u32) -> usize { x as usize }
|
const fn foo30_2(x: *mut u32) -> usize { x as usize }
|
||||||
//~^ ERROR casting pointers to ints is unstable
|
//~^ ERROR casting pointers to integers
|
||||||
const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
|
const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
|
||||||
//~^ ERROR casting pointers to ints is unstable
|
//~^ ERROR casting pointers to integers
|
||||||
const fn foo30_6() -> bool { let x = true; x }
|
const fn foo30_6() -> bool { let x = true; x }
|
||||||
const fn inc(x: &mut i32) { *x += 1 }
|
const fn inc(x: &mut i32) { *x += 1 }
|
||||||
//~^ ERROR mutable references in const fn are unstable
|
//~^ ERROR mutable references in const fn are unstable
|
||||||
|
|
|
@ -94,7 +94,7 @@ LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f }
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= 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
|
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0723]: only int and `bool` operations are stable in const fn
|
error[E0723]: only int, `bool` and `char` operations are stable in const fn
|
||||||
--> $DIR/min_const_fn.rs:84:35
|
--> $DIR/min_const_fn.rs:84:35
|
||||||
|
|
|
|
||||||
LL | const fn foo19_3(f: f32) -> f32 { -f }
|
LL | const fn foo19_3(f: f32) -> f32 { -f }
|
||||||
|
@ -112,59 +112,57 @@ LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= 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
|
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0723]: cannot access `static` items in const fn
|
error[E0013]: constant functions cannot refer to statics
|
||||||
--> $DIR/min_const_fn.rs:90:27
|
--> $DIR/min_const_fn.rs:90:27
|
||||||
|
|
|
|
||||||
LL | const fn foo25() -> u32 { BAR }
|
LL | const fn foo25() -> u32 { BAR }
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: consider extracting the value of the `static` to a `const`, and referring to that
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error[E0723]: cannot access `static` items in const fn
|
error[E0013]: constant functions cannot refer to statics
|
||||||
--> $DIR/min_const_fn.rs:91:37
|
--> $DIR/min_const_fn.rs:91:37
|
||||||
|
|
|
|
||||||
LL | const fn foo26() -> &'static u32 { &BAR }
|
LL | const fn foo26() -> &'static u32 { &BAR }
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: consider extracting the value of the `static` to a `const`, and referring to that
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error[E0723]: casting pointers to ints is unstable in const fn
|
error[E0658]: casting pointers to integers in constant functions is unstable
|
||||||
--> $DIR/min_const_fn.rs:92:42
|
--> $DIR/min_const_fn.rs:92:42
|
||||||
|
|
|
|
||||||
LL | const fn foo30(x: *const u32) -> usize { x as usize }
|
LL | const fn foo30(x: *const u32) -> usize { x as usize }
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
= help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0723]: casting pointers to ints is unstable in const fn
|
error[E0658]: casting pointers to integers in constant functions is unstable
|
||||||
--> $DIR/min_const_fn.rs:94:63
|
--> $DIR/min_const_fn.rs:94:63
|
||||||
|
|
|
|
||||||
LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
|
LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
= help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0723]: casting pointers to ints is unstable in const fn
|
error[E0658]: casting pointers to integers in constant functions is unstable
|
||||||
--> $DIR/min_const_fn.rs:96:42
|
--> $DIR/min_const_fn.rs:96:42
|
||||||
|
|
|
|
||||||
LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
|
LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
= help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0723]: casting pointers to ints is unstable in const fn
|
error[E0658]: casting pointers to integers in constant functions is unstable
|
||||||
--> $DIR/min_const_fn.rs:98:63
|
--> $DIR/min_const_fn.rs:98:63
|
||||||
|
|
|
|
||||||
LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
|
LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
= help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0723]: mutable references in const fn are unstable
|
error[E0723]: mutable references in const fn are unstable
|
||||||
--> $DIR/min_const_fn.rs:101:14
|
--> $DIR/min_const_fn.rs:101:14
|
||||||
|
@ -267,5 +265,5 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
|
||||||
|
|
||||||
error: aborting due to 30 previous errors
|
error: aborting due to 30 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0493, E0723.
|
Some errors have detailed explanations: E0013, E0493, E0658, E0723.
|
||||||
For more information about an error, try `rustc --explain E0493`.
|
For more information about an error, try `rustc --explain E0013`.
|
||||||
|
|
|
@ -13,7 +13,7 @@ const fn foo() -> u32 { 42 }
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||||
// can't call non-min_const_fn
|
// can't call non-min_const_fn
|
||||||
const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
|
const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn
|
||||||
|
|
||||||
#[unstable(feature = "rust1", issue = "none")]
|
#[unstable(feature = "rust1", issue = "none")]
|
||||||
const fn foo2() -> u32 { 42 }
|
const fn foo2() -> u32 { 42 }
|
||||||
|
@ -21,12 +21,13 @@ const fn foo2() -> u32 { 42 }
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||||
// can't call non-min_const_fn
|
// can't call non-min_const_fn
|
||||||
const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn`
|
const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||||
// conformity is required, even with `const_fn` feature gate
|
// conformity is required, even with `const_fn` feature gate
|
||||||
const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations
|
const fn bar3() -> u32 { (5f32 + 6f32) as u32 }
|
||||||
|
//~^ ERROR const-stable function cannot use `#[feature(const_fn)]`
|
||||||
|
|
||||||
// check whether this function cannot be called even with the feature gate active
|
// check whether this function cannot be called even with the feature gate active
|
||||||
#[unstable(feature = "foo2", issue = "none")]
|
#[unstable(feature = "foo2", issue = "none")]
|
||||||
|
@ -35,6 +36,6 @@ const fn foo2_gated() -> u32 { 42 }
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||||
// can't call non-min_const_fn
|
// can't call non-min_const_fn
|
||||||
const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn`
|
const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,39 +1,38 @@
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn`
|
error: `foo` is not yet stable as a const fn
|
||||||
--> $DIR/min_const_fn_libstd_stability.rs:16:25
|
--> $DIR/min_const_fn_libstd_stability.rs:16:25
|
||||||
|
|
|
|
||||||
LL | const fn bar() -> u32 { foo() }
|
LL | const fn bar() -> u32 { foo() }
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: Const-stable functions can only call other const-stable functions
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn`
|
error: `foo2` is not yet stable as a const fn
|
||||||
--> $DIR/min_const_fn_libstd_stability.rs:24:26
|
--> $DIR/min_const_fn_libstd_stability.rs:24:26
|
||||||
|
|
|
|
||||||
LL | const fn bar2() -> u32 { foo2() }
|
LL | const fn bar2() -> u32 { foo2() }
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: Const-stable functions can only call other const-stable functions
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error[E0723]: only int, `bool` and `char` operations are stable in const fn
|
error: const-stable function cannot use `#[feature(const_fn)]`
|
||||||
--> $DIR/min_const_fn_libstd_stability.rs:29:26
|
--> $DIR/min_const_fn_libstd_stability.rs:29:26
|
||||||
|
|
|
|
||||||
LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 }
|
LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 }
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= note: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
help: if it is not part of the public API, make this function unstably const
|
||||||
|
|
|
||||||
|
LL | #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||||
|
|
|
||||||
|
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn`
|
error: `foo2_gated` is not yet stable as a const fn
|
||||||
--> $DIR/min_const_fn_libstd_stability.rs:38:32
|
--> $DIR/min_const_fn_libstd_stability.rs:39:32
|
||||||
|
|
|
|
||||||
LL | const fn bar2_gated() -> u32 { foo2_gated() }
|
LL | const fn bar2_gated() -> u32 { foo2_gated() }
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: Const-stable functions can only call other const-stable functions
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0723`.
|
|
||||||
|
|
|
@ -12,5 +12,5 @@ fn main() {}
|
||||||
const unsafe fn no_union() {
|
const unsafe fn no_union() {
|
||||||
union Foo { x: (), y: () }
|
union Foo { x: (), y: () }
|
||||||
Foo { x: () }.y
|
Foo { x: () }.y
|
||||||
//~^ accessing union fields is unstable
|
//~^ unions in const fn
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,16 +25,15 @@ LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static u
|
||||||
= note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
|
= note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
|
||||||
= help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
|
= help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0723]: accessing union fields is unstable
|
error[E0658]: unions in const fn are unstable
|
||||||
--> $DIR/min_const_fn_unsafe_bad.rs:14:5
|
--> $DIR/min_const_fn_unsafe_bad.rs:14:5
|
||||||
|
|
|
|
||||||
LL | Foo { x: () }.y
|
LL | Foo { x: () }.y
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= note: see issue #51909 <https://github.com/rust-lang/rust/issues/51909> for more information
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
= help: add `#![feature(const_fn_union)]` to the crate attributes to enable
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0658, E0723.
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
For more information about an error, try `rustc --explain E0658`.
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ const unsafe fn foo() -> u32 { 42 }
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||||
// can't call non-min_const_fn
|
// can't call non-min_const_fn
|
||||||
const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `const fn`
|
const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn
|
||||||
|
|
||||||
#[unstable(feature = "rust1", issue = "none")]
|
#[unstable(feature = "rust1", issue = "none")]
|
||||||
const unsafe fn foo2() -> u32 { 42 }
|
const unsafe fn foo2() -> u32 { 42 }
|
||||||
|
@ -21,12 +21,13 @@ const unsafe fn foo2() -> u32 { 42 }
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||||
// can't call non-min_const_fn
|
// can't call non-min_const_fn
|
||||||
const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `const fn`
|
const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||||
// conformity is required, even with `const_fn` feature gate
|
// conformity is required, even with `const_fn` feature gate
|
||||||
const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op
|
const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
|
||||||
|
//~^ ERROR const-stable function cannot use `#[feature(const_fn)]`
|
||||||
|
|
||||||
// check whether this function cannot be called even with the feature gate active
|
// check whether this function cannot be called even with the feature gate active
|
||||||
#[unstable(feature = "foo2", issue = "none")]
|
#[unstable(feature = "foo2", issue = "none")]
|
||||||
|
@ -36,6 +37,6 @@ const unsafe fn foo2_gated() -> u32 { 42 }
|
||||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||||
// can't call non-min_const_fn
|
// can't call non-min_const_fn
|
||||||
const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
|
const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
|
||||||
//~^ ERROR can only call other `const fn`
|
//~^ ERROR not yet stable as a const fn
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,39 +1,38 @@
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn`
|
error: `foo` is not yet stable as a const fn
|
||||||
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41
|
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41
|
||||||
|
|
|
|
||||||
LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
|
LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: Const-stable functions can only call other const-stable functions
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn`
|
error: `foo2` is not yet stable as a const fn
|
||||||
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42
|
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42
|
||||||
|
|
|
|
||||||
LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
|
LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: Const-stable functions can only call other const-stable functions
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error[E0723]: only int, `bool` and `char` operations are stable in const fn
|
error: const-stable function cannot use `#[feature(const_fn)]`
|
||||||
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33
|
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33
|
||||||
|
|
|
|
||||||
LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
|
LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= note: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
help: if it is not part of the public API, make this function unstably const
|
||||||
|
|
|
||||||
|
LL | #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||||
|
|
|
||||||
|
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn`
|
error: `foo2_gated` is not yet stable as a const fn
|
||||||
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:38:48
|
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:39:48
|
||||||
|
|
|
|
||||||
LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
|
LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: Const-stable functions can only call other const-stable functions
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0723`.
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ const fn foo() -> u32 { 42 }
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||||
// can't call non-min_const_fn
|
// can't call non-min_const_fn
|
||||||
const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
|
const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn
|
||||||
|
|
||||||
#[unstable(feature = "rust1", issue = "none")]
|
#[unstable(feature = "rust1", issue = "none")]
|
||||||
const fn foo2() -> u32 { 42 }
|
const fn foo2() -> u32 { 42 }
|
||||||
|
@ -21,7 +21,7 @@ const fn foo2() -> u32 { 42 }
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||||
// can't call non-min_const_fn
|
// can't call non-min_const_fn
|
||||||
const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn`
|
const unsafe fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn
|
||||||
|
|
||||||
// check whether this function cannot be called even with the feature gate active
|
// check whether this function cannot be called even with the feature gate active
|
||||||
#[unstable(feature = "foo2", issue = "none")]
|
#[unstable(feature = "foo2", issue = "none")]
|
||||||
|
@ -30,6 +30,6 @@ const fn foo2_gated() -> u32 { 42 }
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||||
// can't call non-min_const_fn
|
// can't call non-min_const_fn
|
||||||
const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn`
|
const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,30 +1,26 @@
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn`
|
error: `foo` is not yet stable as a const fn
|
||||||
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32
|
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32
|
||||||
|
|
|
|
||||||
LL | const unsafe fn bar() -> u32 { foo() }
|
LL | const unsafe fn bar() -> u32 { foo() }
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: Const-stable functions can only call other const-stable functions
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn`
|
error: `foo2` is not yet stable as a const fn
|
||||||
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33
|
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33
|
||||||
|
|
|
|
||||||
LL | const unsafe fn bar2() -> u32 { foo2() }
|
LL | const unsafe fn bar2() -> u32 { foo2() }
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: Const-stable functions can only call other const-stable functions
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn`
|
error: `foo2_gated` is not yet stable as a const fn
|
||||||
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39
|
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39
|
||||||
|
|
|
|
||||||
LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
|
LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: Const-stable functions can only call other const-stable functions
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0723`.
|
|
||||||
|
|
|
@ -12,6 +12,16 @@ LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "
|
||||||
|
|
||||||
warning: skipping const checks
|
warning: skipping const checks
|
||||||
|
|
|
|
||||||
|
help: skipping check for `const_fn` feature
|
||||||
|
--> $DIR/abi-mismatch.rs:9:23
|
||||||
|
|
|
||||||
|
LL | const fn call_rust_fn(my_fn: extern "Rust" fn()) {
|
||||||
|
| ^^^^^
|
||||||
|
help: skipping check for `const_fn` feature
|
||||||
|
--> $DIR/abi-mismatch.rs:10:5
|
||||||
|
|
|
||||||
|
LL | my_fn();
|
||||||
|
| ^^^^^
|
||||||
help: skipping check that does not even have a feature gate
|
help: skipping check that does not even have a feature gate
|
||||||
--> $DIR/abi-mismatch.rs:10:5
|
--> $DIR/abi-mismatch.rs:10:5
|
||||||
|
|
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::ptr::NonNull;
|
||||||
|
|
||||||
pub const fn dangling_slice<T>() -> NonNull<[T]> {
|
pub const fn dangling_slice<T>() -> NonNull<[T]> {
|
||||||
NonNull::<[T; 0]>::dangling()
|
NonNull::<[T; 0]>::dangling()
|
||||||
//~^ ERROR: unsizing casts are only allowed for references right now
|
//~^ ERROR: unsizing casts to types besides slices
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error[E0723]: unsizing casts are only allowed for references right now
|
error[E0723]: unsizing casts to types besides slices are not allowed in const fn
|
||||||
--> $DIR/unsizing-cast-non-null.rs:6:5
|
--> $DIR/unsizing-cast-non-null.rs:6:5
|
||||||
|
|
|
|
||||||
LL | NonNull::<[T; 0]>::dangling()
|
LL | NonNull::<[T; 0]>::dangling()
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#![stable(feature = "core", since = "1.6.0")]
|
#![stable(feature = "core", since = "1.6.0")]
|
||||||
#![feature(rustc_const_unstable)]
|
#![feature(rustc_const_unstable)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
|
#![feature(const_fn)]
|
||||||
|
|
||||||
enum Opt<T> {
|
enum Opt<T> {
|
||||||
Some(T),
|
Some(T),
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
--> $DIR/unstable-const-fn-in-libcore.rs:23:26
|
--> $DIR/unstable-const-fn-in-libcore.rs:24:26
|
||||||
|
|
|
|
||||||
LL | Opt::None => f(),
|
LL | Opt::None => f(),
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error[E0493]: destructors cannot be evaluated at compile-time
|
error[E0493]: destructors cannot be evaluated at compile-time
|
||||||
--> $DIR/unstable-const-fn-in-libcore.rs:18:53
|
--> $DIR/unstable-const-fn-in-libcore.rs:19:53
|
||||||
|
|
|
|
||||||
LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
|
LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
|
||||||
| ^ constant functions cannot evaluate destructors
|
| ^ constant functions cannot evaluate destructors
|
||||||
|
@ -14,7 +14,7 @@ LL | }
|
||||||
| - value is dropped here
|
| - value is dropped here
|
||||||
|
|
||||||
error[E0493]: destructors cannot be evaluated at compile-time
|
error[E0493]: destructors cannot be evaluated at compile-time
|
||||||
--> $DIR/unstable-const-fn-in-libcore.rs:18:47
|
--> $DIR/unstable-const-fn-in-libcore.rs:19:47
|
||||||
|
|
|
|
||||||
LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
|
LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
|
||||||
| ^^^^ constant functions cannot evaluate destructors
|
| ^^^^ constant functions cannot evaluate destructors
|
||||||
|
|
|
@ -12,6 +12,7 @@ fn main() {
|
||||||
extern "C" fn ff4() {} // OK.
|
extern "C" fn ff4() {} // OK.
|
||||||
const async unsafe extern "C" fn ff5() {} // OK.
|
const async unsafe extern "C" fn ff5() {} // OK.
|
||||||
//~^ ERROR functions cannot be both `const` and `async`
|
//~^ ERROR functions cannot be both `const` and `async`
|
||||||
|
//~| ERROR `from_generator` is not yet stable as a const fn
|
||||||
|
|
||||||
trait X {
|
trait X {
|
||||||
async fn ft1(); //~ ERROR functions in traits cannot be declared `async`
|
async fn ft1(); //~ ERROR functions in traits cannot be declared `async`
|
||||||
|
@ -34,6 +35,7 @@ fn main() {
|
||||||
const async unsafe extern "C" fn ft5() {}
|
const async unsafe extern "C" fn ft5() {}
|
||||||
//~^ ERROR functions in traits cannot be declared `async`
|
//~^ ERROR functions in traits cannot be declared `async`
|
||||||
//~| ERROR functions in traits cannot be declared const
|
//~| ERROR functions in traits cannot be declared const
|
||||||
|
//~| ERROR `from_generator` is not yet stable as a const fn
|
||||||
//~| ERROR method `ft5` has an incompatible type for trait
|
//~| ERROR method `ft5` has an incompatible type for trait
|
||||||
//~| ERROR functions cannot be both `const` and `async`
|
//~| ERROR functions cannot be both `const` and `async`
|
||||||
}
|
}
|
||||||
|
@ -45,6 +47,7 @@ fn main() {
|
||||||
extern "C" fn fi4() {} // OK.
|
extern "C" fn fi4() {} // OK.
|
||||||
const async unsafe extern "C" fn fi5() {}
|
const async unsafe extern "C" fn fi5() {}
|
||||||
//~^ ERROR functions cannot be both `const` and `async`
|
//~^ ERROR functions cannot be both `const` and `async`
|
||||||
|
//~| ERROR `from_generator` is not yet stable as a const fn
|
||||||
}
|
}
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
|
|
|
@ -8,7 +8,7 @@ LL | const async unsafe extern "C" fn ff5() {} // OK.
|
||||||
| `const` because of this
|
| `const` because of this
|
||||||
|
|
||||||
error[E0706]: functions in traits cannot be declared `async`
|
error[E0706]: functions in traits cannot be declared `async`
|
||||||
--> $DIR/fn-header-semantic-fail.rs:17:9
|
--> $DIR/fn-header-semantic-fail.rs:18:9
|
||||||
|
|
|
|
||||||
LL | async fn ft1();
|
LL | async fn ft1();
|
||||||
| -----^^^^^^^^^^
|
| -----^^^^^^^^^^
|
||||||
|
@ -19,19 +19,19 @@ LL | async fn ft1();
|
||||||
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
||||||
|
|
||||||
error[E0379]: functions in traits cannot be declared const
|
error[E0379]: functions in traits cannot be declared const
|
||||||
--> $DIR/fn-header-semantic-fail.rs:19:9
|
--> $DIR/fn-header-semantic-fail.rs:20:9
|
||||||
|
|
|
|
||||||
LL | const fn ft3();
|
LL | const fn ft3();
|
||||||
| ^^^^^ functions in traits cannot be const
|
| ^^^^^ functions in traits cannot be const
|
||||||
|
|
||||||
error[E0379]: functions in traits cannot be declared const
|
error[E0379]: functions in traits cannot be declared const
|
||||||
--> $DIR/fn-header-semantic-fail.rs:21:9
|
--> $DIR/fn-header-semantic-fail.rs:22:9
|
||||||
|
|
|
|
||||||
LL | const async unsafe extern "C" fn ft5();
|
LL | const async unsafe extern "C" fn ft5();
|
||||||
| ^^^^^ functions in traits cannot be const
|
| ^^^^^ functions in traits cannot be const
|
||||||
|
|
||||||
error[E0706]: functions in traits cannot be declared `async`
|
error[E0706]: functions in traits cannot be declared `async`
|
||||||
--> $DIR/fn-header-semantic-fail.rs:21:9
|
--> $DIR/fn-header-semantic-fail.rs:22:9
|
||||||
|
|
|
|
||||||
LL | const async unsafe extern "C" fn ft5();
|
LL | const async unsafe extern "C" fn ft5();
|
||||||
| ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -42,7 +42,7 @@ LL | const async unsafe extern "C" fn ft5();
|
||||||
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
||||||
|
|
||||||
error: functions cannot be both `const` and `async`
|
error: functions cannot be both `const` and `async`
|
||||||
--> $DIR/fn-header-semantic-fail.rs:21:9
|
--> $DIR/fn-header-semantic-fail.rs:22:9
|
||||||
|
|
|
|
||||||
LL | const async unsafe extern "C" fn ft5();
|
LL | const async unsafe extern "C" fn ft5();
|
||||||
| ^^^^^-^^^^^----------------------------
|
| ^^^^^-^^^^^----------------------------
|
||||||
|
@ -51,7 +51,7 @@ LL | const async unsafe extern "C" fn ft5();
|
||||||
| `const` because of this
|
| `const` because of this
|
||||||
|
|
||||||
error[E0706]: functions in traits cannot be declared `async`
|
error[E0706]: functions in traits cannot be declared `async`
|
||||||
--> $DIR/fn-header-semantic-fail.rs:29:9
|
--> $DIR/fn-header-semantic-fail.rs:30:9
|
||||||
|
|
|
|
||||||
LL | async fn ft1() {}
|
LL | async fn ft1() {}
|
||||||
| -----^^^^^^^^^^^^
|
| -----^^^^^^^^^^^^
|
||||||
|
@ -62,19 +62,19 @@ LL | async fn ft1() {}
|
||||||
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
||||||
|
|
||||||
error[E0379]: functions in traits cannot be declared const
|
error[E0379]: functions in traits cannot be declared const
|
||||||
--> $DIR/fn-header-semantic-fail.rs:32:9
|
--> $DIR/fn-header-semantic-fail.rs:33:9
|
||||||
|
|
|
|
||||||
LL | const fn ft3() {}
|
LL | const fn ft3() {}
|
||||||
| ^^^^^ functions in traits cannot be const
|
| ^^^^^ functions in traits cannot be const
|
||||||
|
|
||||||
error[E0379]: functions in traits cannot be declared const
|
error[E0379]: functions in traits cannot be declared const
|
||||||
--> $DIR/fn-header-semantic-fail.rs:34:9
|
--> $DIR/fn-header-semantic-fail.rs:35:9
|
||||||
|
|
|
|
||||||
LL | const async unsafe extern "C" fn ft5() {}
|
LL | const async unsafe extern "C" fn ft5() {}
|
||||||
| ^^^^^ functions in traits cannot be const
|
| ^^^^^ functions in traits cannot be const
|
||||||
|
|
||||||
error[E0706]: functions in traits cannot be declared `async`
|
error[E0706]: functions in traits cannot be declared `async`
|
||||||
--> $DIR/fn-header-semantic-fail.rs:34:9
|
--> $DIR/fn-header-semantic-fail.rs:35:9
|
||||||
|
|
|
|
||||||
LL | const async unsafe extern "C" fn ft5() {}
|
LL | const async unsafe extern "C" fn ft5() {}
|
||||||
| ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -85,7 +85,7 @@ LL | const async unsafe extern "C" fn ft5() {}
|
||||||
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
||||||
|
|
||||||
error: functions cannot be both `const` and `async`
|
error: functions cannot be both `const` and `async`
|
||||||
--> $DIR/fn-header-semantic-fail.rs:34:9
|
--> $DIR/fn-header-semantic-fail.rs:35:9
|
||||||
|
|
|
|
||||||
LL | const async unsafe extern "C" fn ft5() {}
|
LL | const async unsafe extern "C" fn ft5() {}
|
||||||
| ^^^^^-^^^^^------------------------------
|
| ^^^^^-^^^^^------------------------------
|
||||||
|
@ -94,7 +94,7 @@ LL | const async unsafe extern "C" fn ft5() {}
|
||||||
| `const` because of this
|
| `const` because of this
|
||||||
|
|
||||||
error: functions cannot be both `const` and `async`
|
error: functions cannot be both `const` and `async`
|
||||||
--> $DIR/fn-header-semantic-fail.rs:46:9
|
--> $DIR/fn-header-semantic-fail.rs:48:9
|
||||||
|
|
|
|
||||||
LL | const async unsafe extern "C" fn fi5() {}
|
LL | const async unsafe extern "C" fn fi5() {}
|
||||||
| ^^^^^-^^^^^------------------------------
|
| ^^^^^-^^^^^------------------------------
|
||||||
|
@ -103,7 +103,7 @@ LL | const async unsafe extern "C" fn fi5() {}
|
||||||
| `const` because of this
|
| `const` because of this
|
||||||
|
|
||||||
error: functions in `extern` blocks cannot have qualifiers
|
error: functions in `extern` blocks cannot have qualifiers
|
||||||
--> $DIR/fn-header-semantic-fail.rs:51:18
|
--> $DIR/fn-header-semantic-fail.rs:54:18
|
||||||
|
|
|
|
||||||
LL | extern {
|
LL | extern {
|
||||||
| ------ in this `extern` block
|
| ------ in this `extern` block
|
||||||
|
@ -113,7 +113,7 @@ LL | async fn fe1();
|
||||||
| help: remove the qualifiers: `fn`
|
| help: remove the qualifiers: `fn`
|
||||||
|
|
||||||
error: functions in `extern` blocks cannot have qualifiers
|
error: functions in `extern` blocks cannot have qualifiers
|
||||||
--> $DIR/fn-header-semantic-fail.rs:52:19
|
--> $DIR/fn-header-semantic-fail.rs:55:19
|
||||||
|
|
|
|
||||||
LL | extern {
|
LL | extern {
|
||||||
| ------ in this `extern` block
|
| ------ in this `extern` block
|
||||||
|
@ -124,7 +124,7 @@ LL | unsafe fn fe2();
|
||||||
| help: remove the qualifiers: `fn`
|
| help: remove the qualifiers: `fn`
|
||||||
|
|
||||||
error: functions in `extern` blocks cannot have qualifiers
|
error: functions in `extern` blocks cannot have qualifiers
|
||||||
--> $DIR/fn-header-semantic-fail.rs:53:18
|
--> $DIR/fn-header-semantic-fail.rs:56:18
|
||||||
|
|
|
|
||||||
LL | extern {
|
LL | extern {
|
||||||
| ------ in this `extern` block
|
| ------ in this `extern` block
|
||||||
|
@ -135,7 +135,7 @@ LL | const fn fe3();
|
||||||
| help: remove the qualifiers: `fn`
|
| help: remove the qualifiers: `fn`
|
||||||
|
|
||||||
error: functions in `extern` blocks cannot have qualifiers
|
error: functions in `extern` blocks cannot have qualifiers
|
||||||
--> $DIR/fn-header-semantic-fail.rs:54:23
|
--> $DIR/fn-header-semantic-fail.rs:57:23
|
||||||
|
|
|
|
||||||
LL | extern {
|
LL | extern {
|
||||||
| ------ in this `extern` block
|
| ------ in this `extern` block
|
||||||
|
@ -146,7 +146,7 @@ LL | extern "C" fn fe4();
|
||||||
| help: remove the qualifiers: `fn`
|
| help: remove the qualifiers: `fn`
|
||||||
|
|
||||||
error: functions in `extern` blocks cannot have qualifiers
|
error: functions in `extern` blocks cannot have qualifiers
|
||||||
--> $DIR/fn-header-semantic-fail.rs:55:42
|
--> $DIR/fn-header-semantic-fail.rs:58:42
|
||||||
|
|
|
|
||||||
LL | extern {
|
LL | extern {
|
||||||
| ------ in this `extern` block
|
| ------ in this `extern` block
|
||||||
|
@ -157,7 +157,7 @@ LL | const async unsafe extern "C" fn fe5();
|
||||||
| help: remove the qualifiers: `fn`
|
| help: remove the qualifiers: `fn`
|
||||||
|
|
||||||
error: functions cannot be both `const` and `async`
|
error: functions cannot be both `const` and `async`
|
||||||
--> $DIR/fn-header-semantic-fail.rs:55:9
|
--> $DIR/fn-header-semantic-fail.rs:58:9
|
||||||
|
|
|
|
||||||
LL | const async unsafe extern "C" fn fe5();
|
LL | const async unsafe extern "C" fn fe5();
|
||||||
| ^^^^^-^^^^^----------------------------
|
| ^^^^^-^^^^^----------------------------
|
||||||
|
@ -165,8 +165,16 @@ LL | const async unsafe extern "C" fn fe5();
|
||||||
| | `async` because of this
|
| | `async` because of this
|
||||||
| `const` because of this
|
| `const` because of this
|
||||||
|
|
||||||
|
error: `from_generator` is not yet stable as a const fn
|
||||||
|
--> $DIR/fn-header-semantic-fail.rs:13:44
|
||||||
|
|
|
||||||
|
LL | const async unsafe extern "C" fn ff5() {} // OK.
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= help: add `#![feature(gen_future)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0053]: method `ft1` has an incompatible type for trait
|
error[E0053]: method `ft1` has an incompatible type for trait
|
||||||
--> $DIR/fn-header-semantic-fail.rs:29:24
|
--> $DIR/fn-header-semantic-fail.rs:30:24
|
||||||
|
|
|
|
||||||
LL | async fn ft1();
|
LL | async fn ft1();
|
||||||
| - type in trait
|
| - type in trait
|
||||||
|
@ -181,7 +189,7 @@ LL | async fn ft1() {}
|
||||||
found fn pointer `fn() -> impl Future`
|
found fn pointer `fn() -> impl Future`
|
||||||
|
|
||||||
error[E0053]: method `ft5` has an incompatible type for trait
|
error[E0053]: method `ft5` has an incompatible type for trait
|
||||||
--> $DIR/fn-header-semantic-fail.rs:34:48
|
--> $DIR/fn-header-semantic-fail.rs:35:48
|
||||||
|
|
|
|
||||||
LL | const async unsafe extern "C" fn ft5();
|
LL | const async unsafe extern "C" fn ft5();
|
||||||
| - type in trait
|
| - type in trait
|
||||||
|
@ -195,7 +203,23 @@ LL | const async unsafe extern "C" fn ft5() {}
|
||||||
= note: expected fn pointer `unsafe extern "C" fn()`
|
= note: expected fn pointer `unsafe extern "C" fn()`
|
||||||
found fn pointer `unsafe extern "C" fn() -> impl Future`
|
found fn pointer `unsafe extern "C" fn() -> impl Future`
|
||||||
|
|
||||||
error: aborting due to 20 previous errors
|
error: `from_generator` is not yet stable as a const fn
|
||||||
|
--> $DIR/fn-header-semantic-fail.rs:35:48
|
||||||
|
|
|
||||||
|
LL | const async unsafe extern "C" fn ft5() {}
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= help: add `#![feature(gen_future)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: `from_generator` is not yet stable as a const fn
|
||||||
|
--> $DIR/fn-header-semantic-fail.rs:48:48
|
||||||
|
|
|
||||||
|
LL | const async unsafe extern "C" fn fi5() {}
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= help: add `#![feature(gen_future)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 23 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0053, E0379, E0706.
|
Some errors have detailed explanations: E0053, E0379, E0706.
|
||||||
For more information about an error, try `rustc --explain E0053`.
|
For more information about an error, try `rustc --explain E0053`.
|
||||||
|
|
|
@ -10,7 +10,7 @@ fn non_const() {}
|
||||||
|
|
||||||
impl const T for S {
|
impl const T for S {
|
||||||
fn foo() { non_const() }
|
fn foo() { non_const() }
|
||||||
//~^ ERROR can only call other `const fn`
|
//~^ ERROR calls in constant functions
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `non_const` is not stable as `const fn`
|
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
--> $DIR/const-check-fns-in-const-impl.rs:12:16
|
--> $DIR/const-check-fns-in-const-impl.rs:12:16
|
||||||
|
|
|
|
||||||
LL | fn foo() { non_const() }
|
LL | fn foo() { non_const() }
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
= 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
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0723`.
|
For more information about this error, try `rustc --explain E0015`.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: fatal error triggered by #[rustc_error]
|
error: fatal error triggered by #[rustc_error]
|
||||||
--> $DIR/feature-gate.rs:16:1
|
--> $DIR/feature-gate.rs:17:1
|
||||||
|
|
|
|
||||||
LL | fn main() {}
|
LL | fn main() {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#![cfg_attr(gated, feature(const_trait_bound_opt_out))]
|
#![cfg_attr(gated, feature(const_trait_bound_opt_out))]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
#![feature(const_fn)]
|
||||||
|
|
||||||
trait T {
|
trait T {
|
||||||
const CONST: i32;
|
const CONST: i32;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0658]: `?const` on trait bounds is experimental
|
error[E0658]: `?const` on trait bounds is experimental
|
||||||
--> $DIR/feature-gate.rs:12:29
|
--> $DIR/feature-gate.rs:13:29
|
||||||
|
|
|
|
||||||
LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
|
LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
@ -30,7 +30,7 @@ impl const std::ops::Add for Int {
|
||||||
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const fn foo() -> Int {
|
pub const fn foo() -> Int {
|
||||||
Int(1i32) + Int(2i32)
|
Int(1i32) + Int(2i32)
|
||||||
//~^ ERROR can only call other `const fn` within a `const fn`
|
//~^ ERROR not yet stable as a const fn
|
||||||
}
|
}
|
||||||
|
|
||||||
// ok
|
// ok
|
||||||
|
|
|
@ -6,18 +6,14 @@ LL | |
|
||||||
LL | | Int(self.0 - rhs.0)
|
LL | | Int(self.0 - rhs.0)
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
|
||||||
= 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
|
|
||||||
|
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `<Int as Add>::add` is not stable as `const fn`
|
error: `<Int as Add>::add` is not yet stable as a const fn
|
||||||
--> $DIR/stability.rs:32:5
|
--> $DIR/stability.rs:32:5
|
||||||
|
|
|
|
||||||
LL | Int(1i32) + Int(2i32)
|
LL | Int(1i32) + Int(2i32)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
|
= help: Const-stable functions can only call other const-stable functions
|
||||||
= help: add `#![feature(const_fn)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,13 @@ fn main() {
|
||||||
|
|
||||||
const fn foo() -> NonZero<u32> {
|
const fn foo() -> NonZero<u32> {
|
||||||
let mut x = unsafe { NonZero(1) };
|
let mut x = unsafe { NonZero(1) };
|
||||||
let y = &mut x.0; //~ ERROR references in const fn are unstable
|
let y = &mut x.0; //~ ERROR mutable references
|
||||||
//~^ ERROR mutation of layout constrained field is unsafe
|
//~^ ERROR mutation of layout constrained field is unsafe
|
||||||
unsafe { NonZero(1) }
|
unsafe { NonZero(1) }
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn bar() -> NonZero<u32> {
|
const fn bar() -> NonZero<u32> {
|
||||||
let mut x = unsafe { NonZero(1) };
|
let mut x = unsafe { NonZero(1) };
|
||||||
let y = unsafe { &mut x.0 }; //~ ERROR mutable references in const fn are unstable
|
let y = unsafe { &mut x.0 }; //~ ERROR mutable references
|
||||||
unsafe { NonZero(1) }
|
unsafe { NonZero(1) }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue