Auto merge of #48557 - matthewjasper:allow-trvial-bounds, r=nikomatsakis

Implement RFC 2056 trivial constraints in where clauses

This is an implementation of the new behaviour for #48214. Tests are mostly updated to show the effects of this. Feature gate hasn't been added yet.

Some things that are worth noting and are maybe not want we want

* `&mut T: Copy` doesn't allow as much as someone might expect because there is often an implicit reborrow.
* ~There isn't a check that a where clause is well-formed any more, so `where Vec<str>: Debug` is now allowed (without a `str: Sized` bound).~

r? @nikomatsakis
This commit is contained in:
bors 2018-05-16 09:03:38 +00:00
commit 448cc578a9
38 changed files with 1083 additions and 64 deletions

View File

@ -1479,6 +1479,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
ObligationCauseCode::ReturnType(_) |
ObligationCauseCode::BlockTailExpression(_) => (),
ObligationCauseCode::TrivialBound => {
err.help("see issue #48214");
if tcx.sess.opts.unstable_features.is_nightly_build() {
err.help("add #![feature(trivial_bounds)] to the \
crate attributes to enable",
);
}
}
}
}

View File

@ -330,7 +330,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
ty::Predicate::Trait(ref data) => {
let trait_obligation = obligation.with(data.clone());
if data.is_global() {
if data.is_global() && !data.has_late_bound_regions() {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
if selcx.infcx().predicate_must_hold(&obligation) {

View File

@ -243,6 +243,9 @@ pub enum ObligationCauseCode<'tcx> {
/// Block implicit return
BlockTailExpression(ast::NodeId),
/// #[feature(trivial_bounds)] is not enabled
TrivialBound,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@ -641,17 +644,8 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let predicates: Vec<_> =
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec())
.filter(|p| !p.is_global()) // (*)
.collect();
// (*) Any predicate like `i32: Trait<u32>` or whatever doesn't
// need to be in the *environment* to be proven, so screen those
// out. This is important for the soundness of inter-fn
// caching. Note though that we should probably check that these
// predicates hold at the point where the environment is
// constructed, but I am not currently doing so out of laziness.
// -nmatsakis
debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
predicates);

View File

@ -305,9 +305,6 @@ enum BuiltinImplConditions<'tcx> {
/// There is no built-in impl. There may be some other
/// candidate (a where-clause or user-defined impl).
None,
/// There is *no* impl for this, builtin or not. Ignore
/// all where-clauses.
Never,
/// It is unknown whether there is an impl.
Ambiguous
}
@ -781,13 +778,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
mut obligation: TraitObligation<'tcx>)
-> Result<EvaluationResult, OverflowError>
{
debug!("evaluate_trait_predicate_recursively({:?})",
obligation);
debug!("evaluate_trait_predicate_recursively({:?})", obligation);
if !self.intercrate.is_some() && obligation.is_global() {
// If a param env is consistent, global obligations do not depend on its particular
// value in order to work, so we can clear out the param env and get better
// caching. (If the current param env is inconsistent, we don't care what happens).
if self.intercrate.is_none() && obligation.is_global()
&& obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst()) {
// If a param env has no global bounds, global obligations do not
// depend on its particular value in order to work, so we can clear
// out the param env and get better caching.
debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation);
obligation.param_env = obligation.param_env.without_caller_bounds();
}
@ -1451,22 +1448,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let sized_conditions = self.sized_conditions(obligation);
self.assemble_builtin_bound_candidates(sized_conditions,
&mut candidates)?;
} else if lang_items.unsize_trait() == Some(def_id) {
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
} else {
if lang_items.clone_trait() == Some(def_id) {
// Same builtin conditions as `Copy`, i.e. every type which has builtin support
// for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone`
// types have builtin support for `Clone`.
let clone_conditions = self.copy_clone_conditions(obligation);
self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
}
} else if lang_items.unsize_trait() == Some(def_id) {
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
} else {
if lang_items.clone_trait() == Some(def_id) {
// Same builtin conditions as `Copy`, i.e. every type which has builtin support
// for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone`
// types have builtin support for `Clone`.
let clone_conditions = self.copy_clone_conditions(obligation);
self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
}
self.assemble_generator_candidates(obligation, &mut candidates)?;
self.assemble_closure_candidates(obligation, &mut candidates)?;
self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
self.assemble_candidates_from_impls(obligation, &mut candidates)?;
self.assemble_candidates_from_object_ty(obligation, &mut candidates);
self.assemble_generator_candidates(obligation, &mut candidates)?;
self.assemble_closure_candidates(obligation, &mut candidates)?;
self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
self.assemble_candidates_from_impls(obligation, &mut candidates)?;
self.assemble_candidates_from_object_ty(obligation, &mut candidates);
}
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
@ -2081,13 +2078,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// BUILTIN BOUNDS
//
// These cover the traits that are built-in to the language
// itself. This includes `Copy` and `Sized` for sure. For the
// moment, it also includes `Send` / `Sync` and a few others, but
// those will hopefully change to library-defined traits in the
// future.
// itself: `Copy`, `Clone` and `Sized`.
// HACK: if this returns an error, selection exits without considering
// other impls.
fn assemble_builtin_bound_candidates<'o>(&mut self,
conditions: BuiltinImplConditions<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>)
@ -2106,14 +2098,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
debug!("assemble_builtin_bound_candidates: ambiguous builtin");
Ok(candidates.ambiguous = true)
}
BuiltinImplConditions::Never => { Err(Unimplemented) }
}
}
fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
-> BuiltinImplConditions<'tcx>
{
use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
use self::BuiltinImplConditions::{Ambiguous, None, Where};
// NOTE: binder moved to (*)
let self_ty = self.infcx.shallow_resolve(
@ -2130,7 +2121,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
Where(ty::Binder::dummy(Vec::new()))
}
ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => Never,
ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => None,
ty::TyTuple(tys) => {
Where(ty::Binder::bind(tys.last().into_iter().cloned().collect()))
@ -2164,7 +2155,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let self_ty = self.infcx.shallow_resolve(
obligation.predicate.skip_binder().self_ty());
use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
use self::BuiltinImplConditions::{Ambiguous, None, Where};
match self_ty.sty {
ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
@ -2182,7 +2173,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) |
ty::TyGenerator(..) | ty::TyGeneratorWitness(..) | ty::TyForeign(..) |
ty::TyRef(_, _, hir::MutMutable) => {
Never
None
}
ty::TyArray(element_ty, _) => {
@ -2202,7 +2193,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
if is_copy_trait || is_clone_trait {
Where(ty::Binder::bind(substs.upvar_tys(def_id, self.tcx()).collect()))
} else {
Never
None
}
}

View File

@ -243,6 +243,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
super::IntrinsicType => Some(super::IntrinsicType),
super::MethodReceiver => Some(super::MethodReceiver),
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
super::TrivialBound => Some(super::TrivialBound),
}
}
}

