@@ -9,7 +9,7 @@ use rustc_hir as hir;
99use rustc_hir:: def:: { DefKind , Res } ;
1010use rustc_hir:: def_id:: { DefId , LocalDefId , CRATE_DEF_INDEX , LOCAL_CRATE } ;
1111use 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 } ;
1313use rustc_middle:: hir:: map:: Map ;
1414use rustc_middle:: middle:: privacy:: AccessLevels ;
1515use 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