about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-03-09 10:45:29 +0000
committerbors <bors@rust-lang.org>2018-03-09 10:45:29 +0000
commitfedce67cd21dc08ece5a484fe1a060346acac98a (patch)
tree2cc26079f1d4ee58c1bc38e326585013e52f7e6b
parent2079a084df08c38eb4dbfc5c8de5c0245170c3d9 (diff)
parent780b544a391fb2dc42d814ce8cb7e6ad3633fa39 (diff)
downloadrust-fedce67cd21dc08ece5a484fe1a060346acac98a.tar.gz
rust-fedce67cd21dc08ece5a484fe1a060346acac98a.zip
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
-rw-r--r--src/librustc/lint/context.rs21
-rw-r--r--src/librustc/lint/mod.rs6
-rw-r--r--src/librustc_lint/builtin.rs47
-rw-r--r--src/librustc_lint/lib.rs1
-rw-r--r--src/librustc_passes/ast_validation.rs41
-rw-r--r--src/librustc_typeck/collect.rs41
-rw-r--r--src/librustc_typeck/diagnostics.rs21
-rw-r--r--src/libsyntax/ast.rs19
-rw-r--r--src/libsyntax/parse/parser.rs15
-rw-r--r--src/test/compile-fail/bounds-lifetime.rs (renamed from src/test/compile-fail/issue-39122.rs)8
-rw-r--r--src/test/compile-fail/dst-bad-assign-3.rs3
-rw-r--r--src/test/compile-fail/issue-17994.rs2
-rw-r--r--src/test/compile-fail/issue-23046.rs4
-rw-r--r--src/test/compile-fail/private-in-public-warn.rs4
-rw-r--r--src/test/compile-fail/rfc1623.rs2
-rw-r--r--src/test/parse-fail/bounds-lifetime.rs11
-rw-r--r--src/test/parse-fail/bounds-type.rs2
-rw-r--r--src/test/run-pass/impl-trait/lifetimes.rs4
-rw-r--r--src/test/ui/param-bounds-ignored.rs80
-rw-r--r--src/test/ui/param-bounds-ignored.stderr100
20 files changed, 324 insertions, 108 deletions
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index b1e28f729ed..a1381817223 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -824,6 +824,17 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
         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) {
         let generics = self.generics.take();
         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);
     }
 
+    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) {
         self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
             run_lints!(cx, check_trait_item, early_passes, trait_item);
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 668e099ebab..7c103dc2721 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -181,6 +181,9 @@ pub trait LateLintPass<'a, 'tcx>: LintPass {
     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_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,
                 _: &LateContext<'a, 'tcx>,
                 _: FnKind<'tcx>,
@@ -253,6 +256,9 @@ pub trait EarlyLintPass: LintPass {
     fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { }
     fn check_generic_param(&mut self, _: &EarlyContext, _: &ast::GenericParam) { }
     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,
         _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { }
     fn check_fn_post(&mut self, _: &EarlyContext,
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index d39e00ab18f..c6698cbd006 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -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);
     }
 }
+
+/// 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",
+                );
+            }
+        }
+    }
+}
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 81609db6292..779aa3a9037 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -109,6 +109,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                        UnusedImportBraces,
                        AnonymousParameters,
                        UnusedDocComment,