View File

@ -79,7 +79,7 @@ impl FlagComputation {
}
&ty::TyParam(ref p) => {
self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
if p.is_self() {
self.add_flags(TypeFlags::HAS_SELF);
} else {
@ -89,7 +89,7 @@ impl FlagComputation {
&ty::TyGenerator(_, ref substs, _) => {
self.add_flags(TypeFlags::HAS_TY_CLOSURE);
self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
self.add_substs(&substs.substs);
}
@ -101,12 +101,12 @@ impl FlagComputation {
&ty::TyClosure(_, ref substs) => {
self.add_flags(TypeFlags::HAS_TY_CLOSURE);
self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
self.add_substs(&substs.substs);
}
&ty::TyInfer(infer) => {
self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right?
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right?
self.add_flags(TypeFlags::HAS_TY_INFER);
match infer {
ty::FreshTy(_) |

View File

@ -116,10 +116,14 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
/// Indicates whether this value references only 'global'
/// types/lifetimes that are the same regardless of what fn we are
/// in. This is used for caching. Errs on the side of returning
/// false.
/// in. This is used for caching.
fn is_global(&self) -> bool {
!self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES)
!self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
}
/// True if there are any late-bound regions
fn has_late_bound_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
}
}

View File

@ -441,7 +441,7 @@ bitflags! {
// true if there are "names" of types and regions and so forth
// that are local to a particular fn
const HAS_LOCAL_NAMES = 1 << 10;
const HAS_FREE_LOCAL_NAMES = 1 << 10;
// Present if the type belongs in a local type context.
// Only set for TyInfer other than Fresh.
@ -455,6 +455,10 @@ bitflags! {
// ought to be true only for the results of canonicalization.
const HAS_CANONICAL_VARS = 1 << 13;
/// Does this have any `ReLateBound` regions? Used to check
/// if a global bound is safe to evaluate.
const HAS_RE_LATE_BOUND = 1 << 14;
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_RE_EARLY_BOUND.bits;
@ -472,9 +476,10 @@ bitflags! {
TypeFlags::HAS_TY_ERR.bits |
TypeFlags::HAS_PROJECTION.bits |
TypeFlags::HAS_TY_CLOSURE.bits |
TypeFlags::HAS_LOCAL_NAMES.bits |
TypeFlags::HAS_FREE_LOCAL_NAMES.bits |
TypeFlags::KEEP_IN_LOCAL_TCX.bits |
TypeFlags::HAS_CANONICAL_VARS.bits;
TypeFlags::HAS_CANONICAL_VARS.bits |
TypeFlags::HAS_RE_LATE_BOUND.bits;
}
}

View File

@ -1268,7 +1268,9 @@ impl RegionKind {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_RE_SKOL;
}
ty::ReLateBound(..) => { }
ty::ReLateBound(..) => {
flags = flags | TypeFlags::HAS_RE_LATE_BOUND;
}
ty::ReEarlyBound(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_RE_EARLY_BOUND;
@ -1291,8 +1293,8 @@ impl RegionKind {
}
match *self {
ty::ReStatic | ty::ReEmpty | ty::ReErased => (),
_ => flags = flags | TypeFlags::HAS_LOCAL_NAMES,
ty::ReStatic | ty::ReEmpty | ty::ReErased | ty::ReLateBound(..) => (),
_ => flags = flags | TypeFlags::HAS_FREE_LOCAL_NAMES,
}
debug!("type_flags({:?}) = {:?}", self, flags);

View File

@ -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),
);
}
}
}
}
}

