Skip to content

Commit 416195e

Browse files
pierwillestebank
andcommitted
Add duplicate trait bound lint
Co-authored-by: Esteban Kuber <estebank@users.noreply.github.com>
1 parent ca4e394 commit 416195e

File tree

4 files changed

+71
-0
lines changed

4 files changed

+71
-0
lines changed

compiler/rustc_lint/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ macro_rules! late_lint_mod_passes {
209209
UnstableFeatures: UnstableFeatures,
210210
ArrayIntoIter: ArrayIntoIter::default(),
211211
DropTraitConstraints: DropTraitConstraints,
212+
DuplicateTraitBounds: DuplicateTraitBounds,
212213
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
213214
NonPanicFmt: NonPanicFmt,
214215
NoopMethodCall: NoopMethodCall,

compiler/rustc_lint/src/traits.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::LateContext;
22
use crate::LateLintPass;
33
use crate::LintContext;
4+
use hir::GenericBound;
5+
use rustc_data_structures::stable_set::FxHashSet;
46
use rustc_errors::fluent;
57
use rustc_hir as hir;
68
use rustc_span::symbol::sym;
@@ -132,3 +134,44 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
132134
}
133135
}
134136
}
137+
138+
declare_lint! {
139+
pub DUP_TRAIT_BOUNDS,
140+
Deny,
141+
"duplicate trait bounds"
142+
}
143+
144+
declare_lint_pass!(
145+
DuplicateTraitBounds => [DUP_TRAIT_BOUNDS]
146+
);
147+
148+
impl<'tcx> LateLintPass<'tcx> for DuplicateTraitBounds {
149+
fn check_item(&mut self, cx: &LateContext<'_>, item: &'tcx hir::Item<'tcx>) {
150+
let bounds: &[hir::GenericBound<'_>] = match &item.kind {
151+
hir::ItemKind::Trait(_, _, _, bounds, _) => bounds,
152+
hir::ItemKind::TraitAlias(_, bounds) => bounds,
153+
_ => return,
154+
};
155+
156+
let mut set = FxHashSet::default();
157+
for bound in bounds.into_iter() {
158+
match bound {
159+
GenericBound::Trait(polytraitref, _) => {
160+
let Some(did) = polytraitref.trait_ref.trait_def_id() else { continue; };
161+
// If inserting the trait bound into the set returns `false`,
162+
// there is a duplicate.
163+
if !set.insert(did) {
164+
let span = polytraitref.span;
165+
cx.struct_span_lint(DUP_TRAIT_BOUNDS, span, |lint| {
166+
let msg = format!("Duplicate trait bound");
167+
lint.build(&msg)
168+
.span_help(span, "Remove this duplicate trait bound")
169+
.emit();
170+
});
171+
};
172+
}
173+
_ => continue,
174+
}
175+
}
176+
}
177+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
pub trait DirectedGraph {}
2+
pub trait WithStartNode {}
3+
pub trait WithPredecessors {}
4+
pub trait WithSuccessors {}
5+
pub trait WithNumNodes {}
6+
7+
pub trait ControlFlowGraph:
8+
DirectedGraph + WithStartNode + WithPredecessors + WithStartNode + WithSuccessors + WithNumNodes
9+
//~ ERROR duplicate trait bound
10+
{}
11+
12+
fn main() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Duplicate trait bound
2+
--> $DIR/duplicate-trait-bounds.rs:8:56
3+
|
4+
LL | DirectedGraph + WithStartNode + WithPredecessors + WithStartNode + WithSuccessors + WithNumNodes
5+
| ^^^^^^^^^^^^^
6+
|
7+
= note: `#[deny(dup_trait_bounds)]` on by default
8+
help: Remove this duplicate trait bound
9+
--> $DIR/duplicate-trait-bounds.rs:8:56
10+
|
11+
LL | DirectedGraph + WithStartNode + WithPredecessors + WithStartNode + WithSuccessors + WithNumNodes
12+
| ^^^^^^^^^^^^^
13+
14+
error: aborting due to previous error
15+

0 commit comments

Comments
 (0)