about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2018-03-23 09:27:16 -0500
committerAlex Crichton <alex@alexcrichton.com>2018-03-23 10:16:08 -0700
commit7c0c7ef330fd87e8b169f0afc832d15bf098d0f0 (patch)
treeddd4d8c545630c041e2f91ef72bdc4913ccdcd58
parentf836ae48e6e0b55af1d0d6cd579424f26314d530 (diff)
parentc05d23406ead7b5747256c02127097807db45b83 (diff)
downloadrust-7c0c7ef330fd87e8b169f0afc832d15bf098d0f0.tar.gz
rust-7c0c7ef330fd87e8b169f0afc832d15bf098d0f0.zip
Rollup merge of #48909 - RalfJung:type_alias_bounds, r=petrochenkov
Improve lint for type alias bounds

First of all, I learned just today that I was wrong assuming that the bounds in type aliases are entirely ignored: It turns out they are used to resolve associated types in type aliases. So:
```rust
type T1<U: Bound> = U::Assoc; // compiles
type T2<U> = U::Assoc; // fails
type T3<U> = <U as Bound>::Assoc; // "correct" way to write this, maybe?
```
I am sorry for creating this mess.

This PR changes the wording of the lint accordingly. Moreover, since just removing the bound is no longer always a possible fix, I tried to detect cases like `T1` above and show a helpful message to the user:
```
warning: bounds on generic parameters are not enforced in type aliases
  --> $DIR/type-alias-bounds.rs:57:12
   |
LL | type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases
   |            ^^^^^
   |
   = help: the bound will not be checked when the type alias is used, and should be removed
help: use absolute paths (i.e., <T as Trait>::Assoc) to refer to associated types in type aliases
  --> $DIR/type-alias-bounds.rs:57:21
   |
LL | type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases
   |                     ^^^^^^^^
```
I am not sure if I got this entirely right. Ideally, we could provide a suggestion involving the correct trait and type name -- however, while I have access to the HIR in the lint, I do not know how to get access to the resolved name information, like which trait `Assoc` belongs to above. The lint does not even run if that resolution fails, so I assume that information is available *somewhere*...

This is a follow-up for (parts of) https://github.com/rust-lang/rust/pull/48326. Also see https://github.com/rust-lang/rust/issues/21903.

This changes the name of a lint, but that lint was just merged to master yesterday and has never even been on beta.
-rw-r--r--src/librustc/hir/mod.rs19
-rw-r--r--src/librustc_lint/builtin.rs104
-rw-r--r--src/librustc_lint/lib.rs2
-rw-r--r--src/test/compile-fail/issue-17994.rs1
-rw-r--r--src/test/compile-fail/private-in-public-warn.rs2
-rw-r--r--src/test/ui/higher-lifetime-bounds.rs (renamed from src/test/ui/param-bounds-ignored.rs)26
-rw-r--r--src/test/ui/higher-lifetime-bounds.stderr (renamed from src/test/ui/param-bounds-ignored.stderr)48
-rw-r--r--src/test/ui/type-alias-bounds.rs69
-rw-r--r--src/test/ui/type-alias-bounds.stderr83
9 files changed, 270 insertions, 84 deletions
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index d6810b2468b..12b472a7285 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -395,6 +395,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)]
@@ -571,6 +580,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, eg `for<'c> Foo: Send+Clone+'c`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct WhereBoundPredicate {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index bffa8628ff3..c0728cb2b66 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -46,6 +46,7 @@ use syntax::attr;
 use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes};
 use syntax_pos::{BytePos, Span, SyntaxContext};
 use syntax::symbol::keywords;
+use syntax::errors::DiagnosticBuilder;
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::intravisit::FnKind;
@@ -1316,48 +1317,115 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub {
     }
 }
 
-/// Lint for trait and lifetime bounds that are (accidentally) accepted by the parser, but
-/// ignored later.
+/// Lint for trait and lifetime bounds in type aliases being mostly ignored:
+/// They are relevant when using associated types, but otherwise neither checked
+/// at definition site nor enforced at use site.
 
-pub struct IgnoredGenericBounds;
+pub struct TypeAliasBounds;
 
 declare_lint! {
-    IGNORED_GENERIC_BOUNDS,
+    TYPE_ALIAS_BOUNDS,
     Warn,
-    "these generic bounds are ignored"
+    "bounds in type aliases are not enforced"
 }
 