View File

@ -137,6 +137,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
UnreachablePub,
TypeAliasBounds,
UnusedBrokenConst,
TrivialConstraints,
);
add_builtin_with_new!(sess,

View File

@ -47,6 +47,12 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
let param_env = self.param_env;
self.inherited.enter(|inh| {
let fcx = FnCtxt::new(&inh, param_env, id);
if !inh.tcx.features().trivial_bounds {
// As predicates are cached rather than obligations, this
// needsto be called first so that they are checked with an
// empty param_env.
check_false_global_bounds(&fcx, span, id);
}
let wf_tys = f(&fcx, fcx.tcx.global_tcx());
fcx.select_all_obligations_or_error();
fcx.regionck_item(id, span, &wf_tys);
@ -686,6 +692,41 @@ fn reject_shadowing_parameters(tcx: TyCtxt, def_id: DefId) {
}
}
/// Feature gates RFC 2056 - trivial bounds, checking for global bounds that
/// aren't true.
fn check_false_global_bounds<'a, 'gcx, 'tcx>(
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
span: Span,
id: ast::NodeId,
) {
use rustc::ty::TypeFoldable;
let empty_env = ty::ParamEnv::empty();
let def_id = fcx.tcx.hir.local_def_id(id);
let predicates = fcx.tcx.predicates_of(def_id).predicates;
// Check elaborated bounds
let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates);
for pred in implied_obligations {
// Match the existing behavior.
if pred.is_global() && !pred.has_late_bound_regions() {
let obligation = traits::Obligation::new(
traits::ObligationCause::new(
span,
id,
traits::TrivialBound,
),
empty_env,
pred,
);
fcx.register_predicate(obligation);
}
}
fcx.select_all_obligations_or_error();
}
pub struct CheckTypeWellFormedVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
}

View File