+                       IgnoredGenericBounds,
                        );
 
     add_early_builtin_with_new!(sess,
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index a5dd8f1558e..55d00f92e4d 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -136,6 +136,33 @@ impl<'a> AstValidator<'a> {
                                                          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> {
@@ -157,6 +184,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     struct_span_err!(self.session, span, E0561,
                                      "patterns aren't allowed in function pointer types").emit();
                 });
+                self.check_late_bound_lifetime_defs(&bfty.generic_params);
             }
             TyKind::TraitObject(ref bounds, ..) => {
                 let mut any_lifetime_bounds = false;
@@ -417,6 +445,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
         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>`.
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 62301ab4a09..a17b35dec42 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -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) {
     let it = tcx.hir.expect_item(item_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());
             }
         },
-        hir::ItemTy(_, ref generics) => {
-            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(..) => {
+        hir::ItemTy(..) | hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => {
             tcx.generics_of(def_id);
             tcx.type_of(def_id);
             tcx.predicates_of(def_id);
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index bd2267a4601..24044fd2d72 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -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##"
 You declared two fields of a struct with the same name. Erroneous code
 example:
@@ -4815,6 +4795,7 @@ register_diagnostics! {
 //  E0086,
 //  E0103,
 //  E0104,
+//  E0122, // bounds in type aliases are ignored, turned into proper lint
 //  E0123,
 //  E0127,
 //  E0129,
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 10b8e121f83..8b3a7164ccc 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -294,6 +294,15 @@ pub enum TyParamBound {
     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
 /// modifier is `Maybe`. Negative bounds should also be handled here.
 #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
@@ -404,6 +413,16 @@ pub enum WherePredicate {
     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.
 ///
 /// E.g. `for<'c> Foo: Send+Clone+'c`
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 847733e1e37..f5aa01fb034 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -4951,6 +4951,7 @@ impl<'a> Parser<'a> {
                         }
                     ));
                 // 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) {
                     let rhs_ty = self.parse_ty()?;
                     where_clause.predicates.push(ast::WherePredicate::EqPredicate(
@@ -5608,18 +5609,8 @@ impl<'a> Parser<'a> {
             self.expect_lt()?;
             let params = self.parse_generic_params()?;
             self.expect_gt()?;
-
-            let first_non_lifetime_param_span = params.iter()
-                .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");
-            }
-
+            // We rely on AST validation to rule out invalid cases: There must not be type
+            // parameters, and the lifetime parameters must not have bounds.
             Ok(params)
         } else {
             Ok(Vec::new())
diff --git a/src/test/compile-fail/issue-39122.rs b/src/test/compile-fail/bounds-lifetime.rs
index 2e8a740f893..5bfaa6c54fa 100644
--- a/src/test/compile-fail/issue-39122.rs
+++ b/src/test/compile-fail/bounds-lifetime.rs
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // 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() {}
diff --git a/src/test/compile-fail/dst-bad-assign-3.rs b/src/test/compile-fail/dst-bad-assign-3.rs
index 759da7b2bde..ceaa3716232 100644
--- a/src/test/compile-fail/dst-bad-assign-3.rs
+++ b/src/test/compile-fail/dst-bad-assign-3.rs
@@ -12,8 +12,7 @@
 
 #![feature(unsized_tuple_coercion)]
 
-type Fat<T: ?Sized> = (isize, &'static str, T);
-//~^ WARNING bounds are ignored
+type Fat<T> = (isize, &'static str, T);
 
 #[derive(PartialEq,Eq)]
 struct Bar;
diff --git a/src/test/compile-fail/issue-17994.rs b/src/test/compile-fail/issue-17994.rs
index ac15bd9d15b..0f30e2461cf 100644
--- a/src/test/compile-fail/issue-17994.rs
+++ b/src/test/compile-fail/issue-17994.rs
@@ -10,5 +10,5 @@
 
 trait Tr {}
 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() {}
diff --git a/src/test/compile-fail/issue-23046.rs b/src/test/compile-fail/issue-23046.rs
index 129f7c8b1ea..670706b7a9a 100644
--- a/src/test/compile-fail/issue-23046.rs
+++ b/src/test/compile-fail/issue-23046.rs
@@ -10,7 +10,7 @@
 
 pub enum 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>
@@ -18,7 +18,7 @@ pub fn add<'var, VAR>
     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> {
     loop {}
 }
diff --git a/src/test/compile-fail/private-in-public-warn.rs b/src/test/compile-fail/private-in-public-warn.rs
index aa91ce27c37..cc9eed7e654 100644
--- a/src/test/compile-fail/private-in-public-warn.rs
+++ b/src/test/compile-fail/private-in-public-warn.rs
@@ -58,7 +58,7 @@ mod traits {
     pub trait PubTr {}
 
     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
     pub trait Tr1: PrivTr {} //~ ERROR private trait `traits::PrivTr` in public interface
     //~^ WARNING hard error
@@ -85,7 +85,7 @@ mod traits_where {
     pub type Alias<T> where T: PrivTr = T;
         //~^ ERROR private trait `traits_where::PrivTr` in public interface
         //~| WARNING hard error
-        //~| WARNING E0122
+        //~| WARNING where clauses are ignored in type aliases
     pub trait Tr2<T> where T: PrivTr {}
         //~^ ERROR private trait `traits_where::PrivTr` in public interface
         //~| WARNING hard error
diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs
index e8295e5e2da..579fa378a1c 100644
--- a/src/test/compile-fail/rfc1623.rs
+++ b/src/test/compile-fail/rfc1623.rs
@@ -22,7 +22,7 @@ static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 =
 struct SomeStruct<'x, 'y, 'z: 'x> {
     foo: &'x Foo<'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 {
diff --git a/src/test/parse-fail/bounds-lifetime.rs b/src/test/parse-fail/bounds-lifetime.rs
index 5113a6b4803..88db205310c 100644
--- a/src/test/parse-fail/bounds-lifetime.rs
+++ b/src/test/parse-fail/bounds-lifetime.rs
@@ -8,17 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // 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<> fn(); // OK
-type A = for<'a: 'b +> fn(); // OK
-
-type A = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context
+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: '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 `,`
 
 fn main() {}
diff --git a/src/test/parse-fail/bounds-type.rs b/src/test/parse-fail/bounds-type.rs
index c224b44a14b..0ebe7fde0a6 100644
--- a/src/test/parse-fail/bounds-type.rs
+++ b/src/test/parse-fail/bounds-type.rs
@@ -15,7 +15,7 @@ struct S<
     T: Tr + 'a, // OK
     T: 'a, // OK
     T:, // OK
-    T: ?for<'a: 'b + 'c> Trait, // OK
+    T: ?for<'a> Trait, // OK
     T: Tr +, // OK
     T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds
 >;
diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs
index 2d5dfb045db..fcad23926fc 100644
--- a/src/test/run-pass/impl-trait/lifetimes.rs
+++ b/src/test/run-pass/impl-trait/lifetimes.rs
@@ -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_arg<T: Debug>(x: &T) -> &impl Debug { x }
 
-fn mixed_lifetimes<'a>() -> impl for<'b: 'a> Fn(&'b u32) { |_| () }
-fn mixed_as_static() -> impl Fn(&'static u32) { mixed_lifetimes() }
+fn mixed_lifetimes<'a>() -> impl for<'b> Fn(&'b &'a u32) { |_| () }
+fn mixed_as_static() -> impl Fn(&'static &'static u32) { mixed_lifetimes() }
 
 trait MultiRegionTrait<'a, 'b>: Debug {}
 
diff --git a/src/test/ui/param-bounds-ignored.rs b/src/test/ui/param-bounds-ignored.rs
index 9e09102f2d4..94bcdec9450 100644
--- a/src/test/ui/param-bounds-ignored.rs
+++ b/src/test/ui/param-bounds-ignored.rs
@@ -8,13 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// must-compile-successfully
+#![allow(dead_code, non_camel_case_types)]
 
 use std::rc::Rc;
 
-type SVec<T: Send> = Vec<T>;
-type VVec<'b, 'a: 'b> = Vec<&'a i32>;
-type WVec<'b, T: 'b> = Vec<T>;
+type SVec<T: Send+Send> = Vec<T>;
+//~^ WARN bounds on generic parameters are ignored in type aliases
+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) {
     // 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();
     x.push(y);
+
+    let mut x : W2Vec<'static, & 'a i32> = Vec::new();
+    x.push(y);
+}
+
+fn bar1<'a, 'b>(
+    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() {
-    foo(&42);
+    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
 }
diff --git a/src/test/ui/param-bounds-ignored.stderr b/src/test/ui/param-bounds-ignored.stderr
index fe5986448fa..657fec54f96 100644
--- a/src/test/ui/param-bounds-ignored.stderr
+++ b/src/test/ui/param-bounds-ignored.stderr
@@ -1,18 +1,94 @@
-warning[E0122]: generic bounds are ignored in type aliases
-  --> $DIR/param-bounds-ignored.rs:15:1
+error: lifetime bounds cannot be used in this context
+  --> $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
-  --> $DIR/param-bounds-ignored.rs:16:1
+error: lifetime bounds cannot be used in this context
+  --> $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
-  --> $DIR/param-bounds-ignored.rs:17:1
+error: lifetime bounds cannot be used in this context
+  --> $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