1
Fork 0

Proper const stability check, default to unstable

Rather than deferring to const eval for checking if a trait is const, we
now check up-front. This allows the error to be emitted earlier, notably
at the same time as other stability checks.

Also included in this commit is a change of the default const stability
level to UNstable. Previously, an item that was `const` but did not
explicitly state it was unstable was implicitly stable.
This commit is contained in:
Jacob Pratt 2022-02-13 05:54:00 -05:00 committed by Oli Scherer
parent a9dd4cfa6b
commit f0620c9503
16 changed files with 196 additions and 93 deletions

View file

@ -229,18 +229,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
// The local type and predicate checks are not free and only relevant for `const fn`s.
if self.const_kind() == hir::ConstContext::ConstFn {
// Prevent const trait methods from being annotated as `stable`.
// FIXME: Do this as part of stability checking.
if self.is_const_stable_const_fn() {
if crate::const_eval::is_parent_const_impl_raw(tcx, def_id) {
self.ccx
.tcx
.sess
.struct_span_err(self.span, "trait methods cannot be stable const fn")
.emit();
}
}
for (idx, local) in body.local_decls.iter_enumerated() {
// Handle the return place below.
if idx == RETURN_PLACE || local.internal {

View file

@ -84,8 +84,6 @@ pub fn rustc_allow_const_fn_unstable(
// 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<'_>, def_id: DefId) -> bool {
use attr::{ConstStability, StabilityLevel};
// A default body marked const is not const-stable because const
// trait fns currently cannot be const-stable. We shouldn't
// restrict default bodies to only call const-stable functions.
@ -96,9 +94,39 @@ pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// Const-stability is only relevant for `const fn`.
assert!(tcx.is_const_fn_raw(def_id));
// A function is only const-stable if it has `#[rustc_const_stable]`.
matches!(
tcx.lookup_const_stability(def_id),
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. })
)
// A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs
// to is const-stable.
match tcx.lookup_const_stability(def_id) {
Some(stab) => stab.is_const_stable(),
None if is_parent_const_stable_trait(tcx, def_id) => {
// Remove this when `#![feature(const_trait_impl)]` is stabilized,
// returning `true` unconditionally.
tcx.sess.delay_span_bug(
tcx.def_span(def_id),
"trait implementations cannot be const stable yet",
);
true
}
None => false, // By default, items are not const stable.
}
}
fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
let local_def_id = def_id.expect_local();
let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
let Some(parent) = tcx.hir().find_parent_node(hir_id) else { return false };
let parent_def = tcx.hir().get(parent);
if !matches!(
parent_def,
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
..
})
) {
return false;
}
tcx.lookup_const_stability(parent.owner).map_or(false, |stab| stab.is_const_stable())
}