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

@ -9,6 +9,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::privacy::AccessLevels;
@ -530,7 +531,8 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
return;
}
let is_const = self.tcx.is_const_fn(def_id.to_def_id());
let is_const = self.tcx.is_const_fn(def_id.to_def_id())
|| self.tcx.is_const_trait_impl_raw(def_id.to_def_id());
let is_stable = self
.tcx
.lookup_stability(def_id)
@ -604,6 +606,44 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
// stable (assuming they have not inherited instability from their parent).
}
struct CheckStableConstImplTrait<'tcx> {
tcx: TyCtxt<'tcx>,
}
impl<'tcx> ItemLikeVisitor<'tcx> for CheckStableConstImplTrait<'tcx> {
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
if !matches!(
item.kind,
hir::ItemKind::Impl(hir::Impl {
of_trait: Some(_),
constness: hir::Constness::Const,
..
})
) {
return;
}
if self.tcx.lookup_const_stability(item.def_id).map_or(false, |stab| stab.is_const_stable())
{
self.tcx
.sess
.struct_span_err(item.span, "trait implementations cannot be const stable yet")
.note("see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information")
.emit();
}
}
fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem<'tcx>) {
// Nothing to do here.
}
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem<'tcx>) {
// Nothing to do here.
}
fn visit_foreign_item(&mut self, _foreign_item: &'tcx hir::ForeignItem<'tcx>) {
// Nothing to do here.
}
}
fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
let mut index = Index {
stab_map: Default::default(),
@ -824,6 +864,17 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
}
}
pub fn check_const_impl_trait(tcx: TyCtxt<'_>) {
let features = tcx.features(); // FIXME How cheap is this call?
// Both feature gates have to be enabled for this check to have any effect.
if !features.staged_api || !features.const_trait_impl {
return;
}
let mut visitor = CheckStableConstImplTrait { tcx };
tcx.hir().visit_all_item_likes(&mut visitor);
}
/// Given the list of enabled features that were not language features (i.e., that
/// were expected to be library features), and the list of features used from
/// libraries, identify activated features that don't exist and error about them.