Auto merge of #97177 - oli-obk:const-stability, r=davidtwco
Implement proper stability check for const impl Trait, fall back to unstable const when undeclared Continuation of #93960 `@jhpratt` it looks to me like the test was simply not testing for the failure you were looking for? Your checks actually do the right thing for const traits?
This commit is contained in:
commit
acfd327fd4
22 changed files with 259 additions and 168 deletions
|
@ -9,7 +9,7 @@ use rustc_span::symbol::Symbol;
|
|||
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
|
||||
if tcx.is_const_fn_raw(def_id) {
|
||||
let const_stab = tcx.lookup_const_stability(def_id)?;
|
||||
if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
|
||||
if const_stab.is_const_unstable() { Some(const_stab.feature) } else { None }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -944,7 +932,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
// 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());
|
||||
&& tcx.lookup_stability(callee).map_or(false, |s| s.is_unstable());
|
||||
if callee_is_unstable_unmarked {
|
||||
trace!("callee_is_unstable_unmarked");
|
||||
// We do not use `const` modifiers for intrinsic "functions", as intrinsics are
|
||||
|
|
|
@ -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, Stability, 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,22 +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));
|
||||
|
||||
// Functions with `#[rustc_const_unstable]` are const-unstable.
|
||||
// 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(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false,
|
||||
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true,
|
||||
None => {}
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
true
|
||||
tcx.lookup_const_stability(parent.owner).map_or(false, |stab| stab.is_const_stable())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue