Skip to content

Commit dabb820

Browse files
committed
Add trivial bounds lint
1 parent 27183a9 commit dabb820

File tree

5 files changed

+177
-0
lines changed

5 files changed

+177
-0
lines changed

src/librustc_lint/builtin.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,3 +1591,61 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExternCrate {
15911591
self.0 += 1;
15921592
}
15931593
}
1594+
1595+
/// Lint for trait and lifetime bounds that don't depend on type parameters
1596+
/// which either do nothing, or stop the item from being used.
1597+
pub struct TrivialConstraints;
1598+
1599+
declare_lint! {
1600+
TRIVIAL_BOUNDS,
1601+
Warn,
1602+
"these bounds don't depend on an type parameters"
1603+
}
1604+
1605+
impl LintPass for TrivialConstraints {
1606+
fn get_lints(&self) -> LintArray {
1607+
lint_array!(TRIVIAL_BOUNDS)
1608+
}
1609+
}
1610+
1611+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
1612+
fn check_item(
1613+
&mut self,
1614+
cx: &LateContext<'a, 'tcx>,
1615+
item: &'tcx hir::Item,
1616+
) {
1617+
use rustc::ty::fold::TypeFoldable;
1618+
use rustc::ty::Predicate::*;
1619+
1620+
1621+
if cx.tcx.features().trivial_bounds {
1622+
let def_id = cx.tcx.hir.local_def_id(item.id);
1623+
let predicates = cx.tcx.predicates_of(def_id);
1624+
for predicate in &predicates.predicates {
1625+
let predicate_kind_name = match *predicate {
1626+
Trait(..) => "Trait",
1627+
TypeOutlives(..) |
1628+
RegionOutlives(..) => "Lifetime",
1629+
1630+
// Ignore projections, as they can only be global
1631+
// if the trait bound is global
1632+
Projection(..) |
1633+
// Ignore bounds that a user can't type
1634+
WellFormed(..) |
1635+
ObjectSafe(..) |
1636+
ClosureKind(..) |
1637+
Subtype(..) |
1638+
ConstEvaluatable(..) => continue,
1639+
};
1640+
if !predicate.is_global() {
1641+
cx.span_lint(
1642+
TRIVIAL_BOUNDS,
1643+
item.span,
1644+
&format!("{} bound {} does not depend on any type \
1645+
or lifetime parameters", predicate_kind_name, predicate),
1646+
);
1647+
}
1648+
}
1649+
}
1650+
}
1651+
}

src/librustc_lint/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
137137
UnreachablePub,
138138
TypeAliasBounds,
139139
UnusedBrokenConst,
140+
TrivialConstraints,
140141
);
141142

142143
add_builtin_with_new!(sess,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// run-pass
12+
13+
#![allow(unused)]
14+
#![deny(trivial_bounds)] // Ignored without the trivial_bounds feature flag.
15+
16+
struct A where i32: Copy;
17+
18+
fn main() {}

src/test/ui/trivial-bounds-lint.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(trivial_bounds)]
12+
#![allow(unused)]
13+
#![deny(trivial_bounds)]
14+
15+
struct A where i32: Copy; //~ ERROR
16+
17+
trait X<T: Copy> {}
18+
19+
trait Y<T>: Copy {}
20+
21+
trait Z {
22+
type S: Copy;
23+
}
24+
25+
// Check only the bound the user writes trigger the lint
26+
fn trivial_elaboration<T>() where T: X<i32> + Z<S = i32>, i32: Y<T> {} // OK
27+
28+
fn global_param() where i32: X<()> {} //~ ERROR
29+
30+
// Should only error on the trait bound, not the implicit
31+
// projection bound <i32 as Z>::S == i32.
32+
fn global_projection() where i32: Z<S = i32> {} //~ ERROR
33+
34+
impl A {
35+
fn new() -> A { A }
36+
}
37+
38+
// Lifetime bounds should be linted as well
39+
fn global_lifetimes() where i32: 'static, &'static str: 'static {}
40+
//~^ ERROR
41+
//~| ERROR
42+
43+
fn local_lifetimes<'a>() where i32: 'a, &'a str: 'a {} // OK
44+
45+
fn global_outlives() where 'static: 'static {} //~ ERROR
46+
47+
// Check that each bound is checked individually
48+
fn mixed_bounds<T: Copy>() where i32: X<T> + Copy {} //~ ERROR
49+
50+
fn main() {}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters
2+
--> $DIR/trivial-bounds-lint.rs:15:1
3+
|
4+
LL | struct A where i32: Copy; //~ ERROR
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
note: lint level defined here
8+
--> $DIR/trivial-bounds-lint.rs:13:9
9+
|
10+
LL | #![deny(trivial_bounds)]
11+
| ^^^^^^^^^^^^^^
12+
13+
error: Trait bound i32: X<()> does not depend on any type or lifetime parameters
14+
--> $DIR/trivial-bounds-lint.rs:28:1
15+
|
16+
LL | fn global_param() where i32: X<()> {} //~ ERROR
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
19+
error: Trait bound i32: Z does not depend on any type or lifetime parameters
20+
--> $DIR/trivial-bounds-lint.rs:32:1
21+
|
22+
LL | fn global_projection() where i32: Z<S = i32> {} //~ ERROR
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24+
25+
error: Lifetime bound i32 : 'static does not depend on any type or lifetime parameters
26+
--> $DIR/trivial-bounds-lint.rs:39:1
27+
|
28+
LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {}
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
31+
error: Lifetime bound &'static str : 'static does not depend on any type or lifetime parameters
32+
--> $DIR/trivial-bounds-lint.rs:39:1
33+
|
34+
LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {}
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
36+
37+
error: Lifetime bound 'static : 'static does not depend on any type or lifetime parameters
38+
--> $DIR/trivial-bounds-lint.rs:45:1
39+
|
40+
LL | fn global_outlives() where 'static: 'static {} //~ ERROR
41+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42+
43+
error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters
44+
--> $DIR/trivial-bounds-lint.rs:48:1
45+
|
46+
LL | fn mixed_bounds<T: Copy>() where i32: X<T> + Copy {} //~ ERROR
47+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
48+
49+
error: aborting due to 7 previous errors
50+

0 commit comments

Comments
 (0)