Skip to content

Commit 1854f8b

Browse files
committed
Warn for #[unstable] on trait impls when it has no effect.
1 parent 8c35a92 commit 1854f8b

File tree

1 file changed

+64
-2
lines changed

1 file changed

+64
-2
lines changed

compiler/rustc_passes/src/stability.rs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_hir as hir;
99
use rustc_hir::def::{DefKind, Res};
1010
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
1111
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
12-
use rustc_hir::{Generics, HirId, Item, StructField, Variant};
12+
use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Variant};
1313
use rustc_middle::hir::map::Map;
1414
use rustc_middle::middle::privacy::AccessLevels;
1515
use rustc_middle::middle::stability::{DeprecationEntry, Index};
@@ -538,7 +538,31 @@ impl Visitor<'tcx> for Checker<'tcx> {
538538
// For implementations of traits, check the stability of each item
539539
// individually as it's possible to have a stable trait with unstable
540540
// items.
541-
hir::ItemKind::Impl { of_trait: Some(ref t), items, .. } => {
541+
hir::ItemKind::Impl { of_trait: Some(ref t), self_ty, items, .. } => {
542+
// If this impl block has an #[unstable] attribute, give an
543+
// error if all involved types and traits are stable, because
544+
// it will have no effect.
545+
// See: https://github.com/rust-lang/rust/issues/55436
546+
if let (Some(Stability { level: attr::Unstable { .. }, .. }), _) =
547+
attr::find_stability(&self.tcx.sess, &item.attrs, item.span)
548+
{
549+
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
550+
c.visit_ty(self_ty);
551+
c.visit_trait_ref(t);
552+
if c.fully_stable {
553+
let span = item
554+
.attrs
555+
.iter()
556+
.find(|a| a.has_name(sym::unstable))
557+
.map_or(item.span, |a| a.span);
558+
self.tcx.sess.span_warn(
559+
span,
560+
"An `#[unstable]` annotation here has no effect. \
561+
See issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information.",
562+
);
563+
}
564+
}
565+
542566
if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
543567
for impl_item_ref in items {
544568
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
@@ -598,6 +622,44 @@ impl Visitor<'tcx> for Checker<'tcx> {
598622
}
599623
}
600624

625+
struct CheckTraitImplStable<'tcx> {
626+
tcx: TyCtxt<'tcx>,
627+
fully_stable: bool,
628+
}
629+
630+
impl Visitor<'tcx> for CheckTraitImplStable<'tcx> {
631+
type Map = Map<'tcx>;
632+
633+
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
634+
NestedVisitorMap::None
635+
}
636+
637+
fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) {
638+
if let Some(def_id) = path.res.opt_def_id() {
639+
if let Some(stab) = self.tcx.lookup_stability(def_id) {
640+
self.fully_stable &= stab.level.is_stable();
641+
}
642+
}
643+
intravisit::walk_path(self, path)
644+
}
645+
646+
fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) {
647+
if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
648+
if let Some(stab) = self.tcx.lookup_stability(trait_did) {
649+
self.fully_stable &= stab.level.is_stable();
650+
}
651+
}
652+
intravisit::walk_trait_ref(self, t)
653+
}
654+
655+
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
656+
if let TyKind::Never = t.kind {
657+
self.fully_stable = false;
658+
}
659+
intravisit::walk_ty(self, t)
660+
}
661+
}
662+
601663
/// Given the list of enabled features that were not language features (i.e., that
602664
/// were expected to be library features), and the list of features used from
603665
/// libraries, identify activated features that don't exist and error about them.

0 commit comments

Comments
 (0)