Skip to content

Commit 47a0dfe

Browse files
author
Alexander Regueiro
committed
Lint duplicate trait and lifetime bounds.
1 parent 37d51aa commit 47a0dfe

12 files changed

+203
-28
lines changed

src/libcore/array.rs

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
integer constants",
1010
issue = "27778")]
1111

12+
#![cfg_attr(not(stage0), allow(duplicate_bounds))]
13+
1214
use borrow::{Borrow, BorrowMut};
1315
use cmp::Ordering;
1416
use convert::TryFrom;

src/librustc/lint/builtin.rs

+15
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,19 @@ declare_lint! {
346346
"outlives requirements can be inferred"
347347
}
348348

349+
declare_lint! {
350+
pub DEPRECATED_IN_FUTURE,
351+
Allow,
352+
"detects use of items that will be deprecated in a future version",
353+
report_in_external_macro: true
354+
}
355+
356+
declare_lint! {
357+
pub DUPLICATE_BOUNDS,
358+
Warn,
359+
"detects duplicate bounds on type parameters, lifetime parameters, and projections"
360+
}
361+
349362
/// Some lints that are buffered from `libsyntax`. See `syntax::early_buffered_lints`.
350363
pub mod parser {
351364
declare_lint! {
@@ -440,6 +453,8 @@ impl LintPass for HardwiredLints {
440453
parser::ILL_FORMED_ATTRIBUTE_INPUT,
441454
DEPRECATED_IN_FUTURE,
442455
AMBIGUOUS_ASSOCIATED_ITEMS,
456+
DUPLICATE_BOUNDS,
457+
parser::QUESTION_MARK_MACRO_SEP,
443458
)
444459
}
445460
}

src/librustc/traits/util.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use errors::DiagnosticBuilder;
12
use hir;
23
use hir::def_id::DefId;
34
use traits::specialize::specialization_graph::NodeItem;

src/librustc/ty/mod.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -1212,18 +1212,32 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
12121212
// ok to skip binder since trait def-id does not care about regions
12131213
self.skip_binder().def_id()
12141214
}
1215+
1216+
pub fn self_ty(&self) -> Binder<Ty<'tcx>> {
1217+
self.map_bound(|p| p.self_ty())
1218+
}
12151219
}
12161220

12171221
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
1218-
pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A: B`
1219-
pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
1222+
pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B`
1223+
pub type PolyOutlivesPredicate<A, B> = ty::Binder<OutlivesPredicate<A, B>>;
12201224
pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>,
12211225
ty::Region<'tcx>>;
12221226
pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>,
12231227
ty::Region<'tcx>>;
12241228
pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<RegionOutlivesPredicate<'tcx>>;
12251229
pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<TypeOutlivesPredicate<'tcx>>;
12261230

1231+
impl<A: Copy, B: Copy> PolyOutlivesPredicate<A, B> {
1232+
pub fn var(&self) -> Binder<A> {
1233+
self.map_bound(|pred| pred.0)
1234+
}
1235+
1236+
pub fn value(&self) -> Binder<B> {
1237+
self.map_bound(|pred| pred.1)
1238+
}
1239+
}
1240+
12271241
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
12281242
pub struct SubtypePredicate<'tcx> {
12291243
pub a_is_expected: bool,
@@ -1265,11 +1279,11 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
12651279
// This is because here `self` has a `Binder` and so does our
12661280
// return value, so we are preserving the number of binding
12671281
// levels.
1268-
self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx))
1282+
self.map_bound(|pred| pred.projection_ty.trait_ref(tcx))
12691283
}
12701284

12711285
pub fn ty(&self) -> Binder<Ty<'tcx>> {
1272-
self.map_bound(|predicate| predicate.ty)
1286+
self.map_bound(|pred| pred.ty)
12731287
}
12741288

12751289
/// The `DefId` of the `TraitItem` for the associated type.

src/librustc_lint/builtin.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use rustc::hir::{self, GenericParamKind, PatKind};
4747

4848
use nonstandard_style::{MethodLateContext, method_context};
4949

50-
// hardwired lints from librustc
50+
// Hardwired lints from librustc.
5151
pub use lint::builtin::*;
5252

5353
declare_lint! {

src/librustc_lint/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
345345
reference: "issue #57644 <https://github.com/rust-lang/rust/issues/57644>",
346346
edition: None,
347347
},
348-
]);
348+
]);
349349

350350
// Register renamed and removed lints.
351351
store.register_renamed("single_use_lifetime", "single_use_lifetimes");