@ -463,6 +463,9 @@ declare_features! (
// Allows use of the :literal macro fragment specifier (RFC 1576)
(active, macro_literal_matcher, "1.27.0", Some(35625), None),
// inconsistent bounds in where clauses
(active, trivial_bounds, "1.28.0", Some(48214), None),
);
declare_features! (

View File

@ -11,10 +11,9 @@
// Check that when there are vacuous predicates in the environment
// (which make a fn uncallable) we don't erroneously cache those and
// then consider them satisfied elsewhere. The current technique for
// doing this is just to filter "global" predicates out of the
// environment, which means that we wind up with an error in the
// function `vacuous`, because even though `i32: Bar<u32>` is implied
// by its where clause, that where clause never holds.
// doing this is to not use global caches when there is a chance that
// the environment contains such a predicate.
// We still error for `i32: Bar<u32>` pending #48214
trait Foo<X,Y>: Bar<X> {
}

View File

@ -17,7 +17,7 @@ impl<T, Smoke> Mirror<Smoke> for T {
}
pub fn poison<S>(victim: String) where <String as Mirror<S>>::Image: Copy {
loop { drop(victim); } //~ ERROR use of moved value
loop { drop(victim); }
}
fn main() {

View 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() {}

View File

@ -0,0 +1,78 @@
// 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.
#![allow(unused)]
#![allow(type_alias_bounds)]
pub trait Foo {
fn test(&self);
}
fn generic_function<X: Foo>(x: X) {}
enum E where i32: Foo { V } //~ ERROR
struct S where i32: Foo; //~ ERROR
trait T where i32: Foo {} //~ ERROR
union U where i32: Foo { f: i32 } //~ ERROR
type Y where i32: Foo = (); // OK - bound is ignored
impl Foo for () where i32: Foo { //~ ERROR
fn test(&self) {
3i32.test();
Foo::test(&4i32);
generic_function(5i32);
}
}
fn f() where i32: Foo //~ ERROR
{
let s = S;
3i32.test();
Foo::test(&4i32);
generic_function(5i32);
}
fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> { //~ ERROR
-s
}
fn use_for() where i32: Iterator { //~ ERROR
for _ in 2i32 {}
}
trait A {}
impl A for i32 {}
struct Dst<X: ?Sized> {
x: X,
}
struct TwoStrs(str, str) where str: Sized; //~ ERROR
fn unsized_local() where Dst<A>: Sized { //~ ERROR
let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
}
fn return_str() -> str where str: Sized { //~ ERROR
*"Sized".to_string().into_boxed_str()
}
// This is currently accepted because the function pointer isn't
// considered global.
fn global_hr(x: fn(&())) where fn(&()): Foo { // OK
x.test();
}
fn main() {}

View File

@ -0,0 +1,127 @@
error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:20:1
|
LL | enum E where i32: Foo { V } //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:22:1
|
LL | struct S where i32: Foo; //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:24:1
|
LL | trait T where i32: Foo {} //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:26:1
|
LL | union U where i32: Foo { f: i32 } //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:30:1
|
LL | / impl Foo for () where i32: Foo { //~ ERROR
LL | | fn test(&self) {
LL | | 3i32.test();
LL | | Foo::test(&4i32);
LL | | generic_function(5i32);
LL | | }
LL | | }
| |_^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:38:1
|
LL | / fn f() where i32: Foo //~ ERROR
LL | | {
LL | | let s = S;
LL | | 3i32.test();
LL | | Foo::test(&4i32);
LL | | generic_function(5i32);
LL | | }
| |_^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
error[E0277]: the trait bound `std::string::String: std::ops::Neg` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:46:1
|
LL | / fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> { //~ ERROR
LL | | -s
LL | | }
| |_^ the trait `std::ops::Neg` is not implemented for `std::string::String`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:50:1
|
LL | / fn use_for() where i32: Iterator { //~ ERROR
LL | | for _ in 2i32 {}
LL | | }
| |_^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
|
= help: the trait `std::iter::Iterator` is not implemented for `i32`
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:62:1
|
LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `str` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
error[E0277]: the trait bound `A + 'static: std::marker::Sized` is not satisfied in `Dst<A + 'static>`
--> $DIR/feature-gate-trivial_bounds.rs:64:1
|
LL | / fn unsized_local() where Dst<A>: Sized { //~ ERROR
LL | | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
LL | | }
| |_^ `A + 'static` does not have a constant size known at compile-time
|
= help: within `Dst<A + 'static>`, the trait `std::marker::Sized` is not implemented for `A + 'static`
= note: required because it appears within the type `Dst<A + 'static>`
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:68:1
|
LL | / fn return_str() -> str where str: Sized { //~ ERROR
LL | | *"Sized".to_string().into_boxed_str()
LL | | }
| |_^ `str` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
error: aborting due to 11 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -6,6 +6,8 @@ LL | #[derive(Clone)] //~ ERROR conflicting implementations of trait `std::clone
...
LL | impl<T: Clone + ?Sized> Clone for Node<[T]> {
| ------------------------------------------- first implementation here
|
= note: upstream crates may add new impl of trait `std::clone::Clone` for type `[_]` in future versions
error: aborting due to previous error

View File

@ -0,0 +1,29 @@
// 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
// Inconsistent bounds with trait implementations
#![feature(trivial_bounds)]
#![allow(unused)]
trait A {
fn foo(&self) -> Self where Self: Copy;
}
impl A for str {
fn foo(&self) -> Self where Self: Copy { *"" }
}
impl A for i32 {
fn foo(&self) -> Self { 3 }
}
fn main() {}

View File

@ -0,0 +1,19 @@
error[E0596]: cannot borrow immutable item `**t` as mutable
--> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:16:5
|
LL | *t //~ ERROR
| ^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*t`
error[E0596]: cannot borrow immutable item `**t` as mutable
--> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:20:6
|
LL | {*t} //~ ERROR
| ^^ cannot borrow as mutable
|
= note: the value which is causing this path not to be mutable is...: `*t`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0596`.

View File

@ -0,0 +1,23 @@
// 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.
// Check that reborrows are still illegal with Copy mutable references
#![feature(trivial_bounds)]
#![allow(unused)]
fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
*t //~ ERROR
}
fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
{*t} //~ ERROR
}
fn main() {}

View File

@ -0,0 +1,19 @@
error[E0389]: cannot borrow data mutably in a `&` reference
--> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:16:5
|
LL | fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
| --------------- use `&'a mut &'a mut i32` here to make mutable
LL | *t //~ ERROR
| ^^ assignment into an immutable reference
error[E0389]: cannot borrow data mutably in a `&` reference
--> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:20:6
|
LL | fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
| --------------- use `&'a mut &'a mut i32` here to make mutable
LL | {*t} //~ ERROR
| ^^ assignment into an immutable reference
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0389`.

View File

@ -0,0 +1,43 @@
// 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
// Check tautalogically false `Copy` bounds
#![feature(trivial_bounds)]
#![allow(unused)]
fn copy_string(t: String) -> String where String: Copy {
is_copy(&t);
let x = t;
drop(t);
t
}
fn copy_out_string(t: &String) -> String where String: Copy {
*t
}
fn copy_string_with_param<T>(x: String) where String: Copy {
let y = x;
let z = x;
}
// Check that no reborrowing occurs
fn copy_mut<'a>(t: &&'a mut i32) -> &'a mut i32 where for<'b> &'b mut i32: Copy {
is_copy(t);
let x = *t;
drop(x);
x
}
fn is_copy<T: Copy>(t: &T) {}
fn main() {}

View File

@ -0,0 +1,41 @@
warning: Trait bound std::string::String: std::marker::Copy does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent-copy.rs:16:1
|
LL | / fn copy_string(t: String) -> String where String: Copy {
LL | | is_copy(&t);
LL | | let x = t;
LL | | drop(t);
LL | | t
LL | | }
| |_^
|
= note: #[warn(trivial_bounds)] on by default
warning: Trait bound std::string::String: std::marker::Copy does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent-copy.rs:23:1
|
LL | / fn copy_out_string(t: &String) -> String where String: Copy {
LL | | *t
LL | | }
| |_^
warning: Trait bound std::string::String: std::marker::Copy does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent-copy.rs:27:1
|
LL | / fn copy_string_with_param<T>(x: String) where String: Copy {
LL | | let y = x;
LL | | let z = x;
LL | | }
| |_^
warning: Trait bound for<'b> &'b mut i32: std::marker::Copy does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent-copy.rs:33:1
|
LL | / fn copy_mut<'a>(t: &&'a mut i32) -> &'a mut i32 where for<'b> &'b mut i32: Copy {
LL | | is_copy(t);
LL | | let x = *t;
LL | | drop(x);
LL | | x
LL | | }
| |_^

View File

@ -0,0 +1,34 @@
// 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
// Check tautalogically false `Sized` bounds
#![feature(trivial_bounds)]
#![allow(unused)]
trait A {}
impl A for i32 {}
struct T<X: ?Sized> {
x: X,
}
struct S(str, str) where str: Sized;
fn unsized_local() where for<'a> T<A + 'a>: Sized {
let x: T<A> = *(Box::new(T { x: 1 }) as Box<T<A>>);
}
fn return_str() -> str where str: Sized {
*"Sized".to_string().into_boxed_str()
}
fn main() {}

View File

@ -0,0 +1,24 @@
warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent-sized.rs:24:1
|
LL | struct S(str, str) where str: Sized;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(trivial_bounds)] on by default
warning: Trait bound for<'a> T<A + 'a>: std::marker::Sized does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent-sized.rs:26:1
|
LL | / fn unsized_local() where for<'a> T<A + 'a>: Sized {
LL | | let x: T<A> = *(Box::new(T { x: 1 }) as Box<T<A>>);
LL | | }
| |_^
warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent-sized.rs:30:1
|
LL | / fn return_str() -> str where str: Sized {
LL | | *"Sized".to_string().into_boxed_str()
LL | | }
| |_^

View File

@ -0,0 +1,22 @@
// 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
// Test that inconsistent bounds are used in well-formedness checks
#![feature(trivial_bounds)]
use std::fmt::Debug;
pub fn foo() where Vec<str>: Debug, str: Copy {
let x = vec![*"1"];
println!("{:?}", x);
}
fn main() {}

View File

@ -0,0 +1,20 @@
warning: Trait bound std::vec::Vec<str>: std::fmt::Debug does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent-well-formed.rs:17:1
|
LL | / pub fn foo() where Vec<str>: Debug, str: Copy {
LL | | let x = vec![*"1"];
LL | | println!("{:?}", x);
LL | | }
| |_^
|
= note: #[warn(trivial_bounds)] on by default
warning: Trait bound str: std::marker::Copy does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent-well-formed.rs:17:1
|
LL | / pub fn foo() where Vec<str>: Debug, str: Copy {
LL | | let x = vec![*"1"];
LL | | println!("{:?}", x);
LL | | }
| |_^

View File

@ -0,0 +1,81 @@
// 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
// Check that tautalogically false bounds are accepted, and are used
// in type inference.
#![feature(trivial_bounds)]
#![allow(unused)]
pub trait Foo {
fn test(&self);
}
fn generic_function<X: Foo>(x: X) {}
enum E where i32: Foo { V }
struct S where i32: Foo;
trait T where i32: Foo {}
union U where i32: Foo { f: i32 }
type Y where i32: Foo = ();
impl Foo for () where i32: Foo {
fn test(&self) {
3i32.test();
Foo::test(&4i32);
generic_function(5i32);
}
}
fn f() where i32: Foo {
let s = S;
3i32.test();
Foo::test(&4i32);
generic_function(5i32);
}
fn g() where &'static str: Foo {
"Foo".test();
Foo::test(&"Foo");
generic_function("Foo");
}
trait A {}
impl A for i32 {}
struct Dst<X: ?Sized> {
x: X,
}
struct TwoStrs(str, str) where str: Sized;
fn unsized_local() where for<'a> Dst<A + 'a>: Sized {
let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
}
fn return_str() -> str where str: Sized {
*"Sized".to_string().into_boxed_str()
}
fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> {
-s
}
fn use_for() where i32: Iterator {
for _ in 2i32 {}
}
fn main() {}

View File

@ -0,0 +1,112 @@
warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:24:1
|
LL | enum E where i32: Foo { V }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(trivial_bounds)] on by default
warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:26:1
|
LL | struct S where i32: Foo;
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:28:1
|
LL | trait T where i32: Foo {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:30:1
|
LL | union U where i32: Foo { f: i32 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: where clauses are not enforced in type aliases
--> $DIR/trivial-bounds-inconsistent.rs:32:14
|
LL | type Y where i32: Foo = ();
| ^^^^^^^^
|
= note: #[warn(type_alias_bounds)] on by default
= help: the clause will not be checked when the type alias is used, and should be removed
warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:32:1
|
LL | type Y where i32: Foo = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:34:1
|
LL | / impl Foo for () where i32: Foo {
LL | | fn test(&self) {
LL | | 3i32.test();
LL | | Foo::test(&4i32);
LL | | generic_function(5i32);
LL | | }
LL | | }
| |_^
warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:42:1
|
LL | / fn f() where i32: Foo {
LL | | let s = S;
LL | | 3i32.test();
LL | | Foo::test(&4i32);
LL | | generic_function(5i32);
LL | | }
| |_^
warning: Trait bound &'static str: Foo does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:49:1
|
LL | / fn g() where &'static str: Foo {
LL | | "Foo".test();
LL | | Foo::test(&"Foo");
LL | | generic_function("Foo");
LL | | }
| |_^
warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:63:1
|
LL | struct TwoStrs(str, str) where str: Sized;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: Trait bound for<'a> Dst<A + 'a>: std::marker::Sized does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:65:1
|
LL | / fn unsized_local() where for<'a> Dst<A + 'a>: Sized {
LL | | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
LL | | }
| |_^
warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:69:1
|
LL | / fn return_str() -> str where str: Sized {
LL | | *"Sized".to_string().into_boxed_str()
LL | | }
| |_^
warning: Trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:73:1
|
LL | / fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> {
LL | | -s
LL | | }
| |_^
warning: Trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:77:1
|
LL | / fn use_for() where i32: Iterator {
LL | | for _ in 2i32 {}
LL | | }
| |_^

View File

@ -0,0 +1,22 @@
// 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.
// Check that false Copy bounds don't leak
#![feature(trivial_bounds)]
fn copy_out_string(t: &String) -> String where String: Copy {
*t
}
fn move_out_string(t: &String) -> String {
*t //~ ERROR
}
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0507]: cannot move out of borrowed content
--> $DIR/trivial-bounds-leak-copy.rs:19:5
|
LL | *t //~ ERROR
| ^^ cannot move out of borrowed content
error: aborting due to previous error
For more information about this error, try `rustc --explain E0507`.

View File

@ -0,0 +1,42 @@
// 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.
// Check that false bounds don't leak
#![feature(trivial_bounds)]
pub trait Foo {
fn test(&self);
}
fn return_str() -> str where str: Sized {
*"Sized".to_string().into_boxed_str()
}
fn cant_return_str() -> str { //~ ERROR
*"Sized".to_string().into_boxed_str()
}
fn my_function() where i32: Foo
{
3i32.test();
Foo::test(&4i32);
generic_function(5i32);
}
fn foo() {
3i32.test(); //~ ERROR
Foo::test(&4i32); //~ ERROR
generic_function(5i32); //~ ERROR
}
fn generic_function<T: Foo>(t: T) {}
fn main() {}

View File

@ -0,0 +1,47 @@
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
--> $DIR/trivial-bounds-leak.rs:22:25
|
LL | fn cant_return_str() -> str { //~ ERROR
| ^^^ `str` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= note: the return type of a function must have a statically known size
error[E0599]: no method named `test` found for type `i32` in the current scope
--> $DIR/trivial-bounds-leak.rs:34:10
|
LL | 3i32.test(); //~ ERROR
| ^^^^
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `test`, perhaps you need to implement it:
candidate #1: `Foo`
error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/trivial-bounds-leak.rs:35:5
|
LL | Foo::test(&4i32); //~ ERROR
| ^^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
note: required by `Foo::test`
--> $DIR/trivial-bounds-leak.rs:15:5
|
LL | fn test(&self);
| ^^^^^^^^^^^^^^^
error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/trivial-bounds-leak.rs:36:5
|
LL | generic_function(5i32); //~ ERROR
| ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
note: required by `generic_function`
--> $DIR/trivial-bounds-leak.rs:39:1
|
LL | fn generic_function<T: Foo>(t: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors
Some errors occurred: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.

View 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() {}

View 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