-impl LintPass for IgnoredGenericBounds {
+impl LintPass for TypeAliasBounds {
     fn get_lints(&self) -> LintArray {
-        lint_array!(IGNORED_GENERIC_BOUNDS)
+        lint_array!(TYPE_ALIAS_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,
+impl TypeAliasBounds {
+    fn is_type_variable_assoc(qpath: &hir::QPath) -> bool {
+        match *qpath {
+            hir::QPath::TypeRelative(ref ty, _) => {
+                // If this is a type variable, we found a `T::Assoc`.
+                match ty.node {
+                    hir::TyPath(hir::QPath::Resolved(None, ref path)) => {
+                        match path.def {
+                            Def::TyParam(_) => true,
+                            _ => false
+                        }
+                    }
+                    _ => false
+                }
+            }
+            hir::QPath::Resolved(..) => false,
+        }
+    }
+
+    fn suggest_changing_assoc_types(ty: &hir::Ty, err: &mut DiagnosticBuilder) {
+        // Access to associates types should use `<T as Bound>::Assoc`, which does not need a
+        // bound.  Let's see if this type does that.
+
+        // We use a HIR visitor to walk the type.
+        use rustc::hir::intravisit::{self, Visitor};
+        use syntax::ast::NodeId;
+        struct WalkAssocTypes<'a, 'db> where 'db: 'a {
+            err: &'a mut DiagnosticBuilder<'db>
+        }
+        impl<'a, 'db, 'v> Visitor<'v> for WalkAssocTypes<'a, 'db> {
+            fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v>
+            {
+                intravisit::NestedVisitorMap::None
+            }
+
+            fn visit_qpath(&mut self, qpath: &'v hir::QPath, id: NodeId, span: Span) {
+                if TypeAliasBounds::is_type_variable_assoc(qpath) {
+                    self.err.span_help(span,
+                        "use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to \
+                         associated types in type aliases");
+                }
+                intravisit::walk_qpath(self, qpath, id, span)
+            }
+        }
+
+        // Let's go for a walk!
+        let mut visitor = WalkAssocTypes { err };
+        visitor.visit_ty(ty);
+    }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds {
+    fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
+        let (ty, type_alias_generics) = match item.node {
+            hir::ItemTy(ref ty, ref generics) => (&*ty, generics),
             _ => return,
         };
+        let mut suggested_changing_assoc_types = false;
         // 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");
+            let mut err = cx.struct_span_lint(TYPE_ALIAS_BOUNDS, spans,
+                "where clauses are not enforced in type aliases");
+            err.help("the clause will not be checked when the type alias is used, \
+                      and should be removed");
+            if !suggested_changing_assoc_types {
+                TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
+                suggested_changing_assoc_types = true;
+            }
+            err.emit();
         }
         // 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(),
+                &hir::GenericParam::Lifetime(ref l) => l.bounds.iter().map(|b| b.span).collect(),
+                &hir::GenericParam::Type(ref ty) => ty.bounds.iter().map(|b| b.span()).collect(),
             };
             if !spans.is_empty() {
-                cx.span_lint(
-                    IGNORED_GENERIC_BOUNDS,
+                let mut err = cx.struct_span_lint(
+                    TYPE_ALIAS_BOUNDS,
                     spans,
-                    "bounds on generic parameters are ignored in type aliases",
+                    "bounds on generic parameters are not enforced in type aliases",
                 );
+                err.help("the bound will not be checked when the type alias is used, \
+                          and should be removed");
+                if !suggested_changing_assoc_types {
+                    TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
+                    suggested_changing_assoc_types = true;
+                }
+                err.emit();
             }
         }
     }
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index ce896bfb701..30dd2efeb7a 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -109,7 +109,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                        UnusedImportBraces,
                        AnonymousParameters,
                        UnusedDocComment,
-                       IgnoredGenericBounds,
                        );
 
     add_early_builtin_with_new!(sess,
@@ -139,6 +138,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                  MutableTransmutes,
                  UnionsWithDropFields,
                  UnreachablePub,
+                 TypeAliasBounds,
                  );
 
     add_builtin_with_new!(sess,
diff --git a/src/test/compile-fail/issue-17994.rs b/src/test/compile-fail/issue-17994.rs
index 0f30e2461cf..25141b9b825 100644
--- a/src/test/compile-fail/issue-17994.rs
+++ b/src/test/compile-fail/issue-17994.rs
@@ -10,5 +10,4 @@
 
 trait Tr {}
 type Huh<T> where T: Tr = isize; //~  ERROR type parameter `T` is unused
-                                 //~| WARNING where clauses are ignored in type aliases
 fn main() {}
diff --git a/src/test/compile-fail/private-in-public-warn.rs b/src/test/compile-fail/private-in-public-warn.rs
index cc9eed7e654..6eeb14638e7 100644
--- a/src/test/compile-fail/private-in-public-warn.rs
+++ b/src/test/compile-fail/private-in-public-warn.rs
@@ -58,7 +58,6 @@ mod traits {
     pub trait PubTr {}
 
     pub type Alias<T: PrivTr> = T; //~ ERROR private trait `traits::PrivTr` in public interface
-    //~^ 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 +84,6 @@ mod traits_where {
     pub type Alias<T> where T: PrivTr = T;
         //~^ ERROR private trait `traits_where::PrivTr` in public interface
         //~| WARNING hard error
-        //~| 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/ui/param-bounds-ignored.rs b/src/test/ui/higher-lifetime-bounds.rs
index 94bcdec9450..70b3b34fbd8 100644
--- a/src/test/ui/param-bounds-ignored.rs
+++ b/src/test/ui/higher-lifetime-bounds.rs
@@ -10,31 +10,7 @@
 
 #![allow(dead_code, non_camel_case_types)]
 
-use std::rc::Rc;
-
-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.
-    let mut x : SVec<_> = Vec::new();
-    x.push(Rc::new(42));
-
-    let mut x : VVec<'static, 'a> = Vec::new();
-    x.push(y);
-
-    let mut x : WVec<'static, & 'a i32> = Vec::new();
-    x.push(y);
-
-    let mut x : W2Vec<'static, & 'a i32> = Vec::new();
-    x.push(y);
-}
+// Test that bounds on higher-kinded lifetime binders are rejected.
 
 fn bar1<'a, 'b>(
     x: &'a i32,
diff --git a/src/test/ui/param-bounds-ignored.stderr b/src/test/ui/higher-lifetime-bounds.stderr
index 657fec54f96..82c00747436 100644
--- a/src/test/ui/param-bounds-ignored.stderr
+++ b/src/test/ui/higher-lifetime-bounds.stderr
@@ -1,94 +1,68 @@
 error: lifetime bounds cannot be used in this context
-  --> $DIR/param-bounds-ignored.rs:42:22
+  --> $DIR/higher-lifetime-bounds.rs:18:22
    |
 LL |     f: for<'xa, 'xb: 'xa+'xa> fn(&'xa i32, &'xb i32) -> &'xa i32)
    |                      ^^^ ^^^
 
 error: lifetime bounds cannot be used in this context
-  --> $DIR/param-bounds-ignored.rs:50:34
+  --> $DIR/higher-lifetime-bounds.rs:26:34
    |
 LL | 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
-  --> $DIR/param-bounds-ignored.rs:65:28
+  --> $DIR/higher-lifetime-bounds.rs:41:28
    |
 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
+  --> $DIR/higher-lifetime-bounds.rs:53: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
+  --> $DIR/higher-lifetime-bounds.rs:61: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
+  --> $DIR/higher-lifetime-bounds.rs:63: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
+  --> $DIR/higher-lifetime-bounds.rs:65: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
+  --> $DIR/higher-lifetime-bounds.rs:68: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
+  --> $DIR/higher-lifetime-bounds.rs:71: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
+  --> $DIR/higher-lifetime-bounds.rs:75: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
+  --> $DIR/higher-lifetime-bounds.rs:77: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
 
diff --git a/src/test/ui/type-alias-bounds.rs b/src/test/ui/type-alias-bounds.rs
new file mode 100644
index 00000000000..c1cdeef3a46
--- /dev/null
+++ b/src/test/ui/type-alias-bounds.rs
@@ -0,0 +1,69 @@
+// Copyright 2014 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.
+
+// Test ignored_generic_bounds lint warning about bounds in type aliases
+
+// must-compile-successfully
+#![allow(dead_code)]
+
+use std::rc::Rc;
+
+type SVec<T: Send+Send> = Vec<T>;
+//~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds]
+type S2Vec<T> where T: Send = Vec<T>;
+//~^ WARN where clauses are not enforced in type aliases [type_alias_bounds]
+type VVec<'b, 'a: 'b+'b> = (&'b u32, Vec<&'a i32>);
+//~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds]
+type WVec<'b, T: 'b+'b> = (&'b u32, Vec<T>);
+//~^ WARN bounds on generic parameters are not enforced in type aliases [type_alias_bounds]
+type W2Vec<'b, T> where T: 'b, T: 'b = (&'b u32, Vec<T>);
+//~^ WARN where clauses are not enforced in type aliases [type_alias_bounds]
+
+static STATIC : u32 = 0;
+
+fn foo<'a>(y: &'a i32) {
+    // If any of the bounds above would matter, the code below would be rejected.
+    // This can be seen when replacing the type aliases above by newtype structs.
+    // (The type aliases have no unused parameters to make that a valid transformation.)
+    let mut x : SVec<_> = Vec::new();
+    x.push(Rc::new(42)); // is not send
+
+    let mut x : S2Vec<_> = Vec::new();
+    x.push(Rc::new(42)); // is not send
+
+    let mut x : VVec<'static, 'a> = (&STATIC, Vec::new());
+    x.1.push(y); // 'a: 'static does not hold
+
+    let mut x : WVec<'static, &'a i32> = (&STATIC, Vec::new());
+    x.1.push(y); // &'a i32: 'static does not hold
+
+    let mut x : W2Vec<'static, &'a i32> = (&STATIC, Vec::new());
+    x.1.push(y); // &'a i32: 'static does not hold
+}
+
+// Bounds are not checked either, i.e. the definition is not necessarily well-formed
+struct Sendable<T: Send>(T);
+type MySendable<T> = Sendable<T>; // no error here!
+
+// However, bounds *are* taken into account when accessing associated types
+trait Bound { type Assoc; }
+type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases
+type T2<U> where U: Bound = U::Assoc;  //~ WARN not enforced in type aliases
+
+// This errors
+// type T3<U> = U::Assoc;
+// Do this instead
+type T4<U> = <U as Bound>::Assoc;
+
+// Make sure the help about associatd types is not shown incorrectly
+type T5<U: Bound> = <U as Bound>::Assoc;  //~ WARN not enforced in type aliases
+type T6<U: Bound> = ::std::vec::Vec<U>;  //~ WARN not enforced in type aliases
+
+fn main() {}
diff --git a/src/test/ui/type-alias-bounds.stderr b/src/test/ui/type-alias-bounds.stderr
new file mode 100644
index 00000000000..2a2b0b0f26e
--- /dev/null
+++ b/src/test/ui/type-alias-bounds.stderr
@@ -0,0 +1,83 @@
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias-bounds.rs:18:14
+   |
+LL | type SVec<T: Send+Send> = Vec<T>;
+   |              ^^^^ ^^^^
+   |
+   = note: #[warn(type_alias_bounds)] on by default
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias-bounds.rs:20:21
+   |
+LL | type S2Vec<T> where T: Send = Vec<T>;
+   |                     ^^^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias-bounds.rs:22:19
+   |
+LL | type VVec<'b, 'a: 'b+'b> = (&'b u32, Vec<&'a i32>);
+   |                   ^^ ^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias-bounds.rs:24:18
+   |
+LL | type WVec<'b, T: 'b+'b> = (&'b u32, Vec<T>);
+   |                  ^^ ^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias-bounds.rs:26:25
+   |
+LL | type W2Vec<'b, T> where T: 'b, T: 'b = (&'b u32, Vec<T>);
+   |                         ^^^^^  ^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias-bounds.rs:57:12
+   |
+LL | type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases
+   |            ^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+help: use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases
+  --> $DIR/type-alias-bounds.rs:57:21
+   |
+LL | type T1<U: Bound> = U::Assoc; //~ WARN not enforced in type aliases
+   |                     ^^^^^^^^
+
+warning: where clauses are not enforced in type aliases
+  --> $DIR/type-alias-bounds.rs:58:18
+   |
+LL | type T2<U> where U: Bound = U::Assoc;  //~ WARN not enforced in type aliases
+   |                  ^^^^^^^^
+   |
+   = help: the clause will not be checked when the type alias is used, and should be removed
+help: use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases
+  --> $DIR/type-alias-bounds.rs:58:29
+   |
+LL | type T2<U> where U: Bound = U::Assoc;  //~ WARN not enforced in type aliases
+   |                             ^^^^^^^^
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias-bounds.rs:66:12
+   |
+LL | type T5<U: Bound> = <U as Bound>::Assoc;  //~ WARN not enforced in type aliases
+   |            ^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+
+warning: bounds on generic parameters are not enforced in type aliases
+  --> $DIR/type-alias-bounds.rs:67:12
+   |
+LL | type T6<U: Bound> = ::std::vec::Vec<U>;  //~ WARN not enforced in type aliases
+   |            ^^^^^
+   |
+   = help: the bound will not be checked when the type alias is used, and should be removed
+