src/librustc_typeck/astconv.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use std::collections::BTreeSet;
3232
use std::iter;
3333
use std::slice;
3434

35+
use crate::collect::{lint_duplicate_bounds, LintedBoundVar, LintedBoundValue};
3536
use super::{check_type_alias_enum_variants_enabled};
3637
use rustc_data_structures::fx::FxHashSet;
3738

@@ -940,6 +941,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
940941
}
941942

942943
fn conv_object_ty_poly_trait_ref(&self,
944+
node_id: ast::NodeId,
943945
span: Span,
944946
trait_bounds: &[hir::PolyTraitRef],
945947
lifetime: &hir::Lifetime)
@@ -980,6 +982,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
980982
.emit();
981983
}
982984

985+
// Lint duplicate bounds.
986+
{
987+
let bounds = trait_bounds.iter().filter_map(|b| {
988+
let trait_did = b.trait_ref.trait_def_id();
989+
Some((LintedBoundVar::SelfTy, LintedBoundValue::DefId(trait_did), b.span))
990+
});
991+
lint_duplicate_bounds(tcx, node_id, bounds);
992+
}
993+
983994
// Check that there are no gross object safety violations;
984995
// most importantly, that the supertraits don't contain `Self`,
985996
// to avoid ICEs.
@@ -1767,7 +1778,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
17671778
tcx.mk_fn_ptr(self.ty_of_fn(bf.unsafety, bf.abi, &bf.decl))
17681779
}
17691780
hir::TyKind::TraitObject(ref bounds, ref lifetime) => {
1770-
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
1781+
self.conv_object_ty_poly_trait_ref(ast_ty.id, ast_ty.span, bounds, lifetime)
17711782
}
17721783
hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
17731784
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);

src/librustc_typeck/collect.rs

+89-14
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,11 @@ use middle::lang_items::SizedTraitLangItem;
2222
use middle::resolve_lifetime as rl;
2323
use middle::weak_lang_items;
2424
use rustc::mir::mono::Linkage;
25+
use rustc::ty::{self, AdtKind, Binder, Predicate, ToPolyTraitRef, Ty, TyCtxt};
2526
use rustc::ty::query::Providers;
2627
use rustc::ty::query::queries;
2728
use rustc::ty::subst::Substs;
28-
use rustc::ty::util::Discr;
29-
use rustc::ty::util::IntTypeExt;
30-
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
29+
use rustc::ty::util::{Discr, IntTypeExt};
3130
use rustc::ty::{ReprOptions, ToPredicate};
3231
use rustc::util::captures::Captures;
3332
use rustc::util::nodemap::FxHashMap;
@@ -50,9 +49,65 @@ use rustc::hir::GenericParamKind;
5049
use rustc::hir::{self, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety};
5150

5251
use std::iter;
52+
use std::ops::Range;
5353

5454
struct OnlySelfBounds(bool);
5555

