Auto merge of #48326 - RalfJung:generic-bounds, r=petrochenkov
Warn about ignored generic bounds in `for` This adds a new lint to fix #42181. For consistency and to avoid code duplication, I also moved the existing "bounds in type aliases are ignored" here. Questions to the reviewer: * Is it okay to just remove a diagnostic error code like this? Should I instead keep the warning about type aliases where it is? The old code provided a detailed explanation of what's going on when asked, that information is now lost. On the other hand, `span_warn!` seems deprecated (after this patch, it has exactly one user left!). * Did I miss any syntactic construct that can appear as `for` in the surface syntax? I covered function types (`for<'a> fn(...)`), generic traits (`for <'a> Fn(...)`, can appear both as bounds as as trait objects) and bounds (`for<'a> F: ...`). * For the sake of backwards compatibility, this adds a warning, not an error. @nikomatsakis suggested an error in https://github.com/rust-lang/rust/issues/42181#issuecomment-306924389, but I feel that can only happen in a new epoch -- right? Cc @eddyb
This commit is contained in:
commit
fedce67cd2
20 changed files with 325 additions and 109 deletions
|
@ -824,6 +824,17 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
|
||||||
hir_visit::walk_generics(self, g);
|
hir_visit::walk_generics(self, g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate) {
|
||||||
|
run_lints!(self, check_where_predicate, late_passes, p);
|
||||||
|
hir_visit::walk_where_predicate(self, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef,
|
||||||
|
m: hir::TraitBoundModifier) {
|
||||||
|
run_lints!(self, check_poly_trait_ref, late_passes, t, m);
|
||||||
|
hir_visit::walk_poly_trait_ref(self, t, m);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
|
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
|
||||||
let generics = self.generics.take();
|
let generics = self.generics.take();
|
||||||
self.generics = Some(&trait_item.generics);
|
self.generics = Some(&trait_item.generics);
|
||||||
|
@ -986,6 +997,16 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
|
||||||
ast_visit::walk_generics(self, g);
|
ast_visit::walk_generics(self, g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) {
|
||||||
|
run_lints!(self, check_where_predicate, early_passes, p);
|
||||||
|
ast_visit::walk_where_predicate(self, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef, m: &'a ast::TraitBoundModifier) {
|
||||||
|
run_lints!(self, check_poly_trait_ref, early_passes, t, m);
|
||||||
|
ast_visit::walk_poly_trait_ref(self, t, m);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) {
|
fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) {
|
||||||
self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
|
self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
|
||||||
run_lints!(cx, check_trait_item, early_passes, trait_item);
|
run_lints!(cx, check_trait_item, early_passes, trait_item);
|
||||||
|
|
|
@ -181,6 +181,9 @@ pub trait LateLintPass<'a, 'tcx>: LintPass {
|
||||||
fn check_ty(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Ty) { }
|
fn check_ty(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Ty) { }
|
||||||
fn check_generic_param(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::GenericParam) { }
|
fn check_generic_param(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::GenericParam) { }
|
||||||
fn check_generics(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Generics) { }
|
fn check_generics(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Generics) { }
|
||||||
|
fn check_where_predicate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::WherePredicate) { }
|
||||||
|
fn check_poly_trait_ref(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::PolyTraitRef,
|
||||||
|
_: hir::TraitBoundModifier) { }
|
||||||
fn check_fn(&mut self,
|
fn check_fn(&mut self,
|
||||||
_: &LateContext<'a, 'tcx>,
|
_: &LateContext<'a, 'tcx>,
|
||||||
_: FnKind<'tcx>,
|
_: FnKind<'tcx>,
|
||||||
|
@ -253,6 +256,9 @@ pub trait EarlyLintPass: LintPass {
|
||||||
fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { }
|
fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { }
|
||||||
fn check_generic_param(&mut self, _: &EarlyContext, _: &ast::GenericParam) { }
|
fn check_generic_param(&mut self, _: &EarlyContext, _: &ast::GenericParam) { }
|
||||||
fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { }
|
fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { }
|
||||||
|
fn check_where_predicate(&mut self, _: &EarlyContext, _: &ast::WherePredicate) { }
|
||||||
|
fn check_poly_trait_ref(&mut self, _: &EarlyContext, _: &ast::PolyTraitRef,
|
||||||
|
_: &ast::TraitBoundModifier) { }
|
||||||
fn check_fn(&mut self, _: &EarlyContext,
|
fn check_fn(&mut self, _: &EarlyContext,
|
||||||
_: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { }
|
_: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { }
|
||||||
fn check_fn_post(&mut self, _: &EarlyContext,
|
fn check_fn_post(&mut self, _: &EarlyContext,
|
||||||
|
|
|
@ -1315,3 +1315,50 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub {
|
||||||
self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false);
|
self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lint for trait and lifetime bounds that are (accidentally) accepted by the parser, but
|
||||||
|
/// ignored later.
|
||||||
|
|
||||||
|
pub struct IgnoredGenericBounds;
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
IGNORED_GENERIC_BOUNDS,
|
||||||
|
Warn,
|
||||||
|
"these generic bounds are ignored"
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LintPass for IgnoredGenericBounds {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(IGNORED_GENERIC_BOUNDS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EarlyLintPass for IgnoredGenericBounds {
|
||||||
|
fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) {
|
||||||
|
let type_alias_generics = match item.node {
|
||||||
|
ast::ItemKind::Ty(_, ref generics) => generics,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
// There must not be a where clause
|
||||||
|
if !type_alias_generics.where_clause.predicates.is_empty() {
|
||||||
|
let spans : Vec<_> = type_alias_generics.where_clause.predicates.iter()
|
||||||
|
.map(|pred| pred.span()).collect();
|
||||||
|
cx.span_lint(IGNORED_GENERIC_BOUNDS, spans,
|
||||||
|
"where clauses are ignored in type aliases");
|
||||||
|
}
|
||||||
|
// The parameters must not have bounds
|
||||||
|
for param in type_alias_generics.params.iter() {
|
||||||
|
let spans : Vec<_> = match param {
|
||||||
|
&ast::GenericParam::Lifetime(ref l) => l.bounds.iter().map(|b| b.span).collect(),
|
||||||
|
&ast::GenericParam::Type(ref ty) => ty.bounds.iter().map(|b| b.span()).collect(),
|
||||||
|
};
|
||||||
|
if !spans.is_empty() {
|
||||||
|
cx.span_lint(
|
||||||
|
IGNORED_GENERIC_BOUNDS,
|
||||||
|
spans,
|
||||||
|
"bounds on generic parameters are ignored in type aliases",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -109,6 +109,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||||
UnusedImportBraces,
|
UnusedImportBraces,
|
||||||
AnonymousParameters,
|
AnonymousParameters,
|
||||||
UnusedDocComment,
|
UnusedDocComment,
|
||||||
|
IgnoredGenericBounds,
|
||||||
);
|
);
|
||||||
|
|
||||||
add_early_builtin_with_new!(sess,
|
add_early_builtin_with_new!(sess,
|
||||||
|
|
|
@ -136,6 +136,33 @@ impl<'a> AstValidator<'a> {
|
||||||
in patterns")
|
in patterns")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_late_bound_lifetime_defs(&self, params: &Vec<GenericParam>) {
|
||||||
|
// Check: Only lifetime parameters
|
||||||
|
let non_lifetime_param_spans : Vec<_> = params.iter()
|
||||||
|
.filter_map(|param| match *param {
|
||||||
|
GenericParam::Lifetime(_) => None,
|
||||||
|
GenericParam::Type(ref t) => Some(t.span),
|
||||||
|
}).collect();
|
||||||
|
if !non_lifetime_param_spans.is_empty() {
|
||||||
|
self.err_handler().span_err(non_lifetime_param_spans,
|
||||||
|
"only lifetime parameters can be used in this context");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check: No bounds on lifetime parameters
|
||||||
|
for param in params.iter() {
|
||||||
|
match *param {
|
||||||
|
GenericParam::Lifetime(ref l) => {
|
||||||
|
if !l.bounds.is_empty() {
|
||||||
|
let spans : Vec<_> = l.bounds.iter().map(|b| b.span).collect();
|
||||||
|
self.err_handler().span_err(spans,
|
||||||
|
"lifetime bounds cannot be used in this context");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GenericParam::Type(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for AstValidator<'a> {
|
impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
|
@ -157,6 +184,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
struct_span_err!(self.session, span, E0561,
|
struct_span_err!(self.session, span, E0561,
|
||||||
"patterns aren't allowed in function pointer types").emit();
|
"patterns aren't allowed in function pointer types").emit();
|
||||||
});
|
});
|
||||||
|
self.check_late_bound_lifetime_defs(&bfty.generic_params);
|
||||||
}
|
}
|
||||||
TyKind::TraitObject(ref bounds, ..) => {
|
TyKind::TraitObject(ref bounds, ..) => {
|
||||||
let mut any_lifetime_bounds = false;
|
let mut any_lifetime_bounds = false;
|
||||||
|
@ -417,6 +445,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
|
|
||||||
visit::walk_pat(self, pat)
|
visit::walk_pat(self, pat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
|
||||||
|
if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
|
||||||
|
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
|
||||||
|
self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
|
||||||
|
}
|
||||||
|
visit::walk_where_predicate(self, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
|
||||||
|
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
|
||||||
|
visit::walk_poly_trait_ref(self, t, m);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`.
|
// Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`.
|
||||||
|
|
|
@ -356,39 +356,6 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_no_param_bounds(tcx: TyCtxt,
|
|
||||||
span: Span,
|
|
||||||
generics: &hir::Generics,
|
|
||||||
thing: &'static str) {
|
|
||||||
let mut warn = false;
|
|
||||||
|
|
||||||
for ty_param in generics.ty_params() {
|
|
||||||
if !ty_param.bounds.is_empty() {
|
|
||||||
warn = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for lft_param in generics.lifetimes() {
|
|
||||||
if !lft_param.bounds.is_empty() {
|
|
||||||
warn = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !generics.where_clause.predicates.is_empty() {
|
|
||||||
warn = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if warn {
|
|
||||||
// According to accepted RFC #XXX, we should
|
|
||||||
// eventually accept these, but it will not be
|
|
||||||
// part of this PR. Still, convert to warning to
|
|
||||||
// make bootstrapping easier.
|
|
||||||
span_warn!(tcx.sess, span, E0122,
|
|
||||||
"generic bounds are ignored in {}",
|
|
||||||
thing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) {
|
fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) {
|
||||||
let it = tcx.hir.expect_item(item_id);
|
let it = tcx.hir.expect_item(item_id);
|
||||||
debug!("convert: item {} with id {}", it.name, it.id);
|
debug!("convert: item {} with id {}", it.name, it.id);
|
||||||
|
@ -449,13 +416,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) {
|
||||||
convert_variant_ctor(tcx, struct_def.id());
|
convert_variant_ctor(tcx, struct_def.id());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hir::ItemTy(_, ref generics) => {
|
hir::ItemTy(..) | hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => {
|
||||||
ensure_no_param_bounds(tcx, it.span, generics, "type aliases");
|
|
||||||
tcx.generics_of(def_id);
|
|
||||||
tcx.type_of(def_id);
|
|
||||||
tcx.predicates_of(def_id);
|
|
||||||
}
|
|
||||||
hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => {
|
|
||||||
tcx.generics_of(def_id);
|
tcx.generics_of(def_id);
|
||||||
tcx.type_of(def_id);
|
tcx.type_of(def_id);
|
||||||
tcx.predicates_of(def_id);
|
tcx.predicates_of(def_id);
|
||||||
|
|
|
@ -1489,26 +1489,6 @@ static BAR: _ = "test"; // error, explicitly write out the type instead
|
||||||
```
|
```
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
E0122: r##"
|
|
||||||
An attempt was made to add a generic constraint to a type alias. This constraint
|
|
||||||
is entirely ignored. For backwards compatibility, Rust still allows this with a
|
|
||||||
warning. Consider the example below:
|
|
||||||
|
|
||||||
```
|
|
||||||
trait Foo{}
|
|
||||||
|
|
||||||
type MyType<R: Foo> = (R, ());
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let t: MyType<u32>;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
We're able to declare a variable of type `MyType<u32>`, despite the fact that
|
|
||||||
`u32` does not implement `Foo`. As a result, one should avoid using generic
|
|
||||||
constraints in concert with type aliases.
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0124: r##"
|
E0124: r##"
|
||||||
You declared two fields of a struct with the same name. Erroneous code
|
You declared two fields of a struct with the same name. Erroneous code
|
||||||
example:
|
example:
|
||||||
|
@ -4815,6 +4795,7 @@ register_diagnostics! {
|
||||||
// E0086,
|
// E0086,
|
||||||
// E0103,
|
// E0103,
|
||||||
// E0104,
|
// E0104,
|
||||||
|
// E0122, // bounds in type aliases are ignored, turned into proper lint
|
||||||
// E0123,
|
// E0123,
|
||||||
// E0127,
|
// E0127,
|
||||||
// E0129,
|
// E0129,
|
||||||
|
|
|
@ -294,6 +294,15 @@ pub enum TyParamBound {
|
||||||
RegionTyParamBound(Lifetime)
|
RegionTyParamBound(Lifetime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TyParamBound {
|
||||||
|
pub fn span(&self) -> Span {
|
||||||
|
match self {
|
||||||
|
&TraitTyParamBound(ref t, ..) => t.span,
|
||||||
|
&RegionTyParamBound(ref l) => l.span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A modifier on a bound, currently this is only used for `?Sized`, where the
|
/// A modifier on a bound, currently this is only used for `?Sized`, where the
|
||||||
/// modifier is `Maybe`. Negative bounds should also be handled here.
|
/// modifier is `Maybe`. Negative bounds should also be handled here.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||||
|
@ -404,6 +413,16 @@ pub enum WherePredicate {
|
||||||
EqPredicate(WhereEqPredicate),
|
EqPredicate(WhereEqPredicate),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WherePredicate {
|
||||||
|
pub fn span(&self) -> Span {
|
||||||
|
match self {
|
||||||
|
&WherePredicate::BoundPredicate(ref p) => p.span,
|
||||||
|
&WherePredicate::RegionPredicate(ref p) => p.span,
|
||||||
|
&WherePredicate::EqPredicate(ref p) => p.span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A type bound.
|
/// A type bound.
|
||||||
///
|
///
|
||||||
/// E.g. `for<'c> Foo: Send+Clone+'c`
|
/// E.g. `for<'c> Foo: Send+Clone+'c`
|
||||||
|
|
|
@ -4951,6 +4951,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
// FIXME: Decide what should be used here, `=` or `==`.
|
// FIXME: Decide what should be used here, `=` or `==`.
|
||||||
|
// FIXME: We are just dropping the binders in lifetime_defs on the floor here.
|
||||||
} else if self.eat(&token::Eq) || self.eat(&token::EqEq) {
|
} else if self.eat(&token::Eq) || self.eat(&token::EqEq) {
|
||||||
let rhs_ty = self.parse_ty()?;
|
let rhs_ty = self.parse_ty()?;
|
||||||
where_clause.predicates.push(ast::WherePredicate::EqPredicate(
|
where_clause.predicates.push(ast::WherePredicate::EqPredicate(
|
||||||
|
@ -5608,18 +5609,8 @@ impl<'a> Parser<'a> {
|
||||||
self.expect_lt()?;
|
self.expect_lt()?;
|
||||||
let params = self.parse_generic_params()?;
|
let params = self.parse_generic_params()?;
|
||||||
self.expect_gt()?;
|
self.expect_gt()?;
|
||||||
|
// We rely on AST validation to rule out invalid cases: There must not be type
|
||||||
let first_non_lifetime_param_span = params.iter()
|
// parameters, and the lifetime parameters must not have bounds.
|
||||||
.filter_map(|param| match *param {
|
|
||||||
ast::GenericParam::Lifetime(_) => None,
|
|
||||||
ast::GenericParam::Type(ref t) => Some(t.span),
|
|
||||||
})
|
|
||||||
.next();
|
|
||||||
|
|
||||||
if let Some(span) = first_non_lifetime_param_span {
|
|
||||||
self.span_err(span, "only lifetime parameters can be used in this context");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(params)
|
Ok(params)
|
||||||
} else {
|
} else {
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
type Foo<T: std::ops::Add> = T; //~ WARNING E0122
|
type A = for<'b, 'a: 'b> fn(); //~ ERROR lifetime bounds cannot be used in this context
|
||||||
|
type B = for<'b, 'a: 'b,> fn(); //~ ERROR lifetime bounds cannot be used in this context
|
||||||
|
type C = for<'b, 'a: 'b +> fn(); //~ ERROR lifetime bounds cannot be used in this context
|
||||||
|
type D = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context
|
||||||
|
type E = for<T> Fn(); //~ ERROR only lifetime parameters can be used in this context
|
||||||
|
|
||||||
type Bar<T> where T: std::ops::Add = T; //~ WARNING E0122
|
fn main() {}
|
|
@ -12,8 +12,7 @@
|
||||||
|
|
||||||
#![feature(unsized_tuple_coercion)]
|
#![feature(unsized_tuple_coercion)]
|
||||||
|
|
||||||
type Fat<T: ?Sized> = (isize, &'static str, T);
|
type Fat<T> = (isize, &'static str, T);
|
||||||
//~^ WARNING bounds are ignored
|
|
||||||
|
|
||||||
#[derive(PartialEq,Eq)]
|
#[derive(PartialEq,Eq)]
|
||||||
struct Bar;
|
struct Bar;
|
||||||
|
|
|
@ -10,5 +10,5 @@
|
||||||
|
|
||||||
trait Tr {}
|
trait Tr {}
|
||||||
type Huh<T> where T: Tr = isize; //~ ERROR type parameter `T` is unused
|
type Huh<T> where T: Tr = isize; //~ ERROR type parameter `T` is unused
|
||||||
//~| WARNING E0122
|
//~| WARNING where clauses are ignored in type aliases
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
pub enum Expr<'var, VAR> {
|
pub enum Expr<'var, VAR> {
|
||||||
Let(Box<Expr<'var, VAR>>,
|
Let(Box<Expr<'var, VAR>>,
|
||||||
Box<for<'v: 'var> Fn(Expr<'v, VAR>) -> Expr<'v, VAR> + 'var>)
|
Box<for<'v> Fn(Expr<'v, VAR>) -> Expr<'v, VAR> + 'var>)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add<'var, VAR>
|
pub fn add<'var, VAR>
|
||||||
|
@ -18,7 +18,7 @@ pub fn add<'var, VAR>
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn let_<'var, VAR, F: for<'v: 'var> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>>
|
pub fn let_<'var, VAR, F: for<'v> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>>
|
||||||
(a: Expr<'var, VAR>, b: F) -> Expr<'var, VAR> {
|
(a: Expr<'var, VAR>, b: F) -> Expr<'var, VAR> {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ mod traits {
|
||||||
pub trait PubTr {}
|
pub trait PubTr {}
|
||||||
|
|
||||||
pub type Alias<T: PrivTr> = T; //~ ERROR private trait `traits::PrivTr` in public interface
|
pub type Alias<T: PrivTr> = T; //~ ERROR private trait `traits::PrivTr` in public interface
|
||||||
//~^ WARN bounds are ignored in type aliases
|
//~^ WARNING bounds on generic parameters are ignored
|
||||||
//~| WARNING hard error
|
//~| WARNING hard error
|
||||||
pub trait Tr1: PrivTr {} //~ ERROR private trait `traits::PrivTr` in public interface
|
pub trait Tr1: PrivTr {} //~ ERROR private trait `traits::PrivTr` in public interface
|
||||||
//~^ WARNING hard error
|
//~^ WARNING hard error
|
||||||
|
@ -85,7 +85,7 @@ mod traits_where {
|
||||||
pub type Alias<T> where T: PrivTr = T;
|
pub type Alias<T> where T: PrivTr = T;
|
||||||
//~^ ERROR private trait `traits_where::PrivTr` in public interface
|
//~^ ERROR private trait `traits_where::PrivTr` in public interface
|
||||||
//~| WARNING hard error
|
//~| WARNING hard error
|
||||||
//~| WARNING E0122
|
//~| WARNING where clauses are ignored in type aliases
|
||||||
pub trait Tr2<T> where T: PrivTr {}
|
pub trait Tr2<T> where T: PrivTr {}
|
||||||
//~^ ERROR private trait `traits_where::PrivTr` in public interface
|
//~^ ERROR private trait `traits_where::PrivTr` in public interface
|
||||||
//~| WARNING hard error
|
//~| WARNING hard error
|
||||||
|
|
|
@ -22,7 +22,7 @@ static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 =
|
||||||
struct SomeStruct<'x, 'y, 'z: 'x> {
|
struct SomeStruct<'x, 'y, 'z: 'x> {
|
||||||
foo: &'x Foo<'z>,
|
foo: &'x Foo<'z>,
|
||||||
bar: &'x Bar<'z>,
|
bar: &'x Bar<'z>,
|
||||||
f: &'y for<'a, 'b: 'a> Fn(&'a Foo<'b>) -> &'a Bar<'b>,
|
f: &'y for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Bar<'b>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id<T>(t: T) -> T {
|
fn id<T>(t: T) -> T {
|
||||||
|
|
|
@ -8,17 +8,16 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only -Z continue-parse-after-error
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
type A = for<'a: 'b + 'c> fn(); // OK
|
|
||||||
type A = for<'a: 'b,> fn(); // OK
|
|
||||||
type A = for<'a:> fn(); // OK
|
type A = for<'a:> fn(); // OK
|
||||||
type A = for<'a:,> fn(); // OK
|
type A = for<'a:,> fn(); // OK
|
||||||
type A = for<'a> fn(); // OK
|
type A = for<'a> fn(); // OK
|
||||||
type A = for<> fn(); // OK
|
type A = for<> fn(); // OK
|
||||||
type A = for<'a: 'b +> fn(); // OK
|
type A = for<'a: 'b + 'c> fn(); // OK (rejected later by ast_validation)
|
||||||
|
type A = for<'a: 'b,> fn(); // OK(rejected later by ast_validation)
|
||||||
type A = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context
|
type A = for<'a: 'b +> fn(); // OK (rejected later by ast_validation)
|
||||||
|
type A = for<'a, T> fn(); // OK (rejected later by ast_validation)
|
||||||
type A = for<,> fn(); //~ ERROR expected one of `>`, identifier, or lifetime, found `,`
|
type A = for<,> fn(); //~ ERROR expected one of `>`, identifier, or lifetime, found `,`
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -15,7 +15,7 @@ struct S<
|
||||||
T: Tr + 'a, // OK
|
T: Tr + 'a, // OK
|
||||||
T: 'a, // OK
|
T: 'a, // OK
|
||||||
T:, // OK
|
T:, // OK
|
||||||
T: ?for<'a: 'b + 'c> Trait, // OK
|
T: ?for<'a> Trait, // OK
|
||||||
T: Tr +, // OK
|
T: Tr +, // OK
|
||||||
T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds
|
T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds
|
||||||
>;
|
>;
|
||||||
|
|
|
@ -69,8 +69,8 @@ fn foo(x: &impl Debug) -> &impl Debug { x }
|
||||||
fn foo_explicit_lifetime<'a>(x: &'a impl Debug) -> &'a impl Debug { x }
|
fn foo_explicit_lifetime<'a>(x: &'a impl Debug) -> &'a impl Debug { x }
|
||||||
fn foo_explicit_arg<T: Debug>(x: &T) -> &impl Debug { x }
|
fn foo_explicit_arg<T: Debug>(x: &T) -> &impl Debug { x }
|
||||||
|
|
||||||
fn mixed_lifetimes<'a>() -> impl for<'b: 'a> Fn(&'b u32) { |_| () }
|
fn mixed_lifetimes<'a>() -> impl for<'b> Fn(&'b &'a u32) { |_| () }
|
||||||
fn mixed_as_static() -> impl Fn(&'static u32) { mixed_lifetimes() }
|
fn mixed_as_static() -> impl Fn(&'static &'static u32) { mixed_lifetimes() }
|
||||||
|
|
||||||
trait MultiRegionTrait<'a, 'b>: Debug {}
|
trait MultiRegionTrait<'a, 'b>: Debug {}
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,18 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// must-compile-successfully
|
#![allow(dead_code, non_camel_case_types)]
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
type SVec<T: Send> = Vec<T>;
|
type SVec<T: Send+Send> = Vec<T>;
|
||||||
type VVec<'b, 'a: 'b> = Vec<&'a i32>;
|
//~^ WARN bounds on generic parameters are ignored in type aliases
|
||||||
type WVec<'b, T: 'b> = Vec<T>;
|
type VVec<'b, 'a: 'b+'b> = Vec<&'a i32>;
|
||||||
|
//~^ WARN bounds on generic parameters are ignored in type aliases
|
||||||
|
type WVec<'b, T: 'b+'b> = Vec<T>;
|
||||||
|
//~^ WARN bounds on generic parameters are ignored in type aliases
|
||||||
|
type W2Vec<'b, T> where T: 'b, T: 'b = Vec<T>;
|
||||||
|
//~^ WARN where clauses are ignored in type aliases
|
||||||
|
|
||||||
fn foo<'a>(y: &'a i32) {
|
fn foo<'a>(y: &'a i32) {
|
||||||
// If the bounds above would matter, the code below would be rejected.
|
// If the bounds above would matter, the code below would be rejected.
|
||||||
|
@ -26,8 +31,73 @@ fn foo<'a>(y: &'a i32) {
|
||||||
|
|
||||||
let mut x : WVec<'static, & 'a i32> = Vec::new();
|
let mut x : WVec<'static, & 'a i32> = Vec::new();
|
||||||
x.push(y);
|
x.push(y);
|
||||||
|
|
||||||
|
let mut x : W2Vec<'static, & 'a i32> = Vec::new();
|
||||||
|
x.push(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn bar1<'a, 'b>(
|
||||||
foo(&42);
|
x: &'a i32,
|
||||||
|
y: &'b i32,
|
||||||
|
f: for<'xa, 'xb: 'xa+'xa> fn(&'xa i32, &'xb i32) -> &'xa i32)
|
||||||
|
//~^ ERROR lifetime bounds cannot be used in this context
|
||||||
|
{
|
||||||
|
// If the bound in f's type would matter, the call below would (have to)
|
||||||
|
// be rejected.
|
||||||
|
f(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar2<'a, 'b, F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>(
|
||||||
|
//~^ ERROR lifetime bounds cannot be used in this context
|
||||||
|
x: &'a i32,
|
||||||
|
y: &'b i32,
|
||||||
|
f: F)
|
||||||
|
{
|
||||||
|
// If the bound in f's type would matter, the call below would (have to)
|
||||||
|
// be rejected.
|
||||||
|
f(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar3<'a, 'b, F>(
|
||||||
|
x: &'a i32,
|
||||||
|
y: &'b i32,
|
||||||
|
f: F)
|
||||||
|
where F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32
|
||||||
|
//~^ ERROR lifetime bounds cannot be used in this context
|
||||||
|
{
|
||||||
|
// If the bound in f's type would matter, the call below would (have to)
|
||||||
|
// be rejected.
|
||||||
|
f(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar4<'a, 'b, F>(
|
||||||
|
x: &'a i32,
|
||||||
|
y: &'b i32,
|
||||||
|
f: F)
|
||||||
|
where for<'xa, 'xb: 'xa> F: Fn(&'xa i32, &'xb i32) -> &'xa i32
|
||||||
|
//~^ ERROR lifetime bounds cannot be used in this context
|
||||||
|
{
|
||||||
|
// If the bound in f's type would matter, the call below would (have to)
|
||||||
|
// be rejected.
|
||||||
|
f(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S1<F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>(F);
|
||||||
|
//~^ ERROR lifetime bounds cannot be used in this context
|
||||||
|
struct S2<F>(F) where F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32;
|
||||||
|
//~^ ERROR lifetime bounds cannot be used in this context
|
||||||
|
struct S3<F>(F) where for<'xa, 'xb: 'xa> F: Fn(&'xa i32, &'xb i32) -> &'xa i32;
|
||||||
|
//~^ ERROR lifetime bounds cannot be used in this context
|
||||||
|
|
||||||
|
struct S_fnty(for<'xa, 'xb: 'xa> fn(&'xa i32, &'xb i32) -> &'xa i32);
|
||||||
|
//~^ ERROR lifetime bounds cannot be used in this context
|
||||||
|
|
||||||
|
type T1 = Box<for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>;
|
||||||
|
//~^ ERROR lifetime bounds cannot be used in this context
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ : Option<for<'xa, 'xb: 'xa> fn(&'xa i32, &'xb i32) -> &'xa i32> = None;
|
||||||
|
//~^ ERROR lifetime bounds cannot be used in this context
|
||||||
|
let _ : Option<Box<for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>> = None;
|
||||||
|
//~^ ERROR lifetime bounds cannot be used in this context
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,94 @@
|
||||||
warning[E0122]: generic bounds are ignored in type aliases
|
error: lifetime bounds cannot be used in this context
|
||||||
--> $DIR/param-bounds-ignored.rs:15:1
|
--> $DIR/param-bounds-ignored.rs:42:22
|
||||||
|
|
|
|
||||||
LL | type SVec<T: Send> = Vec<T>;
|
LL | f: for<'xa, 'xb: 'xa+'xa> fn(&'xa i32, &'xb i32) -> &'xa i32)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^ ^^^
|
||||||
|
|
||||||
warning[E0122]: generic bounds are ignored in type aliases
|
error: lifetime bounds cannot be used in this context
|
||||||
--> $DIR/param-bounds-ignored.rs:16:1
|
--> $DIR/param-bounds-ignored.rs:50:34
|
||||||
|
|
|
|
||||||
LL | type VVec<'b, 'a: 'b> = Vec<&'a i32>;
|
LL | fn bar2<'a, 'b, F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>(
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^
|
||||||
|
|
||||||
warning[E0122]: generic bounds are ignored in type aliases
|
error: lifetime bounds cannot be used in this context
|
||||||
--> $DIR/param-bounds-ignored.rs:17:1
|
--> $DIR/param-bounds-ignored.rs:65:28
|
||||||
|
|
|
|
||||||
LL | type WVec<'b, T: 'b> = Vec<T>;
|
LL | where F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^
|
||||||
|
|
||||||
|
error: lifetime bounds cannot be used in this context
|
||||||
|
--> $DIR/param-bounds-ignored.rs:77:25
|
||||||
|
|
|
||||||
|
LL | where for<'xa, 'xb: 'xa> F: Fn(&'xa i32, &'xb i32) -> &'xa i32
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: lifetime bounds cannot be used in this context
|
||||||
|
--> $DIR/param-bounds-ignored.rs:85:28
|
||||||
|
|
|
||||||
|
LL | struct S1<F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>(F);
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: lifetime bounds cannot be used in this context
|
||||||
|
--> $DIR/param-bounds-ignored.rs:87:40
|
||||||
|
|
|
||||||
|
LL | struct S2<F>(F) where F: for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32;
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: lifetime bounds cannot be used in this context
|
||||||
|
--> $DIR/param-bounds-ignored.rs:89:37
|
||||||
|
|
|
||||||
|
LL | struct S3<F>(F) where for<'xa, 'xb: 'xa> F: Fn(&'xa i32, &'xb i32) -> &'xa i32;
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: lifetime bounds cannot be used in this context
|
||||||
|
--> $DIR/param-bounds-ignored.rs:92:29
|
||||||
|
|
|
||||||
|
LL | struct S_fnty(for<'xa, 'xb: 'xa> fn(&'xa i32, &'xb i32) -> &'xa i32);
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: lifetime bounds cannot be used in this context
|
||||||
|
--> $DIR/param-bounds-ignored.rs:95:29
|
||||||
|
|
|
||||||
|
LL | type T1 = Box<for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>;
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: lifetime bounds cannot be used in this context
|
||||||
|
--> $DIR/param-bounds-ignored.rs:99:34
|
||||||
|
|
|
||||||
|
LL | let _ : Option<for<'xa, 'xb: 'xa> fn(&'xa i32, &'xb i32) -> &'xa i32> = None;
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: lifetime bounds cannot be used in this context
|
||||||
|
--> $DIR/param-bounds-ignored.rs:101:38
|
||||||
|
|
|
||||||
|
LL | let _ : Option<Box<for<'xa, 'xb: 'xa> Fn(&'xa i32, &'xb i32) -> &'xa i32>> = None;
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
warning: bounds on generic parameters are ignored in type aliases
|
||||||
|
--> $DIR/param-bounds-ignored.rs:15:14
|
||||||
|
|
|
||||||
|
LL | type SVec<T: Send+Send> = Vec<T>;
|
||||||
|
| ^^^^ ^^^^
|
||||||
|
|
|
||||||
|
= note: #[warn(ignored_generic_bounds)] on by default
|
||||||
|
|
||||||
|
warning: bounds on generic parameters are ignored in type aliases
|
||||||
|
--> $DIR/param-bounds-ignored.rs:17:19
|
||||||
|
|
|
||||||
|
LL | type VVec<'b, 'a: 'b+'b> = Vec<&'a i32>;
|
||||||
|
| ^^ ^^
|
||||||
|
|
||||||
|
warning: bounds on generic parameters are ignored in type aliases
|
||||||
|
--> $DIR/param-bounds-ignored.rs:19:18
|
||||||
|
|
|
||||||
|
LL | type WVec<'b, T: 'b+'b> = Vec<T>;
|
||||||
|
| ^^ ^^
|
||||||
|
|
||||||
|
warning: where clauses are ignored in type aliases
|
||||||
|
--> $DIR/param-bounds-ignored.rs:21:25
|
||||||
|
|
|
||||||
|
LL | type W2Vec<'b, T> where T: 'b, T: 'b = Vec<T>;
|
||||||
|
| ^^^^^ ^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 11 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue