Skip to content

Commit ce0a48a

Browse files
committed
Auto merge of #10994 - y21:issue8772, r=giraffate
[`type_repetition_in_bounds`]: respect MSRV for combining bounds Fixes #8772. changelog: [`type_repetition_in_bounds`]: respect msrv for combining `?Sized` bound
2 parents 6ec2388 + 75f9fbc commit ce0a48a

File tree

7 files changed

+61
-12
lines changed

7 files changed

+61
-12
lines changed

book/src/lint_configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ The minimum rust version that the project supports
147147
* [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check)
148148
* [`manual_rem_euclid`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid)
149149
* [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain)
150+
* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds)
150151

151152

152153
## `cognitive-complexity-threshold`

clippy_lints/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
792792
store.register_late_pass(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates));
793793
store.register_late_pass(|_| Box::new(inherent_to_string::InherentToString));
794794
let max_trait_bounds = conf.max_trait_bounds;
795-
store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
795+
store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds, msrv())));
796796
store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain));
797797
let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
798798
store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone())));

clippy_lints/src/trait_bounds.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
2+
use clippy_utils::msrvs::{self, Msrv};
23
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
34
use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash};
45
use core::hash::{Hash, Hasher};
@@ -9,7 +10,7 @@ use rustc_data_structures::unhash::UnhashMap;
910
use rustc_errors::Applicability;
1011
use rustc_hir::def::Res;
1112
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,
1314
TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate,
1415
};
1516
use 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)]
9091
pub struct TraitBounds {
9192
max_trait_bounds: u64,
93+
msrv: Msrv,
9294
}
9395

9496
impl 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

227231
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::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

clippy_lints/src/utils/conf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ define_Conf! {
294294
///
295295
/// Suppress lints whenever the suggested change would cause breakage for other crates.
296296
(avoid_breaking_exported_api: bool = true),
297-
/// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN.
297+
/// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS.
298298
///
299299
/// The minimum rust version that the project supports
300300
(msrv: Option<String> = None),

clippy_utils/src/msrvs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ msrv_aliases! {
4747
1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN }
4848
1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
4949
1,16,0 { STR_REPEAT }
50+
1,15,0 { MAYBE_BOUND_IN_WHERE }
5051
}
5152

5253
fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {

tests/ui/type_repetition_in_bounds.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,28 @@ where
110110
// This should not lint
111111
fn impl_trait(_: impl AsRef<str>, _: impl AsRef<str>) {}
112112

113+
#[clippy::msrv = "1.14.0"]
114+
mod issue8772_fail {
115+
pub trait Trait<X, Y, Z> {}
116+
117+
pub fn f<T: ?Sized, U>(arg: usize)
118+
where
119+
T: Trait<Option<usize>, Box<[String]>, bool> + 'static,
120+
U: Clone + Sync + 'static,
121+
{
122+
}
123+
}
124+
125+
#[clippy::msrv = "1.15.0"]
126+
mod issue8772_pass {
127+
pub trait Trait<X, Y, Z> {}
128+
129+
pub fn f<T: ?Sized, U>(arg: usize)
130+
where
131+
T: Trait<Option<usize>, Box<[String]>, bool> + 'static,
132+
U: Clone + Sync + 'static,
133+
{
134+
}
135+
}
136+
113137
fn main() {}

tests/ui/type_repetition_in_bounds.stderr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,13 @@ LL | T: ?Sized,
3535
|
3636
= help: consider combining the bounds: `T: Clone + ?Sized`
3737

38-
error: aborting due to 4 previous errors
38+
error: this type has already been used as a bound predicate
39+
--> $DIR/type_repetition_in_bounds.rs:131:9
40+
|
41+
LL | T: Trait<Option<usize>, Box<[String]>, bool> + 'static,
42+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43+
|
44+
= help: consider combining the bounds: `T: ?Sized + Trait<Option<usize>, Box<[String]>, bool>`
45+
46+
error: aborting due to 5 previous errors
3947

0 commit comments

Comments
 (0)