56+
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
57+
pub enum LintedBoundVar<'tcx> {
58+
DefId(DefId),
59+
SelfTy,
60+
Ty(Binder<Ty<'tcx>>),
61+
Region(Binder<ty::Region<'tcx>>),
62+
}
63+
64+
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
65+
pub enum LintedBoundValue<'tcx> {
66+
DefId(DefId),
67+
Ty(Binder<Ty<'tcx>>),
68+
Region(Binder<ty::Region<'tcx>>),
69+
}
70+
71+
pub fn lint_duplicate_bounds<'a, 'gcx, 'tcx>(
72+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
73+
node_id: ast::NodeId,
74+
bounds: impl IntoIterator<Item = (LintedBoundVar<'tcx>, LintedBoundValue<'tcx>, Span)>,
75+
) {
76+
let mut bounds: Vec<_> = bounds.into_iter().collect();
77+
bounds.sort_unstable();
78+
79+
let emit_lint = |range: Range<usize>| {
80+
let bound_name = tcx.sess.source_map()
81+
.span_to_snippet(bounds[range.start].2).unwrap();
82+
let mut err = tcx.struct_span_lint_node(
83+
lint::builtin::DUPLICATE_BOUNDS,
84+
node_id,
85+
bounds[range.clone()].iter().map(|(_, _, sp)| *sp).collect::<Vec<_>>(),
86+
&format!("duplicate bound `{}` found",
87+
bound_name));
88+
debug!("zzz: 1: {:?} / {:?}", bounds[range.start].0, bounds[range.start].1);
89+
err.span_label(bounds[range.start].2, "first use of bound");
90+
for i in (range.start + 1)..range.end {
91+
debug!("zzz: 2: {:?} / {:?}", bounds[i].0, bounds[i].1);
92+
err.span_label(bounds[i].2, "subsequent use of bound");
93+
}
94+
err.emit();
95+
};
96+
97+
let mut seq_start = 0;
98+
for i in 1..bounds.len() {
99+
if (&bounds[i].0, &bounds[i].1) != (&bounds[i - 1].0, &bounds[i - 1].1) {
100+
if i - seq_start > 1 {
101+
emit_lint(seq_start..i);
102+
}
103+
seq_start = i;
104+
}
105+
}
106+
if bounds.len() - seq_start > 1 {
107+
emit_lint(seq_start..bounds.len());
108+
}
109+
}
110+
56111
///////////////////////////////////////////////////////////////////////////
57112
// Main entry point
58113

@@ -336,7 +391,7 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
336391
param_id: ast::NodeId,
337392
ty: Ty<'tcx>,
338393
only_self_bounds: OnlySelfBounds,
339-
) -> Vec<(ty::Predicate<'tcx>, Span)> {
394+
) -> Vec<(Predicate<'tcx>, Span)> {
340395
let from_ty_params = ast_generics
341396
.params
342397
.iter()
@@ -726,7 +781,7 @@ fn super_predicates_of<'a, 'tcx>(
726781
// which will, in turn, reach indirect supertraits.
727782
for &(pred, span) in &superbounds {
728783
debug!("superbound: {:?}", pred);
729-
if let ty::Predicate::Trait(bound) = pred {
784+
if let Predicate::Trait(bound) = pred {
730785
tcx.at(span).super_predicates_of(bound.def_id());
731786
}
732787
}
@@ -1672,8 +1727,8 @@ fn explicit_predicates_of<'a, 'tcx>(
16721727
/// Preserving the order of insertion is important here so as not to break
16731728
/// compile-fail UI tests.
16741729
struct UniquePredicates<'tcx> {
1675-
predicates: Vec<(ty::Predicate<'tcx>, Span)>,
1676-
uniques: FxHashSet<(ty::Predicate<'tcx>, Span)>,
1730+
predicates: Vec<(Predicate<'tcx>, Span)>,
1731+
uniques: FxHashSet<(Predicate<'tcx>, Span)>,
16771732
}
16781733

16791734
impl<'tcx> UniquePredicates<'tcx> {
@@ -1684,13 +1739,13 @@ fn explicit_predicates_of<'a, 'tcx>(
16841739
}
16851740
}
16861741

1687-
fn push(&mut self, value: (ty::Predicate<'tcx>, Span)) {
1742+
fn push(&mut self, value: (Predicate<'tcx>, Span)) {
16881743
if self.uniques.insert(value) {
16891744
self.predicates.push(value);
16901745
}
16911746
}
16921747

1693-
fn extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter: I) {
1748+
fn extend<I: IntoIterator<Item = (Predicate<'tcx>, Span)>>(&mut self, iter: I) {
16941749
for value in iter {
16951750
self.push(value);
16961751
}
@@ -1884,7 +1939,7 @@ fn explicit_predicates_of<'a, 'tcx>(
18841939
let span = bound_pred.bounded_ty.span;
18851940
let predicate = ty::OutlivesPredicate(ty, tcx.mk_region(ty::ReEmpty));
18861941
predicates.push(
1887-
(ty::Predicate::TypeOutlives(ty::Binder::dummy(predicate)), span)
1942+
(Predicate::TypeOutlives(ty::Binder::dummy(predicate)), span)
18881943
);
18891944
}
18901945
}
@@ -1910,7 +1965,7 @@ fn explicit_predicates_of<'a, 'tcx>(
19101965
&hir::GenericBound::Outlives(ref lifetime) => {
19111966
let region = AstConv::ast_region_to_region(&icx, lifetime, None);
19121967
let pred = ty::Binder::bind(ty::OutlivesPredicate(ty, region));
1913-
predicates.push((ty::Predicate::TypeOutlives(pred), lifetime.span))
1968+
predicates.push((Predicate::TypeOutlives(pred), lifetime.span))
19141969
}
19151970
}
19161971
}
@@ -1927,7 +1982,7 @@ fn explicit_predicates_of<'a, 'tcx>(
19271982
};
19281983
let pred = ty::Binder::bind(ty::OutlivesPredicate(r1, r2));
19291984

1930-
(ty::Predicate::RegionOutlives(pred), span)
1985+
(Predicate::RegionOutlives(pred), span)
19311986
}))
19321987
}
19331988

@@ -1983,6 +2038,26 @@ fn explicit_predicates_of<'a, 'tcx>(
19832038
);
19842039
}
19852040

2041+
// Lint duplicate bounds.
2042+
let bounds = predicates.iter().filter_map(|(pred, sp)| {
2043+
match pred {
2044+
Predicate::Trait(ref pred) =>
2045+
Some((LintedBoundVar::Ty(pred.self_ty()),
2046+
LintedBoundValue::DefId(pred.def_id()), *sp)),
2047+
Predicate::RegionOutlives(ref pred) =>
2048+
Some((LintedBoundVar::Region(pred.var()),
2049+
LintedBoundValue::Region(pred.value()), *sp)),
2050+
Predicate::TypeOutlives(ref pred) =>
2051+
Some((LintedBoundVar::Ty(pred.var()),
2052+
LintedBoundValue::Region(pred.value()), *sp)),
2053+
Predicate::Projection(ref pred) =>
2054+
Some((LintedBoundVar::DefId(pred.item_def_id()),
2055+
LintedBoundValue::Ty(pred.ty()), *sp)),
2056+
_ => None,
2057+
}
2058+
});
2059+
lint_duplicate_bounds(tcx, node_id, bounds);
2060+
19862061
let result = Lrc::new(ty::GenericPredicates {
19872062
parent: generics.parent,
19882063
predicates,
@@ -2062,7 +2137,7 @@ fn predicates_from_bound<'tcx>(
20622137
astconv: &dyn AstConv<'tcx, 'tcx>,
20632138
param_ty: Ty<'tcx>,
20642139
bound: &hir::GenericBound,
2065-
) -> Vec<(ty::Predicate<'tcx>, Span)> {
2140+
) -> Vec<(Predicate<'tcx>, Span)> {
20662141
match *bound {
20672142
hir::GenericBound::Trait(ref tr, hir::TraitBoundModifier::None) => {
20682143
let mut projections = Vec::new();
@@ -2076,7 +2151,7 @@ fn predicates_from_bound<'tcx>(
20762151
hir::GenericBound::Outlives(ref lifetime) => {
20772152
let region = astconv.ast_region_to_region(lifetime, None);
20782153
let pred = ty::Binder::bind(ty::OutlivesPredicate(param_ty, region));
2079-
vec![(ty::Predicate::TypeOutlives(pred), lifetime.span)]
2154+
vec![(Predicate::TypeOutlives(pred), lifetime.span)]
20802155
}
20812156
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => vec![],
20822157
}

src/test/ui/lint/lint-incoherent-auto-trait-objects.rs

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ impl Foo for dyn Send {}
77
impl Foo for dyn Send + Send {}
88
//~^ ERROR conflicting implementations
99
//~| hard error
10+
//~^^^ WARNING duplicate auto trait `Send` found in type parameter bounds [duplicate_auto_traits_in_bounds]
1011

1112
impl Foo for dyn Send + Sync {}
1213

@@ -17,5 +18,6 @@ impl Foo for dyn Sync + Send {}
1718
impl Foo for dyn Send + Sync + Send {}
1819
//~^ ERROR conflicting implementations
1920
//~| hard error
21+
//~^^^ WARNING duplicate auto trait `Send` found in type parameter bounds [duplicate_auto_traits_in_bounds]
2022

2123
fn main() {}

src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr

+18
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
warning: duplicate auto trait `Send` found in type parameter bounds
2+
--> $DIR/lint-incoherent-auto-trait-objects.rs:7:18
3+
|
4+
LL | impl Foo for dyn Send + Send {}
5+
| ^^^^ ^^^^ subsequent use of auto trait
6+
| |
7+
| first use of auto trait
8+
|
9+
= note: #[warn(duplicate_auto_traits_in_bounds)] on by default
10+
11+
warning: duplicate auto trait `Send` found in type parameter bounds
12+
--> $DIR/lint-incoherent-auto-trait-objects.rs:18:18
13+
|
14+
LL | impl Foo for dyn Send + Sync + Send {}
15+
| ^^^^ ^^^^ subsequent use of auto trait
16+
| |
17+
| first use of auto trait
18+
119
error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + 'static)`: (E0119)
220
--> $DIR/lint-incoherent-auto-trait-objects.rs:7:1
321
|

0 commit comments

Comments
 (0)