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:
commit
448cc578a9
@ -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",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(_) |
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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>,
|
||||
}
|
||||
|
@ -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! (
|
||||
|
@ -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> {
|
||||
}
|
||||
|
@ -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() {
|
||||
|
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() {}
|
78
src/test/ui/feature-gate-trivial_bounds.rs
Normal file
78
src/test/ui/feature-gate-trivial_bounds.rs
Normal 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() {}
|
127
src/test/ui/feature-gate-trivial_bounds.stderr
Normal file
127
src/test/ui/feature-gate-trivial_bounds.stderr
Normal 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`.
|
@ -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
|
||||
|
||||
|
@ -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() {}
|
@ -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`.
|
23
src/test/ui/trivial-bounds-inconsistent-copy-reborrow.rs
Normal file
23
src/test/ui/trivial-bounds-inconsistent-copy-reborrow.rs
Normal 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() {}
|
19
src/test/ui/trivial-bounds-inconsistent-copy-reborrow.stderr
Normal file
19
src/test/ui/trivial-bounds-inconsistent-copy-reborrow.stderr
Normal 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`.
|
43
src/test/ui/trivial-bounds-inconsistent-copy.rs
Normal file
43
src/test/ui/trivial-bounds-inconsistent-copy.rs
Normal 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() {}
|
41
src/test/ui/trivial-bounds-inconsistent-copy.stderr
Normal file
41
src/test/ui/trivial-bounds-inconsistent-copy.stderr
Normal 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 | | }
|
||||
| |_^
|
||||
|
34
src/test/ui/trivial-bounds-inconsistent-sized.rs
Normal file
34
src/test/ui/trivial-bounds-inconsistent-sized.rs
Normal 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() {}
|
24
src/test/ui/trivial-bounds-inconsistent-sized.stderr
Normal file
24
src/test/ui/trivial-bounds-inconsistent-sized.stderr
Normal 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 | | }
|
||||
| |_^
|
||||
|
22
src/test/ui/trivial-bounds-inconsistent-well-formed.rs
Normal file
22
src/test/ui/trivial-bounds-inconsistent-well-formed.rs
Normal 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() {}
|
20
src/test/ui/trivial-bounds-inconsistent-well-formed.stderr
Normal file
20
src/test/ui/trivial-bounds-inconsistent-well-formed.stderr
Normal 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 | | }
|
||||
| |_^
|
||||
|
81
src/test/ui/trivial-bounds-inconsistent.rs
Normal file
81
src/test/ui/trivial-bounds-inconsistent.rs
Normal 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() {}
|
112
src/test/ui/trivial-bounds-inconsistent.stderr
Normal file
112
src/test/ui/trivial-bounds-inconsistent.stderr
Normal 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 | | }
|
||||
| |_^
|
||||
|
22
src/test/ui/trivial-bounds-leak-copy.rs
Normal file
22
src/test/ui/trivial-bounds-leak-copy.rs
Normal 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() {}
|
9
src/test/ui/trivial-bounds-leak-copy.stderr
Normal file
9
src/test/ui/trivial-bounds-leak-copy.stderr
Normal 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`.
|
42
src/test/ui/trivial-bounds-leak.rs
Normal file
42
src/test/ui/trivial-bounds-leak.rs
Normal 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() {}
|
||||
|
47
src/test/ui/trivial-bounds-leak.stderr
Normal file
47
src/test/ui/trivial-bounds-leak.stderr
Normal 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`.
|
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…
x
Reference in New Issue
Block a user