11use clippy_utils:: diagnostics:: { span_lint_and_help, span_lint_and_sugg} ;
2+ use clippy_utils:: msrvs:: { self , Msrv } ;
23use clippy_utils:: source:: { snippet, snippet_opt, snippet_with_applicability} ;
34use clippy_utils:: { is_from_proc_macro, SpanlessEq , SpanlessHash } ;
45use core:: hash:: { Hash , Hasher } ;
@@ -9,7 +10,7 @@ use rustc_data_structures::unhash::UnhashMap;
910use rustc_errors:: Applicability ;
1011use rustc_hir:: def:: Res ;
1112use rustc_hir:: {
12- GenericArg , GenericBound , Generics , Item , ItemKind , Node , Path , PathSegment , PredicateOrigin , QPath ,
13+ GenericArg , GenericBound , Generics , Item , ItemKind , LangItem , Node , Path , PathSegment , PredicateOrigin , QPath ,
1314 TraitBoundModifier , TraitItem , TraitRef , Ty , TyKind , WherePredicate ,
1415} ;
1516use rustc_lint:: { LateContext , LateLintPass } ;
@@ -86,15 +87,16 @@ declare_clippy_lint! {
8687 "check if the same trait bounds are specified more than once during a generic declaration"
8788}
8889
89- #[ derive( Copy , Clone ) ]
90+ #[ derive( Clone ) ]
9091pub struct TraitBounds {
9192 max_trait_bounds : u64 ,
93+ msrv : Msrv ,
9294}
9395
9496impl TraitBounds {
9597 #[ must_use]
96- pub fn new ( max_trait_bounds : u64 ) -> Self {
97- Self { max_trait_bounds }
98+ pub fn new ( max_trait_bounds : u64 , msrv : Msrv ) -> Self {
99+ Self { max_trait_bounds, msrv }
98100 }
99101}
100102
@@ -222,10 +224,24 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
222224 }
223225 }
224226 }
227+
228+ extract_msrv_attr ! ( LateContext ) ;
225229}
226230
227231impl TraitBounds {
228- fn check_type_repetition < ' tcx > ( self , cx : & LateContext < ' tcx > , gen : & ' tcx Generics < ' _ > ) {
232+ /// Is the given bound a `?Sized` bound, and is combining it (i.e. `T: X + ?Sized`) an error on
233+ /// this MSRV? See <https://github.com/rust-lang/rust-clippy/issues/8772> for details.
234+ fn cannot_combine_maybe_bound ( & self , cx : & LateContext < ' _ > , bound : & GenericBound < ' _ > ) -> bool {
235+ if !self . msrv . meets ( msrvs:: MAYBE_BOUND_IN_WHERE )
236+ && let GenericBound :: Trait ( tr, TraitBoundModifier :: Maybe ) = bound
237+ {
238+ cx. tcx . lang_items ( ) . get ( LangItem :: Sized ) == tr. trait_ref . path . res . opt_def_id ( )
239+ } else {
240+ false
241+ }
242+ }
243+
244+ fn check_type_repetition < ' tcx > ( & self , cx : & LateContext < ' tcx > , gen : & ' tcx Generics < ' _ > ) {
229245 struct SpanlessTy < ' cx , ' tcx > {
230246 ty : & ' tcx Ty < ' tcx > ,
231247 cx : & ' cx LateContext < ' tcx > ,
@@ -256,10 +272,9 @@ impl TraitBounds {
256272 if p. origin != PredicateOrigin :: ImplTrait ;
257273 if p. bounds. len( ) as u64 <= self . max_trait_bounds;
258274 if !p. span. from_expansion( ) ;
259- if let Some ( ref v) = map. insert(
260- SpanlessTy { ty: p. bounded_ty, cx } ,
261- p. bounds. iter( ) . collect:: <Vec <_>>( )
262- ) ;
275+ let bounds = p. bounds. iter( ) . filter( |b| !self . cannot_combine_maybe_bound( cx, b) ) . collect:: <Vec <_>>( ) ;
276+ if !bounds. is_empty( ) ;
277+ if let Some ( ref v) = map. insert( SpanlessTy { ty: p. bounded_ty, cx } , bounds) ;
263278 if !is_from_proc_macro( cx, p. bounded_ty) ;
264279 then {
265280 let trait_bounds = v
0 commit comments