Add trivial bounds lint
This commit is contained in:
parent
27183a9030
commit
dabb820b00
5 changed files with 177 additions and 0 deletions
|
|
@ -1591,3 +1591,61 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExternCrate {
|
|||
self.0 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Lint for trait and lifetime bounds that don't depend on type parameters
|
||||
/// which either do nothing, or stop the item from being used.
|
||||
pub struct TrivialConstraints;
|
||||
|
||||
declare_lint! {
|
||||
TRIVIAL_BOUNDS,
|
||||
Warn,
|
||||
"these bounds don't depend on an type parameters"
|
||||
}
|
||||
|
||||
impl LintPass for TrivialConstraints {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(TRIVIAL_BOUNDS)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
|
||||
fn check_item(
|
||||
&mut self,
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
item: &'tcx hir::Item,
|
||||
) {
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::Predicate::*;
|
||||
|
||||
|
||||
if cx.tcx.features().trivial_bounds {
|
||||
let def_id = cx.tcx.hir.local_def_id(item.id);
|
||||
let predicates = cx.tcx.predicates_of(def_id);
|
||||
for predicate in &predicates.predicates {
|
||||
let predicate_kind_name = match *predicate {
|
||||
Trait(..) => "Trait",
|
||||
TypeOutlives(..) |
|
||||
RegionOutlives(..) => "Lifetime",
|
||||
|
||||
// Ignore projections, as they can only be global
|
||||
// if the trait bound is global
|
||||
Projection(..) |
|
||||
// Ignore bounds that a user can't type
|
||||
WellFormed(..) |
|
||||
ObjectSafe(..) |
|
||||
ClosureKind(..) |
|
||||
Subtype(..) |
|
||||
ConstEvaluatable(..) => continue,
|
||||
};
|
||||
if !predicate.is_global() {
|
||||
cx.span_lint(
|
||||
TRIVIAL_BOUNDS,
|
||||
item.span,
|
||||
&format!("{} bound {} does not depend on any type \
|
||||
or lifetime parameters", predicate_kind_name, predicate),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||
UnreachablePub,
|
||||
TypeAliasBounds,
|
||||
UnusedBrokenConst,
|
||||
TrivialConstraints,
|
||||
);
|
||||
|
||||
add_builtin_with_new!(sess,
|
||||
|
|
|
|||
18
src/test/ui/feature-gate-trivial_bounds-lint.rs
Normal file
18
src/test/ui/feature-gate-trivial_bounds-lint.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// run-pass
|
||||
|
||||
#![allow(unused)]
|
||||
#![deny(trivial_bounds)] // Ignored without the trivial_bounds feature flag.
|
||||
|
||||
struct A where i32: Copy;
|
||||
|
||||
fn main() {}
|
||||
50
src/test/ui/trivial-bounds-lint.rs
Normal file
50
src/test/ui/trivial-bounds-lint.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(trivial_bounds)]
|
||||
#![allow(unused)]
|
||||
#![deny(trivial_bounds)]
|
||||
|
||||
struct A where i32: Copy; //~ ERROR
|
||||
|
||||
trait X<T: Copy> {}
|
||||
|
||||
trait Y<T>: Copy {}
|
||||
|
||||
trait Z {
|
||||
type S: Copy;
|
||||
}
|
||||
|
||||
// Check only the bound the user writes trigger the lint
|
||||
fn trivial_elaboration<T>() where T: X<i32> + Z<S = i32>, i32: Y<T> {} // OK
|
||||
|
||||
fn global_param() where i32: X<()> {} //~ ERROR
|
||||
|
||||
// Should only error on the trait bound, not the implicit
|
||||
// projection bound <i32 as Z>::S == i32.
|
||||
fn global_projection() where i32: Z<S = i32> {} //~ ERROR
|
||||
|
||||
impl A {
|
||||
fn new() -> A { A }
|
||||
}
|
||||
|
||||
// Lifetime bounds should be linted as well
|
||||
fn global_lifetimes() where i32: 'static, &'static str: 'static {}
|
||||
//~^ ERROR
|
||||
//~| ERROR
|
||||
|
||||
fn local_lifetimes<'a>() where i32: 'a, &'a str: 'a {} // OK
|
||||
|
||||
fn global_outlives() where 'static: 'static {} //~ ERROR
|
||||
|
||||
// Check that each bound is checked individually
|
||||
fn mixed_bounds<T: Copy>() where i32: X<T> + Copy {} //~ ERROR
|
||||
|
||||
fn main() {}
|
||||
50
src/test/ui/trivial-bounds-lint.stderr
Normal file
50
src/test/ui/trivial-bounds-lint.stderr
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters
|
||||
--> $DIR/trivial-bounds-lint.rs:15:1
|
||||
|
|
||||
LL | struct A where i32: Copy; //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/trivial-bounds-lint.rs:13:9
|
||||
|
|
||||
LL | #![deny(trivial_bounds)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: Trait bound i32: X<()> does not depend on any type or lifetime parameters
|
||||
--> $DIR/trivial-bounds-lint.rs:28:1
|
||||
|
|
||||
LL | fn global_param() where i32: X<()> {} //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: Trait bound i32: Z does not depend on any type or lifetime parameters
|
||||
--> $DIR/trivial-bounds-lint.rs:32:1
|
||||
|
|
||||
LL | fn global_projection() where i32: Z<S = i32> {} //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: Lifetime bound i32 : 'static does not depend on any type or lifetime parameters
|
||||
--> $DIR/trivial-bounds-lint.rs:39:1
|
||||
|
|
||||
LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: Lifetime bound &'static str : 'static does not depend on any type or lifetime parameters
|
||||
--> $DIR/trivial-bounds-lint.rs:39:1
|
||||
|
|
||||
LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: Lifetime bound 'static : 'static does not depend on any type or lifetime parameters
|
||||
--> $DIR/trivial-bounds-lint.rs:45:1
|
||||
|
|
||||
LL | fn global_outlives() where 'static: 'static {} //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters
|
||||
--> $DIR/trivial-bounds-lint.rs:48:1
|
||||
|
|
||||
LL | fn mixed_bounds<T: Copy>() where i32: X<T> + Copy {} //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue