1
1
use clippy_utils:: diagnostics:: { span_lint_and_help, span_lint_and_sugg} ;
2
+ use clippy_utils:: msrvs:: { self , Msrv } ;
2
3
use clippy_utils:: source:: { snippet, snippet_opt, snippet_with_applicability} ;
3
4
use clippy_utils:: { is_from_proc_macro, SpanlessEq , SpanlessHash } ;
4
5
use core:: hash:: { Hash , Hasher } ;
@@ -9,7 +10,7 @@ use rustc_data_structures::unhash::UnhashMap;
9
10
use rustc_errors:: Applicability ;
10
11
use rustc_hir:: def:: Res ;
11
12
use 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 ,
13
14
TraitBoundModifier , TraitItem , TraitRef , Ty , TyKind , WherePredicate ,
14
15
} ;
15
16
use rustc_lint:: { LateContext , LateLintPass } ;
@@ -86,15 +87,16 @@ declare_clippy_lint! {
86
87
"check if the same trait bounds are specified more than once during a generic declaration"
87
88
}
88
89
89
- #[ derive( Copy , Clone ) ]
90
+ #[ derive( Clone ) ]
90
91
pub struct TraitBounds {
91
92
max_trait_bounds : u64 ,
93
+ msrv : Msrv ,
92
94
}
93
95
94
96
impl TraitBounds {
95
97
#[ 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 }
98
100
}
99
101
}
100
102
@@ -222,10 +224,24 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
222
224
}
223
225
}
224
226
}
227
+
228
+ extract_msrv_attr ! ( LateContext ) ;
225
229
}
226
230
227
231
impl 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:: COMBINED_MAYBE_BOUND )
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 < ' _ > ) {
229
245
struct SpanlessTy < ' cx , ' tcx > {
230
246
ty : & ' tcx Ty < ' tcx > ,
231
247
cx : & ' cx LateContext < ' tcx > ,
@@ -256,10 +272,9 @@ impl TraitBounds {
256
272
if p. origin != PredicateOrigin :: ImplTrait ;
257
273
if p. bounds. len( ) as u64 <= self . max_trait_bounds;
258
274
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) ;
263
278
if !is_from_proc_macro( cx, p. bounded_ty) ;
264
279
then {
265
280
let trait_bounds = v
0 commit comments