From f3290cdcac1c698d7b1c9aacab2988cd3a8cc56b Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Fri, 7 Sep 2018 17:45:01 +0300
Subject: [PATCH 1/4] rustc: support turning trait errors into lints via
 ObligationCauseCode.

---
 .../infer/error_reporting/need_type_info.rs   | 168 +++++++++---------
 src/librustc/infer/mod.rs                     |   4 +-
 src/librustc/infer/outlives/env.rs            |  10 +-
 src/librustc/mir/interpret/error.rs           |  18 +-
 src/librustc/traits/error_reporting.rs        | 107 ++++++++---
 src/librustc/traits/fulfill.rs                |   4 +-
 src/librustc/traits/mod.rs                    |   2 +-
 src/librustc/traits/query/outlives_bounds.rs  |  52 ++++--
 src/librustc/traits/select.rs                 |   4 +-
 src/librustc/ty/context.rs                    |   6 +-
 src/librustc/ty/util.rs                       |   2 +-
 src/librustc/ty/wf.rs                         |  36 ++--
 src/librustc_mir/transform/qualify_consts.rs  |   2 +-
 .../implied_outlives_bounds.rs                |   6 +-
 src/librustc_typeck/check/closure.rs          |   5 +-
 src/librustc_typeck/check/compare_method.rs   |  26 +--
 src/librustc_typeck/check/dropck.rs           |   2 +-
 src/librustc_typeck/check/mod.rs              |  36 ++--
 src/librustc_typeck/check/regionck.rs         |   9 +-
 src/librustc_typeck/check/wfcheck.rs          |  76 ++++----
 src/librustc_typeck/check/writeback.rs        |  10 +-
 src/librustc_typeck/coherence/builtin.rs      |   2 +-
 src/librustc_typeck/lib.rs                    |   2 +-
 src/test/ui/issues/issue-23046.rs             |   4 +-
 src/test/ui/issues/issue-23046.stderr         |   6 +-
 25 files changed, 345 insertions(+), 254 deletions(-)

diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs
index 505b1bc032d20..757068783b0e8 100644
--- a/src/librustc/infer/error_reporting/need_type_info.rs
+++ b/src/librustc/infer/error_reporting/need_type_info.rs
@@ -8,71 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use hir::{self, Local, Pat, Body, HirId};
-use hir::intravisit::{self, Visitor, NestedVisitorMap};
+use hir::{self, HirId};
 use infer::InferCtxt;
 use infer::type_variable::TypeVariableOrigin;
+use traits;
 use ty::{self, Ty, Infer, TyVar};
 use syntax::source_map::CompilerDesugaringKind;
-use syntax_pos::Span;
 use errors::DiagnosticBuilder;
 
-struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
-    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-    target_ty: &'a Ty<'tcx>,
-    hir_map: &'a hir::map::Map<'gcx>,
-    found_local_pattern: Option<&'gcx Pat>,
-    found_arg_pattern: Option<&'gcx Pat>,
-}
-
-impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
-    fn node_matches_type(&mut self, node_id: HirId) -> bool {
-        let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
-            tables.borrow().node_id_to_type_opt(node_id)
-        });
-        match ty_opt {
-            Some(ty) => {
-                let ty = self.infcx.resolve_type_vars_if_possible(&ty);
-                ty.walk().any(|inner_ty| {
-                    inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) {
-                        (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
-                            self.infcx
-                                .type_variables
-                                .borrow_mut()
-                                .sub_unified(a_vid, b_vid)
-                        }
-                        _ => false,
-                    }
-                })
-            }
-            None => false,
-        }
-    }
-}
-
-impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.hir_map)
-    }
-
-    fn visit_local(&mut self, local: &'gcx Local) {
-        if self.found_local_pattern.is_none() && self.node_matches_type(local.hir_id) {
-            self.found_local_pattern = Some(&*local.pat);
-        }
-        intravisit::walk_local(self, local);
-    }
-
-    fn visit_body(&mut self, body: &'gcx Body) {
-        for argument in &body.arguments {
-            if self.found_arg_pattern.is_none() && self.node_matches_type(argument.hir_id) {
-                self.found_arg_pattern = Some(&*argument.pat);
-            }
-        }
-        intravisit::walk_body(self, body);
-    }
-}
-
-
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
         if let ty::Infer(ty::TyVar(ty_vid)) = (*ty).sty {
@@ -89,38 +32,85 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn need_type_info_err(&self,
-                            body_id: Option<hir::BodyId>,
-                            span: Span,
-                            ty: Ty<'tcx>)
-                            -> DiagnosticBuilder<'gcx> {
+                              cause: &traits::ObligationCause<'tcx>,
+                              ty: Ty<'tcx>)
+                              -> DiagnosticBuilder<'gcx> {
         let ty = self.resolve_type_vars_if_possible(&ty);
         let name = self.extract_type_name(&ty);
 
-        let mut err_span = span;
         let mut labels = vec![(
-            span,
+            cause.span,
             if &name == "_" {
                 "cannot infer type".to_string()
             } else {
                 format!("cannot infer type for `{}`", name)
             },
         )];
+        let mut span = cause.span;
 
-        let mut local_visitor = FindLocalByTypeVisitor {
-            infcx: &self,
-            target_ty: &ty,
-            hir_map: &self.tcx.hir,
-            found_local_pattern: None,
-            found_arg_pattern: None,
-        };
-
-        if let Some(body_id) = body_id {
-            let expr = self.tcx.hir.expect_expr(body_id.node_id);
-            local_visitor.visit_expr(expr);
+        // NB. Lower values are more preferred.
+        #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+        enum LocalKind {
+            ClosureArg,
+            Let,
         }
 
-        if let Some(pattern) = local_visitor.found_arg_pattern {
-            err_span = pattern.span;
+        let found_local = self.in_progress_tables.and_then(|tables| {
+            let tables = tables.borrow();
+            let local_id_root = tables.local_id_root?;
+            assert!(local_id_root.is_local());
+
+            tables.node_types().iter().filter_map(|(&local_id, &node_ty)| {
+                let node_id = self.tcx.hir.hir_to_node_id(HirId {
+                    owner: local_id_root.index,
+                    local_id,
+                });
+
+                let (kind, pattern) = match self.tcx.hir.find(node_id) {
+                    Some(hir::Node::Local(local)) => {
+                        (LocalKind::Let, &*local.pat)
+                    }
+
+                    Some(hir::Node::Binding(pat)) |
+                    Some(hir::Node::Pat(pat)) => {
+                        let parent_id = self.tcx.hir.get_parent_node(node_id);
+                        match self.tcx.hir.find(parent_id) {
+                            Some(hir::Node::Expr(e)) => {
+                                match e.node {
+                                    hir::ExprKind::Closure(..) => {}
+                                    _ => return None,
+                                }
+                            }
+                            _ => return None,
+                        }
+
+                        (LocalKind::ClosureArg, pat)
+                    }
+
+                    _ => return None
+                };
+
+                let node_ty = self.resolve_type_vars_if_possible(&node_ty);
+                let matches_type = node_ty.walk().any(|inner_ty| {
+                    inner_ty == ty || match (&inner_ty.sty, &ty.sty) {
+                        (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
+                            self.type_variables
+                                .borrow_mut()
+                                .sub_unified(a_vid, b_vid)
+                        }
+                        _ => false,
+                    }
+                });
+                if !matches_type {
+                    return None;
+                }
+
+                Some((kind, pattern))
+            }).min_by_key(|&(kind, pattern)| (kind, pattern.hir_id.local_id))
+        });
+
+        if let Some((LocalKind::ClosureArg, pattern)) = found_local {
+            span = pattern.span;
             // We don't want to show the default label for closures.
             //
             // So, before clearing, the output would look something like this:
@@ -139,7 +129,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             labels.clear();
             labels.push(
                 (pattern.span, "consider giving this closure parameter a type".to_string()));
-        } else if let Some(pattern) = local_visitor.found_local_pattern {
+        } else if let Some((LocalKind::Let, pattern)) = found_local {
             if let Some(simple_ident) = pattern.simple_ident() {
                 match pattern.span.compiler_desugaring_kind() {
                     None => labels.push((pattern.span,
@@ -155,10 +145,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
-        let mut err = struct_span_err!(self.tcx.sess,
-                                       err_span,
-                                       E0282,
-                                       "type annotations needed");
+        let lint = self.get_lint_from_cause_code(&cause.code);
+        macro_rules! struct_span_err_or_lint {
+            ($code:ident, $($message:tt)*) => {
+                match lint {
+                    Some((lint, id)) => {
+                        let message = format!($($message)*);
+                        self.tcx.struct_span_lint_node(lint, id, span, &message)
+                    }
+                    None => {
+                        struct_span_err!(self.tcx.sess, span, $code, $($message)*)
+                    }
+                }
+            }
+        }
+
+        let mut err = struct_span_err_or_lint!(E0282, "type annotations needed");
 
         for (target_span, label_message) in labels {
             err.span_label(target_span, label_message);
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index e628a3458f9e6..160048b37df68 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1424,8 +1424,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// new obligations that must further be processed.
     pub fn partially_normalize_associated_types_in<T>(
         &self,
-        span: Span,
-        body_id: ast::NodeId,
+        cause: ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         value: &T,
     ) -> InferOk<'tcx, T>
@@ -1434,7 +1433,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     {
         debug!("partially_normalize_associated_types_in(value={:?})", value);
         let mut selcx = traits::SelectionContext::new(self);
-        let cause = ObligationCause::misc(span, body_id);
         let traits::Normalized { value, obligations } =
             traits::normalize(&mut selcx, param_env, cause, value);
         debug!(
diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc/infer/outlives/env.rs
index 7f59a6794efbd..f9d3518d550c8 100644
--- a/src/librustc/infer/outlives/env.rs
+++ b/src/librustc/infer/outlives/env.rs
@@ -10,12 +10,9 @@
 
 use infer::{GenericKind, InferCtxt};
 use infer::outlives::free_region_map::FreeRegionMap;
-use traits::query::outlives_bounds::{self, OutlivesBound};
+use traits::{self, query::outlives_bounds::{self, OutlivesBound}};
 use ty::{self, Ty};
 
-use syntax::ast;
-use syntax_pos::Span;
-
 /// The `OutlivesEnvironment` collects information about what outlives
 /// what in a given type-checking setting. For example, if we have a
 /// where-clause like `where T: 'a` in scope, then the
@@ -136,15 +133,14 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
         &mut self,
         infcx: &InferCtxt<'a, 'gcx, 'tcx>,
         fn_sig_tys: &[Ty<'tcx>],
-        body_id: ast::NodeId,
-        span: Span,
+        cause: &traits::ObligationCause<'tcx>,
     ) {
         debug!("add_implied_bounds()");
 
         for &ty in fn_sig_tys {
             let ty = infcx.resolve_type_vars_if_possible(&ty);
             debug!("add_implied_bounds: ty = {}", ty);
-            let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
+            let implied_bounds = infcx.implied_outlives_bounds(self.param_env, cause, ty);
             self.add_outlives_bounds(Some(infcx), implied_bounds)
         }
     }
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index cccde692bf789..13ea8bd532a4a 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -55,6 +55,16 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
         self.struct_generic(tcx, message, None)
     }
 
+    pub fn struct_lint(&self,
+        tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
+        message: &str,
+        lint_root: ast::NodeId,
+        lint: Option<&'static ::lint::Lint>)
+        -> Option<DiagnosticBuilder<'tcx>>
+    {
+        self.struct_generic(tcx, message, Some((lint_root, lint)))
+    }
+
     pub fn report_as_error(&self,
         tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
         message: &str
@@ -73,7 +83,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
         let lint = self.struct_generic(
             tcx,
             message,
-            Some(lint_root),
+            Some((lint_root, None)),
         );
         if let Some(mut lint) = lint {
             lint.emit();
@@ -84,7 +94,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
         &self,
         tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
         message: &str,
-        lint_root: Option<ast::NodeId>,
+        lint_root: Option<(ast::NodeId, Option<&'static ::lint::Lint>)>,
     ) -> Option<DiagnosticBuilder<'tcx>> {
         match self.error.kind {
             ::mir::interpret::EvalErrorKind::TypeckError |
@@ -97,7 +107,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
             _ => {},
         }
         trace!("reporting const eval failure at {:?}", self.span);
-        let mut err = if let Some(lint_root) = lint_root {
+        let mut err = if let Some((lint_root, lint)) = lint_root {
             let node_id = self.stacktrace
                 .iter()
                 .rev()
@@ -105,7 +115,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
                 .next()
                 .unwrap_or(lint_root);
             tcx.struct_span_lint_node(
-                ::rustc::lint::builtin::CONST_ERR,
+                lint.unwrap_or(::rustc::lint::builtin::CONST_ERR),
                 node_id,
                 tcx.span,
                 message,
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 466d472cca338..8602e7563b8bd 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -50,7 +50,6 @@ use syntax_pos::{DUMMY_SP, Span};
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn report_fulfillment_errors(&self,
                                      errors: &[FulfillmentError<'tcx>],
-                                     body_id: Option<hir::BodyId>,
                                      fallback_has_occurred: bool) {
         #[derive(Debug)]
         struct ErrorDescriptor<'tcx> {
@@ -111,7 +110,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         for (error, suppressed) in errors.iter().zip(is_suppressed) {
             if !suppressed {
-                self.report_fulfillment_error(error, body_id, fallback_has_occurred);
+                self.report_fulfillment_error(error, fallback_has_occurred);
             }
         }
     }
@@ -155,7 +154,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>,
-                                body_id: Option<hir::BodyId>,
                                 fallback_has_occurred: bool) {
         debug!("report_fulfillment_errors({:?})", error);
         match error.code {
@@ -166,7 +164,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 self.report_projection_error(&error.obligation, e);
             }
             FulfillmentErrorCode::CodeAmbiguity => {
-                self.maybe_report_ambiguity(&error.obligation, body_id);
+                self.maybe_report_ambiguity(&error.obligation);
             }
             FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
                 self.report_mismatched_types(&error.obligation.cause,
@@ -224,13 +222,30 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 }
             }
 
+
+            let span = obligation.cause.span;
+            let lint = self.get_lint_from_cause_code(&obligation.cause.code);
+            macro_rules! struct_span_err_or_lint {
+                ($code:ident, $($message:tt)*) => {
+                    match lint {
+                        Some((lint, id)) => {
+                            let message = format!($($message)*);
+                            self.tcx.struct_span_lint_node(lint, id, span, &message)
+                        }
+                        None => {
+                            struct_span_err!(self.tcx.sess, span, $code, $($message)*)
+                        }
+                    }
+                }
+            }
+
             let msg = format!("type mismatch resolving `{}`", predicate);
             let error_id = (DiagnosticMessageId::ErrorId(271),
                             Some(obligation.cause.span), msg.clone());
             let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
             if fresh {
-                let mut diag = struct_span_err!(
-                    self.tcx.sess, obligation.cause.span, E0271,
+                let mut diag = struct_span_err_or_lint!(
+                    E0271,
                     "type mismatch resolving `{}`", predicate
                 );
                 self.note_type_err(&mut diag, &obligation.cause, None, values, err);
@@ -559,6 +574,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    /// Get the lint and `NodeId` it applies to, if any exist.
+    pub fn get_lint_from_cause_code(
+        &self,
+        code: &ObligationCauseCode<'tcx>,
+    ) -> Option<(&'static ::lint::Lint, ast::NodeId)> {
+        match code {
+            ObligationCauseCode::BuiltinDerivedObligation(data) |
+            ObligationCauseCode::ImplDerivedObligation(data) => {
+                self.get_lint_from_cause_code(&data.parent_code)
+            }
+            _ => None,
+        }
+    }
+
     pub fn report_selection_error(&self,
                                   obligation: &PredicateObligation<'tcx>,
                                   error: &SelectionError<'tcx>,
@@ -566,6 +595,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     {
         let span = obligation.cause.span;
 
+        let lint = self.get_lint_from_cause_code(&obligation.cause.code);
+        macro_rules! struct_span_err_or_lint {
+            ($code:ident, $($message:tt)*) => {
+                match lint {
+                    Some((lint, id)) => {
+                        let message = format!($($message)*);
+                        self.tcx.struct_span_lint_node(lint, id, span, &message)
+                    }
+                    None => {
+                        struct_span_err!(self.tcx.sess, span, $code, $($message)*)
+                    }
+                }
+            }
+        }
+
         let mut err = match *error {
             SelectionError::Unimplemented => {
                 if let ObligationCauseCode::CompareImplMethodObligation {
@@ -580,6 +624,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         .emit();
                     return;
                 }
+
                 match obligation.predicate {
                     ty::Predicate::Trait(ref trait_predicate) => {
                         let trait_predicate =
@@ -598,9 +643,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             = self.on_unimplemented_note(trait_ref, obligation);
                         let have_alt_message = message.is_some() || label.is_some();
 
-                        let mut err = struct_span_err!(
-                            self.tcx.sess,
-                            span,
+                        let mut err = struct_span_err_or_lint!(
                             E0277,
                             "{}",
                             message.unwrap_or_else(|| {
@@ -694,7 +737,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         let predicate = self.resolve_type_vars_if_possible(predicate);
                         let err = self.region_outlives_predicate(&obligation.cause,
                                                                     &predicate).err().unwrap();
-                        struct_span_err!(self.tcx.sess, span, E0279,
+                        struct_span_err_or_lint!(E0279,
                             "the requirement `{}` is not satisfied (`{}`)",
                             predicate, err)
                     }
@@ -702,7 +745,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
                         let predicate =
                             self.resolve_type_vars_if_possible(&obligation.predicate);
-                        struct_span_err!(self.tcx.sess, span, E0280,
+                        struct_span_err_or_lint!(E0280,
                             "the requirement `{}` is not satisfied",
                             predicate)
                     }
@@ -841,10 +884,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             }
 
             ConstEvalFailure(ref err) => {
-                match err.struct_error(
-                    self.tcx.at(span),
-                    "could not evaluate constant expression",
-                ) {
+                let err = if let Some((lint, id)) = lint {
+                    err.struct_lint(
+                        self.tcx.at(span),
+                        "could not evaluate constant expression",
+                        id,
+                        Some(lint),
+                    )
+                } else {
+                    err.struct_error(
+                        self.tcx.at(span),
+                        "could not evaluate constant expression",
+                    )
+                };
+                match err {
                     Some(err) => err,
                     None => return,
                 }
@@ -1230,8 +1283,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-    fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>,
-                              body_id: Option<hir::BodyId>) {
+    fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
         // Unable to successfully determine, probably means
         // insufficient type information, but could mean
         // ambiguous impls. The latter *ought* to be a
@@ -1250,6 +1302,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             return;
         }
 
+        // Avoid erroring about inference variables in lint mode.
+        if let Some((lint, id)) = self.get_lint_from_cause_code(&obligation.cause.code) {
+            match self.tcx.lint_level_at_node(lint, id).0 {
+                // These are the only cases in which we can't detect whether
+                // a diagnostic was emitted (as it likely wasn't an error).
+                ::lint::Level::Allow |
+                ::lint::Level::Warn => return,
+
+                ::lint::Level::Deny |
+                ::lint::Level::Forbid => {}
+            }
+        }
+
         match predicate {
             ty::Predicate::Trait(ref data) => {
                 let trait_ref = data.to_poly_trait_ref();
@@ -1286,7 +1351,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         self.tcx.lang_items().sized_trait()
                         .map_or(false, |sized_id| sized_id == trait_ref.def_id())
                     {
-                        self.need_type_info_err(body_id, span, self_ty).emit();
+                        self.need_type_info_err(&obligation.cause, self_ty).emit();
                     } else {
                         let mut err = struct_span_err!(self.tcx.sess,
                                                         span, E0283,
@@ -1303,7 +1368,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 // Same hacky approach as above to avoid deluging user
                 // with error messages.
                 if !ty.references_error() && !self.tcx.sess.has_errors() {
-                    self.need_type_info_err(body_id, span, ty).emit();
+                    self.need_type_info_err(&obligation.cause, ty).emit();
                 }
             }
 
@@ -1314,9 +1379,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
                     // both must be type variables, or the other would've been instantiated
                     assert!(a.is_ty_var() && b.is_ty_var());
-                    self.need_type_info_err(body_id,
-                                            obligation.cause.span,
-                                            a).emit();
+                    self.need_type_info_err(&obligation.cause, a).emit();
                 }
             }
 
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 9998db4ad1d48..9ee52ecbdf00b 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -440,8 +440,8 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
             ty::Predicate::WellFormed(ty) => {
                 match ty::wf::obligations(self.selcx.infcx(),
                                           obligation.param_env,
-                                          obligation.cause.body_id,
-                                          ty, obligation.cause.span) {
+                                          &obligation.cause,
+                                          ty) {
                     None => {
                         pending_obligation.stalled_on = vec![ty];
                         ProcessResult::Unchanged
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index e2dbe88354060..485d8041c5ee1 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -700,7 +700,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         ) {
             Ok(predicates) => predicates,
             Err(errors) => {
-                infcx.report_fulfillment_errors(&errors, None, false);
+                infcx.report_fulfillment_errors(&errors, false);
                 // An unnormalized env is better than nothing.
                 return elaborated_env;
             }
diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs
index 47c8ee357fbe8..c2fc0c829cfc8 100644
--- a/src/librustc/traits/query/outlives_bounds.rs
+++ b/src/librustc/traits/query/outlives_bounds.rs
@@ -9,8 +9,6 @@
 // except according to those terms.
 
 use infer::InferCtxt;
-use syntax::ast;
-use syntax::source_map::Span;
 use smallvec::SmallVec;
 use traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt};
 use traits::query::NoSolution;
@@ -99,36 +97,54 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     pub fn implied_outlives_bounds(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        body_id: ast::NodeId,
+        cause: &ObligationCause<'tcx>,
         ty: Ty<'tcx>,
-        span: Span,
     ) -> Vec<OutlivesBound<'tcx>> {
         debug!("implied_outlives_bounds(ty = {:?})", ty);
 
+        let mut skip_delay_bug = false;
+
+        // Avoid ICE-ing from unsolved inference variables in lint mode.
+        if let Some((lint, id)) = self.get_lint_from_cause_code(&cause.code) {
+            match self.tcx.lint_level_at_node(lint, id).0 {
+                // These are the only cases in which we can't detect whether
+                // a diagnostic was emitted (as it likely wasn't an error).
+                ::lint::Level::Allow |
+                ::lint::Level::Warn => skip_delay_bug = true,
+
+                ::lint::Level::Deny |
+                ::lint::Level::Forbid => {}
+            }
+        }
+
         let mut orig_values = SmallVec::new();
         let key = self.canonicalize_query(&param_env.and(ty), &mut orig_values);
         let result = match self.tcx.global_tcx().implied_outlives_bounds(key) {
             Ok(r) => r,
             Err(NoSolution) => {
-                self.tcx.sess.delay_span_bug(
-                    span,
-                    "implied_outlives_bounds failed to solve all obligations"
-                );
+                if !skip_delay_bug {
+                    self.tcx.sess.delay_span_bug(
+                        cause.span,
+                        "implied_outlives_bounds failed to solve all obligations"
+                    );
+                }
                 return vec![];
             }
         };
         assert!(result.value.is_proven());
 
         let result = self.instantiate_query_result_and_region_obligations(
-            &ObligationCause::misc(span, body_id), param_env, &orig_values, &result);
+            cause, param_env, &orig_values, &result);
         debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result);
         let result = match result {
             Ok(v) => v,
             Err(_) => {
-                self.tcx.sess.delay_span_bug(
-                    span,
-                    "implied_outlives_bounds failed to instantiate"
-                );
+                if !skip_delay_bug {
+                    self.tcx.sess.delay_span_bug(
+                        cause.span,
+                        "implied_outlives_bounds failed to instantiate"
+                    );
+                }
                 return vec![];
             }
         };
@@ -138,10 +154,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
         let mut fulfill_cx = FulfillmentContext::new();
         fulfill_cx.register_predicate_obligations(self, result.obligations);
         if fulfill_cx.select_all_or_error(self).is_err() {
-            self.tcx.sess.delay_span_bug(
-                span,
-                "implied_outlives_bounds failed to solve obligations from instantiation"
-            );
+            if !skip_delay_bug {
+                self.tcx.sess.delay_span_bug(
+                    cause.span,
+                    "implied_outlives_bounds failed to solve obligations from instantiation"
+                );
+            }
         }
 
         result.value
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 85e7368bfdd10..3c880f5d0cc90 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -682,8 +682,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             ty::Predicate::WellFormed(ty) => {
                 match ty::wf::obligations(self.infcx,
                                           obligation.param_env,
-                                          obligation.cause.body_id,
-                                          ty, obligation.cause.span) {
+                                          &obligation.cause,
+                                          ty) {
                     Some(obligations) =>
                         self.evaluate_predicates_recursively(previous_stack, obligations.iter()),
                     None =>
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index b7b0fdca2e634..586020513070a 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -2931,7 +2931,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                                                     hir_id: HirId,
                                                     span: S,
                                                     msg: &str)
-        -> DiagnosticBuilder<'tcx>
+        -> DiagnosticBuilder<'gcx>
     {
         let node_id = self.hir.hir_to_node_id(hir_id);
         let (level, src) = self.lint_level_at_node(lint, node_id);
@@ -2943,14 +2943,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                                                      id: NodeId,
                                                      span: S,
                                                      msg: &str)
-        -> DiagnosticBuilder<'tcx>
+        -> DiagnosticBuilder<'gcx>
     {
         let (level, src) = self.lint_level_at_node(lint, id);
         lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
     }
 
     pub fn struct_lint_node(self, lint: &'static Lint, id: NodeId, msg: &str)
-        -> DiagnosticBuilder<'tcx>
+        -> DiagnosticBuilder<'gcx>
     {
         let (level, src) = self.lint_level_at_node(lint, id);
         lint::struct_lint_level(self.sess, lint, level, src, None, msg)
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index cc0429de2f624..9cd87d07b09a8 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -217,7 +217,7 @@ impl<'tcx> ty::ParamEnv<'tcx> {
                             infringing.push(field);
                         }
                         Err(errors) => {
-                            infcx.report_fulfillment_errors(&errors, None, false);
+                            infcx.report_fulfillment_errors(&errors, false);
                         }
                     };
                 }
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 63206a660df41..c2bad44db4266 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -15,8 +15,6 @@ use ty::subst::Substs;
 use traits;
 use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use std::iter::once;
-use syntax::ast;
-use syntax_pos::Span;
 use middle::lang_items;
 
 /// Returns the set of obligations needed to make `ty` well-formed.
@@ -27,20 +25,15 @@ use middle::lang_items;
 /// say "$0 is WF if $0 is WF".
 pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                    param_env: ty::ParamEnv<'tcx>,
-                                   body_id: ast::NodeId,
-                                   ty: Ty<'tcx>,
-                                   span: Span)
+                                   parent_cause: &traits::ObligationCause<'tcx>,
+                                   ty: Ty<'tcx>)
                                    -> Option<Vec<traits::PredicateObligation<'tcx>>>
 {
-    let mut wf = WfPredicates { infcx,
-                                param_env,
-                                body_id,
-                                span,
-                                out: vec![] };
+    let mut wf = WfPredicates { infcx, param_env, parent_cause, out: vec![] };
     if wf.compute(ty) {
-        debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
+        debug!("wf::obligations({:?}, parent_cause={:?}) = {:?}", ty, parent_cause, wf.out);
         let result = wf.normalize();
-        debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result);
+        debug!("wf::obligations({:?}, parent_cause={:?}) ~~> {:?}", ty, parent_cause, result);
         Some(result)
     } else {
         None // no progress made, return None
@@ -53,24 +46,22 @@ pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
 /// if `Bar: Eq`.
 pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                          param_env: ty::ParamEnv<'tcx>,
-                                         body_id: ast::NodeId,
-                                         trait_ref: &ty::TraitRef<'tcx>,
-                                         span: Span)
+                                         parent_cause: &traits::ObligationCause<'tcx>,
+                                         trait_ref: &ty::TraitRef<'tcx>)
                                          -> Vec<traits::PredicateObligation<'tcx>>
 {
-    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
+    let mut wf = WfPredicates { infcx, param_env, parent_cause, out: vec![] };
     wf.compute_trait_ref(trait_ref, Elaborate::All);
     wf.normalize()
 }
 
 pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                              param_env: ty::ParamEnv<'tcx>,
-                                             body_id: ast::NodeId,
-                                             predicate: &ty::Predicate<'tcx>,
-                                             span: Span)
+                                             parent_cause: &traits::ObligationCause<'tcx>,
+                                             predicate: &ty::Predicate<'tcx>)
                                              -> Vec<traits::PredicateObligation<'tcx>>
 {
-    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
+    let mut wf = WfPredicates { infcx, param_env, parent_cause, out: vec![] };
 
     // (*) ok to skip binders, because wf code is prepared for it
     match *predicate {
@@ -114,8 +105,7 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
 struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    body_id: ast::NodeId,
-    span: Span,
+    parent_cause: &'a traits::ObligationCause<'tcx>,
     out: Vec<traits::PredicateObligation<'tcx>>,
 }
 
@@ -150,7 +140,7 @@ enum Elaborate {
 
 impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
     fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
-        traits::ObligationCause::new(self.span, self.body_id, code)
+        traits::ObligationCause::new(self.parent_cause.span, self.parent_cause.body_id, code)
     }
 
     fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> {
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index bc9cc7274d5e7..ccfd6497243e3 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -1257,7 +1257,7 @@ impl MirPass for QualifyAndPromoteConstants {
                                               tcx.require_lang_item(lang_items::SyncTraitLangItem),
                                               cause);
                 if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
-                    infcx.report_fulfillment_errors(&err, None, false);
+                    infcx.report_fulfillment_errors(&err, false);
                 }
             });
         }
diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs
index 7b31518c07b18..dc35965974570 100644
--- a/src/librustc_traits/implied_outlives_bounds.rs
+++ b/src/librustc_traits/implied_outlives_bounds.rs
@@ -22,7 +22,7 @@ use rustc::ty::query::Providers;
 use rustc::ty::wf;
 use syntax::ast::DUMMY_NODE_ID;
 use syntax::source_map::DUMMY_SP;
-use rustc::traits::FulfillmentContext;
+use rustc::traits::{self, FulfillmentContext};
 
 use rustc_data_structures::sync::Lrc;
 
@@ -73,8 +73,8 @@ fn compute_implied_outlives_bounds<'tcx>(
         // than the ultimate set. (Note: normally there won't be
         // unresolved inference variables here anyway, but there might be
         // during typeck under some circumstances.)
-        let obligations =
-            wf::obligations(infcx, param_env, DUMMY_NODE_ID, ty, DUMMY_SP).unwrap_or(vec![]);
+        let cause = traits::ObligationCause::new(DUMMY_SP, DUMMY_NODE_ID, traits::MiscObligation);
+        let obligations = wf::obligations(infcx, param_env, &cause, ty).unwrap_or(vec![]);
 
         // NB: All of these predicates *ought* to be easily proven
         // true. In fact, their correctness is (mostly) implied by
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index a283e032e0e02..b6a5350275be2 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -17,7 +17,7 @@ use rustc::hir::def_id::DefId;
 use rustc::infer::{InferOk, InferResult};
 use rustc::infer::LateBoundRegionConversionTime;
 use rustc::infer::type_variable::TypeVariableOrigin;
-use rustc::traits::error_reporting::ArgKind;
+use rustc::traits::{self, error_reporting::ArgKind};
 use rustc::ty::{self, ToPolyTraitRef, Ty, GenericParamDefKind};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::Substs;
@@ -667,8 +667,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let liberated_sig = self.tcx()
             .liberate_late_bound_regions(expr_def_id, &bound_sig);
         let liberated_sig = self.inh.normalize_associated_types_in(
-            body.value.span,
-            body.value.id,
+            traits::ObligationCause::misc(body.value.span, body.value.id),
             self.param_env,
             &liberated_sig,
         );
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index a192068d28f20..5657991e79881 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -267,8 +267,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                             infer::HigherRankedType,
                                                             &tcx.fn_sig(impl_m.def_id));
         let impl_sig =
-            inh.normalize_associated_types_in(impl_m_span,
-                                              impl_m_node_id,
+            inh.normalize_associated_types_in(ObligationCause::misc(impl_m_span,
+                                                                    impl_m_node_id),
                                               param_env,
                                               &impl_sig);
         let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig));
@@ -280,8 +280,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let trait_sig =
             trait_sig.subst(tcx, trait_to_skol_substs);
         let trait_sig =
-            inh.normalize_associated_types_in(impl_m_span,
-                                              impl_m_node_id,
+            inh.normalize_associated_types_in(ObligationCause::misc(impl_m_span,
+                                                                    impl_m_node_id),
                                               param_env,
                                               &trait_sig);
         let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig));
@@ -347,14 +347,15 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // Check that all obligations are satisfied by the implementation's
         // version.
         if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
-            infcx.report_fulfillment_errors(errors, None, false);
+            infcx.report_fulfillment_errors(errors, false);
             return Err(ErrorReported);
         }
 
         // Finally, resolve all regions. This catches wily misuses of
         // lifetime parameters.
         let fcx = FnCtxt::new(&inh, param_env, impl_m_node_id);
-        fcx.regionck_item(impl_m_node_id, impl_m_span, &[]);
+        fcx.regionck_item(impl_m_node_id, impl_m_span,
+            ObligationCauseCode::MiscObligation, &[]);
 
         Ok(())
     })
@@ -928,15 +929,15 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id);
 
         // There is no "body" here, so just pass dummy id.
-        let impl_ty = inh.normalize_associated_types_in(impl_c_span,
-                                                        impl_c_node_id,
+        let impl_ty = inh.normalize_associated_types_in(ObligationCause::misc(impl_c_span,
+                                                                              impl_c_node_id),
                                                         param_env,
                                                         &impl_ty);
 
         debug!("compare_const_impl: impl_ty={:?}", impl_ty);
 
-        let trait_ty = inh.normalize_associated_types_in(impl_c_span,
-                                                         impl_c_node_id,
+        let trait_ty = inh.normalize_associated_types_in(ObligationCause::misc(impl_c_span,
+                                                                               impl_c_node_id),
                                                          param_env,
                                                          &trait_ty);
 
@@ -987,11 +988,12 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // Check that all obligations are satisfied by the implementation's
         // version.
         if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
-            infcx.report_fulfillment_errors(errors, None, false);
+            infcx.report_fulfillment_errors(errors, false);
             return;
         }
 
         let fcx = FnCtxt::new(&inh, param_env, impl_c_node_id);
-        fcx.regionck_item(impl_c_node_id, impl_c_span, &[]);
+        fcx.regionck_item(impl_c_node_id, impl_c_span,
+            ObligationCauseCode::MiscObligation, &[]);
     });
 }
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 9d3cbf910e059..6749f509972b7 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -112,7 +112,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
 
         if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
             // this could be reached when we get lazy normalization
-            infcx.report_fulfillment_errors(errors, None, false);
+            infcx.report_fulfillment_errors(errors, false);
             return Err(ErrorReported);
         }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 80df7faf39d22..e1348ee492395 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -225,8 +225,6 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     /// environment is for an item or something where the "callee" is
     /// not clear.
     implicit_region_bound: Option<ty::Region<'tcx>>,
-
-    body_id: Option<hir::BodyId>,
 }
 
 impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
@@ -640,7 +638,6 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
             deferred_generator_interiors: RefCell::new(Vec::new()),
             opaque_types: RefCell::new(DefIdMap()),
             implicit_region_bound,
-            body_id,
         }
     }
 
@@ -668,13 +665,12 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
     }
 
     fn normalize_associated_types_in<T>(&self,
-                                        span: Span,
-                                        body_id: ast::NodeId,
+                                        cause: ObligationCause<'tcx>,
                                         param_env: ty::ParamEnv<'tcx>,
                                         value: &T) -> T
         where T : TypeFoldable<'tcx>
     {
-        let ok = self.partially_normalize_associated_types_in(span, body_id, param_env, value);
+        let ok = self.partially_normalize_associated_types_in(cause, param_env, value);
         self.register_infer_ok_obligations(ok)
     }
 }
@@ -850,8 +846,8 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             let fn_sig =
                 tcx.liberate_late_bound_regions(def_id, &fn_sig);
             let fn_sig =
-                inh.normalize_associated_types_in(body.value.span,
-                                                  body_id.node_id,
+                inh.normalize_associated_types_in(ObligationCause::misc(body.value.span,
+                                                                        body_id.node_id),
                                                   param_env,
                                                   &fn_sig);
 
@@ -2262,17 +2258,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
         where T : TypeFoldable<'tcx>
     {
-        self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value)
+        self.inh.normalize_associated_types_in(
+            ObligationCause::misc(span, self.body_id),
+            self.param_env,
+            value,
+        )
     }
 
     fn normalize_associated_types_in_as_infer_ok<T>(&self, span: Span, value: &T)
                                                     -> InferOk<'tcx, T>
         where T : TypeFoldable<'tcx>
     {
-        self.inh.partially_normalize_associated_types_in(span,
-                                                         self.body_id,
-                                                         self.param_env,
-                                                         value)
+        self.inh.partially_normalize_associated_types_in(
+            ObligationCause::misc(span, self.body_id),
+            self.param_env,
+            value,
+        )
     }
 
     pub fn require_type_meets(&self,
@@ -2433,7 +2434,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn select_all_obligations_or_error(&self) {
         debug!("select_all_obligations_or_error");
         if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {
-            self.report_fulfillment_errors(&errors, self.inh.body_id, false);
+            self.report_fulfillment_errors(&errors, false);
         }
     }
 
@@ -2442,7 +2443,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match self.fulfillment_cx.borrow_mut().select_where_possible(self) {
             Ok(()) => { }
             Err(errors) => {
-                self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
+                self.report_fulfillment_errors(&errors, fallback_has_occurred);
             },
         }
     }
@@ -5262,7 +5263,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             ty
         } else {
             if !self.is_tainted_by_errors() {
-                self.need_type_info_err((**self).body_id, sp, ty)
+                self.need_type_info_err(
+                    &ObligationCause::misc(sp, self.body_id),
+                    ty,
+                )
                     .note("type must be known at this point")
                     .emit();
             }
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index fbf8afc3be234..89d88202336a2 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -88,6 +88,7 @@ use middle::mem_categorization as mc;
 use middle::mem_categorization::Categorization;
 use middle::region;
 use rustc::hir::def_id::DefId;
+use rustc::traits;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty};
 use rustc::infer;
@@ -139,6 +140,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn regionck_item(&self,
                          item_id: ast::NodeId,
                          span: Span,
+                         code: traits::ObligationCauseCode<'tcx>,
                          wf_tys: &[Ty<'tcx>]) {
         debug!("regionck_item(item.id={:?}, wf_tys={:?})", item_id, wf_tys);
         let subject = self.tcx.hir.local_def_id(item_id);
@@ -147,7 +149,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                       item_id,
                                       Subject(subject),
                                       self.param_env);
-        rcx.outlives_environment.add_implied_bounds(self, wf_tys, item_id, span);
+        let cause = traits::ObligationCause::new(span, item_id, code);
+        rcx.outlives_environment.add_implied_bounds(self, wf_tys, &cause);
         rcx.visit_region_obligations(item_id);
         rcx.resolve_regions_and_report_errors();
     }
@@ -334,8 +337,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         self.outlives_environment.add_implied_bounds(
             self.fcx,
             &fn_sig_tys[..],
-            body_id.node_id,
-            span);
+            &traits::ObligationCause::misc(span, body_id.node_id),
+        );
         self.link_fn_args(
             region::Scope {
                 id: body.value.hir_id.local_id,
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 9e09f2cd1851e..002b9a0b8ea7c 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -39,7 +39,7 @@ struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 }
 
 impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
-    fn with_fcx<F>(&'tcx mut self, f: F) where
+    fn with_fcx<F>(&'tcx mut self, code: ObligationCauseCode<'tcx>, f: F) where
         F: for<'b> FnOnce(&FnCtxt<'b, 'gcx, 'tcx>,
                          TyCtxt<'b, 'gcx, 'gcx>) -> Vec<Ty<'tcx>>
     {
@@ -56,7 +56,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
             }
             let wf_tys = f(&fcx, fcx.tcx.global_tcx());
             fcx.select_all_obligations_or_error();
-            fcx.regionck_item(id, span, &wf_tys);
+            fcx.regionck_item(id, span, code, &wf_tys);
         });
     }
 }
@@ -118,11 +118,16 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def
         hir::ItemKind::Fn(..) => {
             check_item_fn(tcx, item);
         }
-        hir::ItemKind::Static(..) => {
-            check_item_type(tcx, item);
-        }
+        hir::ItemKind::Static(..) |
         hir::ItemKind::Const(..) => {
-            check_item_type(tcx, item);
+            for_item(tcx, item).with_fcx(ObligationCauseCode::MiscObligation, |fcx, _this| {
+                let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id));
+                let item_ty = fcx.normalize_associated_types_in(item.span, &ty);
+
+                fcx.register_wf_obligation(item_ty, item.span, ObligationCauseCode::MiscObligation);
+
+                vec![] // no implied bounds in a static/const
+            });
         }
         hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
             check_type_defn(tcx, item, false, |fcx| {
@@ -179,7 +184,7 @@ fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             span: Span,
                             sig_if_method: Option<&hir::MethodSig>) {
     let code = ObligationCauseCode::MiscObligation;
-    for_id(tcx, item_id, span).with_fcx(|fcx, tcx| {
+    for_id(tcx, item_id, span).with_fcx(ObligationCauseCode::MiscObligation, |fcx, tcx| {
         let item = fcx.tcx.associated_item(fcx.tcx.hir.local_def_id(item_id));
 
         let (mut implied_bounds, self_ty) = match item.container {
@@ -240,7 +245,7 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 item: &hir::Item, all_sized: bool, mut lookup_fields: F)
     where F: for<'fcx, 'gcx, 'tcx2> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx2>) -> Vec<AdtVariant<'tcx2>>
 {
-    for_item(tcx, item).with_fcx(|fcx, fcx_tcx| {
+    for_item(tcx, item).with_fcx(ObligationCauseCode::MiscObligation, |fcx, fcx_tcx| {
         let variants = lookup_fields(fcx);
         let def_id = fcx.tcx.hir.local_def_id(item.id);
         let packed = fcx.tcx.adt_def(def_id).repr.packed();
@@ -296,7 +301,8 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
         }
 
-        check_where_clauses(tcx, fcx, item.span, def_id, None);
+        check_where_clauses(tcx, fcx, item.span, def_id, None,
+            traits::ItemObligation(def_id));
 
         vec![] // no implied bounds in a struct def'n
     });
@@ -304,14 +310,15 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) {
     let trait_def_id = tcx.hir.local_def_id(item.id);
-    for_item(tcx, item).with_fcx(|fcx, _| {
-        check_where_clauses(tcx, fcx, item.span, trait_def_id, None);
+    for_item(tcx, item).with_fcx(ObligationCauseCode::MiscObligation, |fcx, _| {
+        check_where_clauses(tcx, fcx, item.span, trait_def_id, None,
+            traits::ItemObligation(trait_def_id));
         vec![]
     });
 }
 
 fn check_item_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) {
-    for_item(tcx, item).with_fcx(|fcx, tcx| {
+    for_item(tcx, item).with_fcx(ObligationCauseCode::MiscObligation, |fcx, tcx| {
         let def_id = fcx.tcx.hir.local_def_id(item.id);
         let sig = fcx.tcx.fn_sig(def_id);
         let sig = fcx.normalize_associated_types_in(item.span, &sig);
@@ -322,21 +329,6 @@ fn check_item_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) {
     })
 }
 
-fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                    item: &hir::Item)
-{
-    debug!("check_item_type: {:?}", item);
-
-    for_item(tcx, item).with_fcx(|fcx, _this| {
-        let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id));
-        let item_ty = fcx.normalize_associated_types_in(item.span, &ty);
-
-        fcx.register_wf_obligation(item_ty, item.span, ObligationCauseCode::MiscObligation);
-
-        vec![] // no implied bounds in a const etc
-    });
-}
-
 fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 item: &hir::Item,
                 ast_self_ty: &hir::Ty,
@@ -344,7 +336,7 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     debug!("check_impl: {:?}", item);
 
-    for_item(tcx, item).with_fcx(|fcx, tcx| {
+    for_item(tcx, item).with_fcx(ObligationCauseCode::MiscObligation, |fcx, tcx| {
         let item_def_id = fcx.tcx.hir.local_def_id(item.id);
 
         match *ast_trait_ref {
@@ -353,12 +345,16 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 let trait_ref =
                     fcx.normalize_associated_types_in(
                         ast_trait_ref.path.span, &trait_ref);
+                let cause = traits::ObligationCause::new(
+                    ast_trait_ref.path.span,
+                    fcx.body_id,
+                    ObligationCauseCode::MiscObligation,
+                );
                 let obligations =
                     ty::wf::trait_obligations(fcx,
                                                 fcx.param_env,
-                                                fcx.body_id,
-                                                &trait_ref,
-                                                ast_trait_ref.path.span);
+                                                &cause,
+                                                &trait_ref);
                 for obligation in obligations {
                     fcx.register_predicate(obligation);
                 }
@@ -371,7 +367,8 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
         }
 
-        check_where_clauses(tcx, fcx, item.span, item_def_id, None);
+        check_where_clauses(tcx, fcx, item.span, item_def_id, None,
+            traits::ItemObligation(item_def_id));
 
         fcx.impl_implied_bounds(item_def_id, item.span)
     });
@@ -384,6 +381,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
     span: Span,
     def_id: DefId,
     return_ty: Option<Ty<'tcx>>,
+    code: traits::ObligationCauseCode<'tcx>,
 ) {
     use ty::subst::Subst;
     use rustc::ty::TypeFoldable;
@@ -448,6 +446,9 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
             }
         }
     });
+
+    let cause = traits::ObligationCause::new(span, fcx.body_id, code);
+
     // Now we build the substituted predicates.
     let default_obligations = predicates.predicates.iter().flat_map(|&pred| {
         struct CountParams { params: FxHashSet<u32> }
@@ -493,8 +494,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
         // below: there, we are not trying to prove those predicates
         // to be *true* but merely *well-formed*.
         let pred = fcx.normalize_associated_types_in(span, &pred);
-        let cause = traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def_id));
-        traits::Obligation::new(cause, fcx.param_env, pred)
+        traits::Obligation::new(cause.clone(), fcx.param_env, pred)
     });
 
     let mut predicates = predicates.instantiate_identity(fcx.tcx);
@@ -511,9 +511,8 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
                     .iter()
                     .flat_map(|p| ty::wf::predicate_obligations(fcx,
                                                                 fcx.param_env,
-                                                                fcx.body_id,
-                                                                p,
-                                                                span));
+                                                                &cause,
+                                                                p));
 
     for obligation in wf_obligations.chain(default_obligations) {
         debug!("next obligation cause: {:?}", obligation.cause);
@@ -541,7 +540,8 @@ fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
     // FIXME(#25759) return types should not be implied bounds
     implied_bounds.push(sig.output());
 
-    check_where_clauses(tcx, fcx, span, def_id, Some(sig.output()));
+    check_where_clauses(tcx, fcx, span, def_id, Some(sig.output()),
+        traits::ItemObligation(def_id));
 }
 
 /// Checks "defining uses" of existential types to ensure that they meet the restrictions laid for
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 0b2f92ac4bcb6..7881152c35e68 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -17,6 +17,7 @@ use rustc::hir;
 use rustc::hir::def_id::{DefId, DefIndex};
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::infer::InferCtxt;
+use rustc::traits;
 use rustc::ty::adjustment::{Adjust, Adjustment};
 use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder};
 use rustc::ty::subst::UnpackedKind;
@@ -738,8 +739,13 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> {
 
     fn report_error(&self, t: Ty<'tcx>) {
         if !self.tcx.sess.has_errors() {
-            self.infcx
-                .need_type_info_err(Some(self.body.id()), self.span.to_span(&self.tcx), t)
+            self.infcx.need_type_info_err(
+                &traits::ObligationCause::misc(
+                    self.span.to_span(&self.tcx),
+                    self.body.id().node_id,
+                ),
+                t,
+            )
                 .emit();
         }
     }
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index efc35fad820c8..722ace8cb9f6a 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -386,7 +386,7 @@ pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>,
 
         // Check that all transitive obligations are satisfied.
         if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
-            infcx.report_fulfillment_errors(&errors, None, false);
+            infcx.report_fulfillment_errors(&errors, false);
         }
 
         // Finally, resolve all regions.
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index c9aa0339dd469..213493e98dd58 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -172,7 +172,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         match fulfill_cx.select_all_or_error(infcx) {
             Ok(()) => true,
             Err(errors) => {
-                infcx.report_fulfillment_errors(&errors, None, false);
+                infcx.report_fulfillment_errors(&errors, false);
                 false
             }
         }
diff --git a/src/test/ui/issues/issue-23046.rs b/src/test/ui/issues/issue-23046.rs
index 670706b7a9adf..ce2758ba2abcd 100644
--- a/src/test/ui/issues/issue-23046.rs
+++ b/src/test/ui/issues/issue-23046.rs
@@ -24,7 +24,7 @@ pub fn let_<'var, VAR, F: for<'v> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>>
 }
 
 fn main() {
-    let ex = |x| { //~ ERROR type annotations needed
+    let ex = |x| {
         let_(add(x,x), |y| {
-            let_(add(x, x), |x|x)})};
+            let_(add(x, x), |x|x)})}; //~ ERROR type annotations needed
 }
diff --git a/src/test/ui/issues/issue-23046.stderr b/src/test/ui/issues/issue-23046.stderr
index 3e5b4ec91d782..01f7de29c5acd 100644
--- a/src/test/ui/issues/issue-23046.stderr
+++ b/src/test/ui/issues/issue-23046.stderr
@@ -1,8 +1,8 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-23046.rs:27:15
+  --> $DIR/issue-23046.rs:29:30
    |
-LL |     let ex = |x| { //~ ERROR type annotations needed
-   |               ^ consider giving this closure parameter a type
+LL |             let_(add(x, x), |x|x)})}; //~ ERROR type annotations needed
+   |                              ^ consider giving this closure parameter a type
 
 error: aborting due to previous error
 

From a33367700efb07f72a063bfc5b96b2ad325669d0 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Mon, 17 Sep 2018 05:50:13 +0300
Subject: [PATCH 2/4] rustc_typeck: check well-formedness of type aliases.

---
 src/Cargo.lock                                | 19 ++++++++---
 src/bootstrap/bin/rustc.rs                    |  5 +++
 src/libgraphviz/lib.rs                        |  6 ++--
 src/librustc/infer/canonical/mod.rs           |  8 +++--
 src/librustc/lint/builtin.rs                  |  7 ++++
 src/librustc/traits/error_reporting.rs        | 14 ++++++++
 src/librustc/traits/mod.rs                    |  4 +++
 src/librustc/traits/structural_impls.rs       |  3 ++
 src/librustc/ty/wf.rs                         |  9 +++++
 src/librustc_data_structures/Cargo.toml       |  2 +-
 src/librustc_data_structures/indexed_vec.rs   |  3 +-
 src/librustc_mir/util/liveness.rs             |  3 +-
 src/librustc_typeck/check/wfcheck.rs          | 16 +++++++++
 src/test/rustdoc/assoc-item-cast.rs           |  4 +--
 src/test/rustdoc/const-evalutation-ice.rs     |  1 +
 .../consts/const-eval/pub_const_err-warn.rs   | 17 ++++++++++
 .../const-eval/pub_const_err-warn.stderr      | 14 ++++++++
 .../ui/consts/const-eval/pub_const_err.rs     | 10 ++----
 .../ui/consts/const-eval/pub_const_err.stderr | 34 ++++++++-----------
 .../const-eval/pub_const_err_bin-warn.rs      | 17 ++++++++++
 .../const-eval/pub_const_err_bin-warn.stderr  | 14 ++++++++
 .../ui/consts/const-eval/pub_const_err_bin.rs | 10 ++----
 .../const-eval/pub_const_err_bin.stderr       | 34 ++++++++-----------
 .../feature-gate-trivial_bounds.rs            |  2 +-
 .../feature-gate-trivial_bounds.stderr        | 11 +++++-
 src/test/ui/hygiene/assoc_ty_bindings.rs      |  8 ++---
 src/test/ui/regions/regions-enum-not-wf.rs    |  2 +-
 .../ui/regions/regions-enum-not-wf.stderr     | 16 ++++++++-
 src/test/ui/resolve/issue-3907-2.rs           |  1 +
 src/test/ui/resolve/issue-3907-2.stderr       | 14 ++++++--
 .../regions-enum-not-wf.rs                    |  2 +-
 .../regions-enum-not-wf.stderr                | 16 ++++++++-
 .../ui/structs/struct-path-alias-bounds.rs    |  2 +-
 .../structs/struct-path-alias-bounds.stderr   | 17 ++++------
 src/test/ui/type/issue-51626.rs               | 23 +++++++++++++
 src/test/ui/type/issue-51626.stderr           | 22 ++++++++++++
 src/test/ui/type/type-alias-bounds-err.rs     | 25 ++++++++++++++
 src/test/ui/type/type-alias-bounds-err.stderr | 24 +++++++++++++
 src/test/ui/type/type-alias-bounds.rs         |  6 ++--
 39 files changed, 350 insertions(+), 95 deletions(-)
 create mode 100644 src/test/ui/consts/const-eval/pub_const_err-warn.rs
 create mode 100644 src/test/ui/consts/const-eval/pub_const_err-warn.stderr
 create mode 100644 src/test/ui/consts/const-eval/pub_const_err_bin-warn.rs
 create mode 100644 src/test/ui/consts/const-eval/pub_const_err_bin-warn.stderr
 create mode 100644 src/test/ui/type/issue-51626.rs
 create mode 100644 src/test/ui/type/issue-51626.stderr
 create mode 100644 src/test/ui/type/type-alias-bounds-err.rs
 create mode 100644 src/test/ui/type/type-alias-bounds-err.stderr

diff --git a/src/Cargo.lock b/src/Cargo.lock
index 5ac838cadc2a4..89d326222cf42 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -250,7 +250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "chalk-engine"
-version = "0.7.0"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -643,6 +643,14 @@ dependencies = [
  "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "ena"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "env_logger"
 version = "0.5.12"
@@ -1864,7 +1872,7 @@ dependencies = [
  "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chalk-engine 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "fmt_macros 0.0.0",
  "graphviz 0.0.0",
@@ -2130,7 +2138,7 @@ name = "rustc_data_structures"
 version = "0.0.0"
 dependencies = [
  "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ena 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2392,7 +2400,7 @@ name = "rustc_traits"
 version = "0.0.0"
 dependencies = [
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chalk-engine 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "graphviz 0.0.0",
  "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
@@ -3146,7 +3154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1"
 "checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
 "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
-"checksum chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "25ce2f28f55ed544a2a3756b7acf41dd7d6f27acffb2086439950925506af7d0"
+"checksum chalk-engine 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "217042da49c0c0655bbc4aa9f9bed20c7a599429faddc9b2ef3bd09a2769d3ef"
 "checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e"
 "checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37"
 "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
@@ -3176,6 +3184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
 "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
 "checksum elasticlunr-rs 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4837d77a1e157489a3933b743fd774ae75074e0e390b2b7f071530048a0d87ee"
+"checksum ena 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "25b4e5febb25f08c49f1b07dc33a182729a6b21edfb562b5aef95f78e0dbe5bb"
 "checksum ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dc8393b3c7352f94092497f6b52019643e493b6b890eb417cdb7c46117e621"
 "checksum env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f4d7e69c283751083d53d01eac767407343b8b69c4bd70058e08adc2637cb257"
 "checksum environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4b14e20978669064c33b4c1e0fb4083412e40fe56cbea2eae80fd7591503ee"
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index f30f34acf5c6c..2b8643615d4ab 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -304,6 +304,11 @@ fn main() {
     {
         cmd.arg("-Dwarnings");
         cmd.arg("-Dbare_trait_objects");
+        if !(stage == "0" || target.is_none() && version.is_none()) {
+            // HACK(eddyb) allow bootstrapping while we're testing with
+            // the lint on `deny` by default. Remove before merging.
+            cmd.arg("-Atype_alias_missing_bounds");
+        }
     }
 
     if verbose > 1 {
diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs
index 9fa48adebdf07..56394b1b07e34 100644
--- a/src/libgraphviz/lib.rs
+++ b/src/libgraphviz/lib.rs
@@ -574,8 +574,10 @@ impl<'a> LabelText<'a> {
     }
 }
 
-pub type Nodes<'a,N> = Cow<'a,[N]>;
-pub type Edges<'a,E> = Cow<'a,[E]>;
+#[allow(type_alias_bounds)]
+pub type Nodes<'a,N: Clone> = Cow<'a,[N]>;
+#[allow(type_alias_bounds)]
+pub type Edges<'a,E: Clone> = Cow<'a,[E]>;
 
 // (The type parameters in GraphWalk should be associated items,
 // when/if Rust supports such.)
diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs
index 85aa4f62f214c..e2424b5128db6 100644
--- a/src/librustc/infer/canonical/mod.rs
+++ b/src/librustc/infer/canonical/mod.rs
@@ -128,10 +128,12 @@ pub struct QueryResult<'tcx, R> {
     pub value: R,
 }
 
-pub type Canonicalized<'gcx, V> = Canonical<'gcx, <V as Lift<'gcx>>::Lifted>;
+#[allow(type_alias_bounds)]
+pub type Canonicalized<'gcx, V: Lift<'gcx>> = Canonical<'gcx, V::Lifted>;
 
-pub type CanonicalizedQueryResult<'gcx, T> =
-    Lrc<Canonical<'gcx, QueryResult<'gcx, <T as Lift<'gcx>>::Lifted>>>;
+#[allow(type_alias_bounds)]
+pub type CanonicalizedQueryResult<'gcx, T: Lift<'gcx>> =
+    Lrc<Canonical<'gcx, QueryResult<'gcx, T::Lifted>>>;
 
 /// Indicates whether or not we were able to prove the query to be
 /// true.
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index e6452ad09278e..87877a087e78a 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -338,6 +338,12 @@ declare_lint! {
      cannot be referred to by absolute paths"
 }
 
+declare_lint! {
+    pub TYPE_ALIAS_MISSING_BOUNDS,
+    Deny,
+    "type aliases missing bounds required by the type being aliased, are now deprecated"
+}
+
 /// Some lints that are buffered from `libsyntax`. See `syntax::early_buffered_lints`.
 pub mod parser {
     declare_lint! {
@@ -406,6 +412,7 @@ impl LintPass for HardwiredLints {
             PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
             MACRO_USE_EXTERN_CRATE,
             MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
+            TYPE_ALIAS_MISSING_BOUNDS,
             parser::QUESTION_MARK_MACRO_SEP,
         )
     }
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 8602e7563b8bd..6c04ec12e73e5 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -584,6 +584,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             ObligationCauseCode::ImplDerivedObligation(data) => {
                 self.get_lint_from_cause_code(&data.parent_code)
             }
+            &ObligationCauseCode::TypeAliasMissingBound(id) => {
+                if self.tcx.sess.rust_2018() {
+                    // Error since Rust 2018.
+                    None
+                } else {
+                    Some((::lint::builtin::TYPE_ALIAS_MISSING_BOUNDS, id))
+                }
+            }
             _ => None,
         }
     }
@@ -1612,6 +1620,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     );
                 }
             }
+            ObligationCauseCode::TypeAliasMissingBound(_) => {
+                err.help("missing bounds in type aliases were previously allowed");
+                if !self.tcx.sess.rust_2018() {
+                    err.help("this is a hard error in Rust 2018");
+                }
+            }
         }
     }
 
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 485d8041c5ee1..f172690de53e8 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -251,6 +251,10 @@ pub enum ObligationCauseCode<'tcx> {
 
     /// #[feature(trivial_bounds)] is not enabled
     TrivialBound,
+
+    /// `type` alias is missing bounds required by the type being aliased
+    /// (lint in Rust 2015, error since Rust 2018).
+    TypeAliasMissingBound(ast::NodeId),
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 10e930d1c92d9..7748abd466dc0 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -238,6 +238,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
             super::MethodReceiver => Some(super::MethodReceiver),
             super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
             super::TrivialBound => Some(super::TrivialBound),
+            super::ObligationCauseCode::TypeAliasMissingBound(id) => {
+                Some(super::ObligationCauseCode::TypeAliasMissingBound(id))
+            }
         }
     }
 }
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index c2bad44db4266..aa286a33cd295 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -140,6 +140,15 @@ enum Elaborate {
 
 impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
     fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
+        let code = match self.parent_cause.code {
+            traits::ObligationCauseCode::TypeAliasMissingBound(_) => {
+                // FIXME(eddyb) We're not chaining obligation causes here,
+                // so in the case of cause codes that turn errors into lints,
+                // we have to replace our cause `code` with the parent one.
+                self.parent_cause.code.clone()
+            }
+            _ => code,
+        };
         traits::ObligationCause::new(self.parent_cause.span, self.parent_cause.body_id, code)
     }
 
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index 5a72fde6a2c8a..b888fa412a6a3 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -9,7 +9,7 @@ path = "lib.rs"
 crate-type = ["dylib"]
 
 [dependencies]
-ena = "0.9.3"
+ena = "0.10.1"
 log = "0.4"
 rustc_cratesio_shim = { path = "../librustc_cratesio_shim" }
 serialize = { path = "../libserialize" }
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
index 2f11fea46d69a..d22b408c09fa1 100644
--- a/src/librustc_data_structures/indexed_vec.rs
+++ b/src/librustc_data_structures/indexed_vec.rs
@@ -486,7 +486,8 @@ impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexVec<I, T> {
     }
 }
 
-pub type Enumerated<I, J> = iter::Map<iter::Enumerate<J>, IntoIdx<I>>;
+#[allow(type_alias_bounds)]
+pub type Enumerated<I: Idx, J> = iter::Map<iter::Enumerate<J>, IntoIdx<I>>;
 
 impl<I: Idx, T> IndexVec<I, T> {
     #[inline]
diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs
index 420ca4efde37d..701c6a34777f7 100644
--- a/src/librustc_mir/util/liveness.rs
+++ b/src/librustc_mir/util/liveness.rs
@@ -46,7 +46,8 @@ use std::path::{Path, PathBuf};
 use transform::MirSource;
 use util::pretty::{dump_enabled, write_basic_block, write_mir_intro};
 
-pub type LiveVarSet<V> = BitSet<V>;
+#[allow(type_alias_bounds)]
+pub type LiveVarSet<V: Idx> = BitSet<V>;
 
 /// This gives the result of the liveness analysis at the boundary of
 /// basic blocks.
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 002b9a0b8ea7c..b9eec5a1f6458 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -129,6 +129,22 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def
                 vec![] // no implied bounds in a static/const
             });
         }
+        hir::ItemKind::Ty(ref hir_ty, _) => {
+            let code = ObligationCauseCode::TypeAliasMissingBound(item.id);
+            for_item(tcx, item).with_fcx(code.clone(), |fcx, _this| {
+                let cause = traits::ObligationCause::new(hir_ty.span, fcx.body_id, code.clone());
+
+                let def_id = fcx.tcx.hir.local_def_id(item.id);
+                let ty = fcx.tcx.type_of(def_id);
+                let item_ty = fcx.inh.normalize_associated_types_in(cause, fcx.param_env, &ty);
+
+                fcx.register_wf_obligation(item_ty, hir_ty.span, code.clone());
+
+                check_where_clauses(tcx, fcx, item.span, def_id, None, code);
+
+                vec![item_ty]
+            });
+        }
         hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
             check_type_defn(tcx, item, false, |fcx| {
                 vec![fcx.non_enum_variant(struct_def)]
diff --git a/src/test/rustdoc/assoc-item-cast.rs b/src/test/rustdoc/assoc-item-cast.rs
index 24f31b5b1040b..f136b6efb5372 100644
--- a/src/test/rustdoc/assoc-item-cast.rs
+++ b/src/test/rustdoc/assoc-item-cast.rs
@@ -22,5 +22,5 @@ pub trait AsExpression<T> {
 }
 
 // @has foo/type.AsExprOf.html
-// @has - '//*[@class="rust typedef"]' 'type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;'
-pub type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;
+// @has - '//*[@class="rust typedef"]' 'type AsExprOf<Item: AsExpression<Type>, Type> = <Item as AsExpression<Type>>::Expression;'
+pub type AsExprOf<Item: AsExpression<Type>, Type> = <Item as AsExpression<Type>>::Expression;
diff --git a/src/test/rustdoc/const-evalutation-ice.rs b/src/test/rustdoc/const-evalutation-ice.rs
index 000ed709a8aae..d9d12ce38f1e8 100644
--- a/src/test/rustdoc/const-evalutation-ice.rs
+++ b/src/test/rustdoc/const-evalutation-ice.rs
@@ -17,4 +17,5 @@ pub struct S {
     s: Cell<usize>
 }
 
+#[allow(type_alias_missing_bounds)] // HACK(eddyb) remove before merge
 pub type _S = [usize; 0 - (mem::size_of::<S>() != 4) as usize];
diff --git a/src/test/ui/consts/const-eval/pub_const_err-warn.rs b/src/test/ui/consts/const-eval/pub_const_err-warn.rs
new file mode 100644
index 0000000000000..58e888d5dfa97
--- /dev/null
+++ b/src/test/ui/consts/const-eval/pub_const_err-warn.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 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.
+
+// compile-pass
+#![warn(const_err)]
+
+#![crate_type = "lib"]
+
+pub const Z: u32 = 0 - 1;
+//~^ WARN this constant cannot be used
diff --git a/src/test/ui/consts/const-eval/pub_const_err-warn.stderr b/src/test/ui/consts/const-eval/pub_const_err-warn.stderr
new file mode 100644
index 0000000000000..997b23bfeaed9
--- /dev/null
+++ b/src/test/ui/consts/const-eval/pub_const_err-warn.stderr
@@ -0,0 +1,14 @@
+warning: this constant cannot be used
+  --> $DIR/pub_const_err-warn.rs:16:1
+   |
+LL | pub const Z: u32 = 0 - 1;
+   | ^^^^^^^^^^^^^^^^^^^-----^
+   |                    |
+   |                    attempt to subtract with overflow
+   |
+note: lint level defined here
+  --> $DIR/pub_const_err-warn.rs:12:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+
diff --git a/src/test/ui/consts/const-eval/pub_const_err.rs b/src/test/ui/consts/const-eval/pub_const_err.rs
index b7cfa949bac95..92e95c5de8fb6 100644
--- a/src/test/ui/consts/const-eval/pub_const_err.rs
+++ b/src/test/ui/consts/const-eval/pub_const_err.rs
@@ -8,14 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-pass
-#![warn(const_err)]
-
 #![crate_type = "lib"]
 
-pub const Z: u32 = 0 - 1;
-//~^ WARN this constant cannot be used
-
 pub type Foo = [i32; 0 - 1];
-//~^ WARN attempt to subtract with overflow
-//~| WARN this array length cannot be used
+//~^ ERROR could not evaluate constant expression
+//~| attempt to subtract with overflow
diff --git a/src/test/ui/consts/const-eval/pub_const_err.stderr b/src/test/ui/consts/const-eval/pub_const_err.stderr
index fa3a79a5f1790..da2a4409392cf 100644
--- a/src/test/ui/consts/const-eval/pub_const_err.stderr
+++ b/src/test/ui/consts/const-eval/pub_const_err.stderr
@@ -1,26 +1,22 @@
-warning: this constant cannot be used
-  --> $DIR/pub_const_err.rs:16:1
-   |
-LL | pub const Z: u32 = 0 - 1;
-   | ^^^^^^^^^^^^^^^^^^^-----^
-   |                    |
-   |                    attempt to subtract with overflow
-   |
-note: lint level defined here
-  --> $DIR/pub_const_err.rs:12:9
-   |
-LL | #![warn(const_err)]
-   |         ^^^^^^^^^
-
-warning: attempt to subtract with overflow
-  --> $DIR/pub_const_err.rs:19:22
+error: attempt to subtract with overflow
+  --> $DIR/pub_const_err.rs:13:22
    |
 LL | pub type Foo = [i32; 0 - 1];
    |                      ^^^^^
+   |
+   = note: #[deny(const_err)] on by default
 
-warning: this array length cannot be used
-  --> $DIR/pub_const_err.rs:19:22
+error: could not evaluate constant expression
+  --> $DIR/pub_const_err.rs:13:16
    |
 LL | pub type Foo = [i32; 0 - 1];
-   |                      ^^^^^ attempt to subtract with overflow
+   |                ^^^^^^-----^
+   |                      |
+   |                      attempt to subtract with overflow
+   |
+   = note: #[deny(type_alias_missing_bounds)] on by default
+   = help: missing bounds in type aliases were previously allowed
+   = help: this is a hard error in Rust 2018
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin-warn.rs b/src/test/ui/consts/const-eval/pub_const_err_bin-warn.rs
new file mode 100644
index 0000000000000..5a035711f8647
--- /dev/null
+++ b/src/test/ui/consts/const-eval/pub_const_err_bin-warn.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 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.
+
+// compile-pass
+#![warn(const_err)]
+
+pub const Z: u32 = 0 - 1;
+//~^ WARN this constant cannot be used
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin-warn.stderr b/src/test/ui/consts/const-eval/pub_const_err_bin-warn.stderr
new file mode 100644
index 0000000000000..db0bf9e5fe679
--- /dev/null
+++ b/src/test/ui/consts/const-eval/pub_const_err_bin-warn.stderr
@@ -0,0 +1,14 @@
+warning: this constant cannot be used
+  --> $DIR/pub_const_err_bin-warn.rs:14:1
+   |
+LL | pub const Z: u32 = 0 - 1;
+   | ^^^^^^^^^^^^^^^^^^^-----^
+   |                    |
+   |                    attempt to subtract with overflow
+   |
+note: lint level defined here
+  --> $DIR/pub_const_err_bin-warn.rs:12:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+
diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.rs b/src/test/ui/consts/const-eval/pub_const_err_bin.rs
index bafa5b2f4da12..ad11ae255eaa6 100644
--- a/src/test/ui/consts/const-eval/pub_const_err_bin.rs
+++ b/src/test/ui/consts/const-eval/pub_const_err_bin.rs
@@ -8,14 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-pass
-#![warn(const_err)]
-
-pub const Z: u32 = 0 - 1;
-//~^ WARN this constant cannot be used
-
 pub type Foo = [i32; 0 - 1];
-//~^ WARN attempt to subtract with overflow
-//~| WARN this array length cannot be used
+//~^ ERROR could not evaluate constant expression
+//~| attempt to subtract with overflow
 
 fn main() {}
diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr
index 73229c60d14db..3e36a0afff27e 100644
--- a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr
+++ b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr
@@ -1,26 +1,22 @@
-warning: this constant cannot be used
-  --> $DIR/pub_const_err_bin.rs:14:1
-   |
-LL | pub const Z: u32 = 0 - 1;
-   | ^^^^^^^^^^^^^^^^^^^-----^
-   |                    |
-   |                    attempt to subtract with overflow
-   |
-note: lint level defined here
-  --> $DIR/pub_const_err_bin.rs:12:9
-   |
-LL | #![warn(const_err)]
-   |         ^^^^^^^^^
-
-warning: attempt to subtract with overflow
-  --> $DIR/pub_const_err_bin.rs:17:22
+error: attempt to subtract with overflow
+  --> $DIR/pub_const_err_bin.rs:11:22
    |
 LL | pub type Foo = [i32; 0 - 1];
    |                      ^^^^^
+   |
+   = note: #[deny(const_err)] on by default
 
-warning: this array length cannot be used
-  --> $DIR/pub_const_err_bin.rs:17:22
+error: could not evaluate constant expression
+  --> $DIR/pub_const_err_bin.rs:11:16
    |
 LL | pub type Foo = [i32; 0 - 1];
-   |                      ^^^^^ attempt to subtract with overflow
+   |                ^^^^^^-----^
+   |                      |
+   |                      attempt to subtract with overflow
+   |
+   = note: #[deny(type_alias_missing_bounds)] on by default
+   = help: missing bounds in type aliases were previously allowed
+   = help: this is a hard error in Rust 2018
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs b/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs
index dba66e0b69bfc..c7e9155fc9fca 100644
--- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs
+++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.rs
@@ -25,7 +25,7 @@ trait T where i32: Foo {} //~ ERROR
 
 union U where i32: Foo { f: i32 } //~ ERROR
 
-type Y where i32: Foo = (); // OK - bound is ignored
+type Y where i32: Foo = (); //~ ERROR
 
 impl Foo for () where i32: Foo { //~ ERROR
     fn test(&self) {
diff --git a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr
index f20c1ebb37aa9..9d43b6cc79d57 100644
--- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr
+++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr
@@ -34,6 +34,15 @@ LL | union U where i32: Foo { f: i32 } //~ ERROR
    = 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:28:1
+   |
+LL | type Y 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:30:1
    |
@@ -125,6 +134,6 @@ LL | | }
    = help: see issue #48214
    = help: add #![feature(trivial_bounds)] to the crate attributes to enable
 
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hygiene/assoc_ty_bindings.rs b/src/test/ui/hygiene/assoc_ty_bindings.rs
index 46a138749ff17..e0a04c43da5e5 100644
--- a/src/test/ui/hygiene/assoc_ty_bindings.rs
+++ b/src/test/ui/hygiene/assoc_ty_bindings.rs
@@ -15,10 +15,10 @@
 
 trait Base {
     type AssocTy;
-    fn f();
+    fn f(&self);
 }
 trait Derived: Base {
-    fn g();
+    fn g(&self);
 }
 
 macro mac() {
@@ -27,12 +27,12 @@ macro mac() {
 
     impl Base for u8 {
         type AssocTy = u8;
-        fn f() {
+        fn f(&self) {
             let _: Self::AssocTy;
         }
     }
     impl Derived for u8 {
-        fn g() {
+        fn g(&self) {
             let _: Self::AssocTy;
         }
     }
diff --git a/src/test/ui/regions/regions-enum-not-wf.rs b/src/test/ui/regions/regions-enum-not-wf.rs
index a2d3cf6779f17..524a07de80d4f 100644
--- a/src/test/ui/regions/regions-enum-not-wf.rs
+++ b/src/test/ui/regions/regions-enum-not-wf.rs
@@ -22,7 +22,7 @@ where T: 'a
 {
   type Out = ();
 }
-type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out;
+type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out; //~ ERROR the parameter type `T` may not live long enough
 
 enum Ref1<'a, T> {
     Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough
diff --git a/src/test/ui/regions/regions-enum-not-wf.stderr b/src/test/ui/regions/regions-enum-not-wf.stderr
index 923ea17622ac0..384bb6a8748b5 100644
--- a/src/test/ui/regions/regions-enum-not-wf.stderr
+++ b/src/test/ui/regions/regions-enum-not-wf.stderr
@@ -1,3 +1,17 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/regions-enum-not-wf.rs:25:31
+   |
+LL | type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out; //~ ERROR the parameter type `T` may not live long enough
+   |                          -    ^^^^^^^^^^^^^^^^^^^^^
+   |                          |
+   |                          help: consider adding an explicit lifetime bound `T: 'a`...
+   |
+note: ...so that the type `T` will meet its required lifetime bounds
+  --> $DIR/regions-enum-not-wf.rs:25:31
+   |
+LL | type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out; //~ ERROR the parameter type `T` may not live long enough
+   |                               ^^^^^^^^^^^^^^^^^^^^^
+
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-enum-not-wf.rs:28:18
    |
@@ -62,6 +76,6 @@ note: ...so that the type `T` will meet its required lifetime bounds
 LL |     RefDoubleVariant1(&'a RequireOutlives<'b, T>)
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/resolve/issue-3907-2.rs b/src/test/ui/resolve/issue-3907-2.rs
index 130647966f2d1..7a76e020da521 100644
--- a/src/test/ui/resolve/issue-3907-2.rs
+++ b/src/test/ui/resolve/issue-3907-2.rs
@@ -12,6 +12,7 @@
 extern crate issue_3907;
 
 type Foo = issue_3907::Foo+'static;
+//~^ ERROR E0038
 
 struct S {
     name: isize
diff --git a/src/test/ui/resolve/issue-3907-2.stderr b/src/test/ui/resolve/issue-3907-2.stderr
index 567fd31b09ca3..8a61415aae6e5 100644
--- a/src/test/ui/resolve/issue-3907-2.stderr
+++ b/src/test/ui/resolve/issue-3907-2.stderr
@@ -1,11 +1,21 @@
 error[E0038]: the trait `issue_3907::Foo` cannot be made into an object
-  --> $DIR/issue-3907-2.rs:20:1
+  --> $DIR/issue-3907-2.rs:14:12
+   |
+LL | type Foo = issue_3907::Foo+'static;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^ the trait `issue_3907::Foo` cannot be made into an object
+   |
+   = note: method `bar` has no receiver
+   = help: missing bounds in type aliases were previously allowed
+   = help: this is a hard error in Rust 2018
+
+error[E0038]: the trait `issue_3907::Foo` cannot be made into an object
+  --> $DIR/issue-3907-2.rs:21:1
    |
 LL | fn bar(_x: Foo) {}
    | ^^^^^^^^^^^^^^^ the trait `issue_3907::Foo` cannot be made into an object
    |
    = note: method `bar` has no receiver
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs
index a2d3cf6779f17..524a07de80d4f 100644
--- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs
@@ -22,7 +22,7 @@ where T: 'a
 {
   type Out = ();
 }
-type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out;
+type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out; //~ ERROR the parameter type `T` may not live long enough
 
 enum Ref1<'a, T> {
     Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough
diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
index 923ea17622ac0..384bb6a8748b5 100644
--- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
@@ -1,3 +1,17 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/regions-enum-not-wf.rs:25:31
+   |
+LL | type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out; //~ ERROR the parameter type `T` may not live long enough
+   |                          -    ^^^^^^^^^^^^^^^^^^^^^
+   |                          |
+   |                          help: consider adding an explicit lifetime bound `T: 'a`...
+   |
+note: ...so that the type `T` will meet its required lifetime bounds
+  --> $DIR/regions-enum-not-wf.rs:25:31
+   |
+LL | type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out; //~ ERROR the parameter type `T` may not live long enough
+   |                               ^^^^^^^^^^^^^^^^^^^^^
+
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-enum-not-wf.rs:28:18
    |
@@ -62,6 +76,6 @@ note: ...so that the type `T` will meet its required lifetime bounds
 LL |     RefDoubleVariant1(&'a RequireOutlives<'b, T>)
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/structs/struct-path-alias-bounds.rs b/src/test/ui/structs/struct-path-alias-bounds.rs
index 1b6e51e37034e..d41cb9694761b 100644
--- a/src/test/ui/structs/struct-path-alias-bounds.rs
+++ b/src/test/ui/structs/struct-path-alias-bounds.rs
@@ -14,8 +14,8 @@ struct S<T: Clone> { a: T }
 
 struct NoClone;
 type A = S<NoClone>;
+//~^ ERROR the trait bound `NoClone: std::clone::Clone` is not satisfied
 
 fn main() {
     let s = A { a: NoClone };
-    //~^ ERROR the trait bound `NoClone: std::clone::Clone` is not satisfied
 }
diff --git a/src/test/ui/structs/struct-path-alias-bounds.stderr b/src/test/ui/structs/struct-path-alias-bounds.stderr
index f8e2fe1410f6c..8ed4282b66a0d 100644
--- a/src/test/ui/structs/struct-path-alias-bounds.stderr
+++ b/src/test/ui/structs/struct-path-alias-bounds.stderr
@@ -1,15 +1,12 @@
-error[E0277]: the trait bound `NoClone: std::clone::Clone` is not satisfied
-  --> $DIR/struct-path-alias-bounds.rs:19:13
+error: the trait bound `NoClone: std::clone::Clone` is not satisfied
+  --> $DIR/struct-path-alias-bounds.rs:16:10
    |
-LL |     let s = A { a: NoClone };
-   |             ^ the trait `std::clone::Clone` is not implemented for `NoClone`
+LL | type A = S<NoClone>;
+   |          ^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `NoClone`
    |
-note: required by `S`
-  --> $DIR/struct-path-alias-bounds.rs:13:1
-   |
-LL | struct S<T: Clone> { a: T }
-   | ^^^^^^^^^^^^^^^^^^
+   = note: #[deny(type_alias_missing_bounds)] on by default
+   = help: missing bounds in type aliases were previously allowed
+   = help: this is a hard error in Rust 2018
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type/issue-51626.rs b/src/test/ui/type/issue-51626.rs
new file mode 100644
index 0000000000000..f8c7a5f6b14f7
--- /dev/null
+++ b/src/test/ui/type/issue-51626.rs
@@ -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.
+
+pub trait Trait {}
+
+pub struct Foo<T: Trait>(T);
+
+pub struct Qux;
+
+pub type Bar<T = Qux> = Foo<T>;
+//~^ ERROR the trait bound `T: Trait` is not satisfied
+
+pub type Baz<T: Trait = Qux> = Foo<T>;
+//~^ ERROR the trait bound `Qux: Trait` is not satisfied
+
+fn main() {}
diff --git a/src/test/ui/type/issue-51626.stderr b/src/test/ui/type/issue-51626.stderr
new file mode 100644
index 0000000000000..7debf69fa196a
--- /dev/null
+++ b/src/test/ui/type/issue-51626.stderr
@@ -0,0 +1,22 @@
+error: the trait bound `T: Trait` is not satisfied
+  --> $DIR/issue-51626.rs:17:25
+   |
+LL | pub type Bar<T = Qux> = Foo<T>;
+   |                         ^^^^^^ the trait `Trait` is not implemented for `T`
+   |
+   = note: #[deny(type_alias_missing_bounds)] on by default
+   = help: consider adding a `where T: Trait` bound
+   = help: missing bounds in type aliases were previously allowed
+   = help: this is a hard error in Rust 2018
+
+error: the trait bound `Qux: Trait` is not satisfied
+  --> $DIR/issue-51626.rs:20:1
+   |
+LL | pub type Baz<T: Trait = Qux> = Foo<T>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `Qux`
+   |
+   = help: missing bounds in type aliases were previously allowed
+   = help: this is a hard error in Rust 2018
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/type/type-alias-bounds-err.rs b/src/test/ui/type/type-alias-bounds-err.rs
new file mode 100644
index 0000000000000..6676561bcbf7a
--- /dev/null
+++ b/src/test/ui/type/type-alias-bounds-err.rs
@@ -0,0 +1,25 @@
+// 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.
+
+#![allow(dead_code)]
+
+// This test contains examples originally in `type-alias-bounds.rs`,
+// that now produce errors instead of being silently accepted.
+
+// Bounds are not checked either, i.e. the definition is not necessarily well-formed
+struct Sendable<T: Send>(T);
+type MySendable<T> = Sendable<T>;
+//~^ ERROR `T` cannot be sent between threads safely
+
+trait Bound { type Assoc; }
+type T4<U> = <U as Bound>::Assoc;
+//~^ ERROR the trait bound `U: Bound` is not satisfied
+
+fn main() {}
diff --git a/src/test/ui/type/type-alias-bounds-err.stderr b/src/test/ui/type/type-alias-bounds-err.stderr
new file mode 100644
index 0000000000000..342a58661a48d
--- /dev/null
+++ b/src/test/ui/type/type-alias-bounds-err.stderr
@@ -0,0 +1,24 @@
+error: `T` cannot be sent between threads safely
+  --> $DIR/type-alias-bounds-err.rs:18:22
+   |
+LL | type MySendable<T> = Sendable<T>;
+   |                      ^^^^^^^^^^^ `T` cannot be sent between threads safely
+   |
+   = note: #[deny(type_alias_missing_bounds)] on by default
+   = help: the trait `std::marker::Send` is not implemented for `T`
+   = help: consider adding a `where T: std::marker::Send` bound
+   = help: missing bounds in type aliases were previously allowed
+   = help: this is a hard error in Rust 2018
+
+error: the trait bound `U: Bound` is not satisfied
+  --> $DIR/type-alias-bounds-err.rs:22:14
+   |
+LL | type T4<U> = <U as Bound>::Assoc;
+   |              ^^^^^^^^^^^^^^^^^^^ the trait `Bound` is not implemented for `U`
+   |
+   = help: consider adding a `where U: Bound` bound
+   = help: missing bounds in type aliases were previously allowed
+   = help: this is a hard error in Rust 2018
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/type/type-alias-bounds.rs b/src/test/ui/type/type-alias-bounds.rs
index a17bb9e952d3c..60171251f8aeb 100644
--- a/src/test/ui/type/type-alias-bounds.rs
+++ b/src/test/ui/type/type-alias-bounds.rs
@@ -49,8 +49,8 @@ fn foo<'a>(y: &'a i32) {
 }
 
 // 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!
+// struct Sendable<T: Send>(T); // NOTE(eddyb) moved to `type-alias-bounds-err.rs`
+// type MySendable<T> = Sendable<T>; // no error here!
 
 // However, bounds *are* taken into account when accessing associated types
 trait Bound { type Assoc; }
@@ -60,7 +60,7 @@ 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;
+// type T4<U> = <U as Bound>::Assoc; // NOTE(eddyb) moved to `type-alias-bounds-err.rs`
 
 // 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

From e243158e59cb9838266e15a227f789111d6564bf Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Thu, 20 Sep 2018 17:17:03 +0300
Subject: [PATCH 3/4] rustc_typeck: make "global" WF requirements hard errors,
 in type aliases.

---
 src/librustc_typeck/check/wfcheck.rs          | 20 +++++++++++++++++--
 .../ui/consts/const-eval/pub_const_err.stderr |  7 ++-----
 .../const-eval/pub_const_err_bin.stderr       |  7 ++-----
 src/test/ui/resolve/issue-3907-2.stderr       |  2 --
 .../structs/struct-path-alias-bounds.stderr   |  7 ++-----
 5 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index b9eec5a1f6458..a2a273bebea62 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -136,9 +136,25 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def
 
                 let def_id = fcx.tcx.hir.local_def_id(item.id);
                 let ty = fcx.tcx.type_of(def_id);
-                let item_ty = fcx.inh.normalize_associated_types_in(cause, fcx.param_env, &ty);
+                let item_ty = fcx.inh.normalize_associated_types_in(
+                    cause.clone(),
+                    fcx.param_env,
+                    &ty,
+                );
+
+                let wf_obligations = ty::wf::obligations(fcx,
+                                                         fcx.param_env,
+                                                         &cause,
+                                                         item_ty)
+                    .unwrap_or(vec![]);
 
-                fcx.register_wf_obligation(item_ty, hir_ty.span, code.clone());
+                for mut obligation in wf_obligations {
+                    // Produce hard errors for monomorphic/"global" obligations.
+                    if obligation.predicate.is_global() {
+                        obligation.cause.code = ObligationCauseCode::MiscObligation;
+                    }
+                    fcx.register_predicate(obligation);
+                }
 
                 check_where_clauses(tcx, fcx, item.span, def_id, None, code);
 
diff --git a/src/test/ui/consts/const-eval/pub_const_err.stderr b/src/test/ui/consts/const-eval/pub_const_err.stderr
index da2a4409392cf..584787fea0b37 100644
--- a/src/test/ui/consts/const-eval/pub_const_err.stderr
+++ b/src/test/ui/consts/const-eval/pub_const_err.stderr
@@ -6,17 +6,14 @@ LL | pub type Foo = [i32; 0 - 1];
    |
    = note: #[deny(const_err)] on by default
 
-error: could not evaluate constant expression
+error[E0080]: could not evaluate constant expression
   --> $DIR/pub_const_err.rs:13:16
    |
 LL | pub type Foo = [i32; 0 - 1];
    |                ^^^^^^-----^
    |                      |
    |                      attempt to subtract with overflow
-   |
-   = note: #[deny(type_alias_missing_bounds)] on by default
-   = help: missing bounds in type aliases were previously allowed
-   = help: this is a hard error in Rust 2018
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr
index 3e36a0afff27e..a1277b46efec5 100644
--- a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr
+++ b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr
@@ -6,17 +6,14 @@ LL | pub type Foo = [i32; 0 - 1];
    |
    = note: #[deny(const_err)] on by default
 
-error: could not evaluate constant expression
+error[E0080]: could not evaluate constant expression
   --> $DIR/pub_const_err_bin.rs:11:16
    |
 LL | pub type Foo = [i32; 0 - 1];
    |                ^^^^^^-----^
    |                      |
    |                      attempt to subtract with overflow
-   |
-   = note: #[deny(type_alias_missing_bounds)] on by default
-   = help: missing bounds in type aliases were previously allowed
-   = help: this is a hard error in Rust 2018
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/resolve/issue-3907-2.stderr b/src/test/ui/resolve/issue-3907-2.stderr
index 8a61415aae6e5..19fb3d9de85b0 100644
--- a/src/test/ui/resolve/issue-3907-2.stderr
+++ b/src/test/ui/resolve/issue-3907-2.stderr
@@ -5,8 +5,6 @@ LL | type Foo = issue_3907::Foo+'static;
    |            ^^^^^^^^^^^^^^^^^^^^^^^ the trait `issue_3907::Foo` cannot be made into an object
    |
    = note: method `bar` has no receiver
-   = help: missing bounds in type aliases were previously allowed
-   = help: this is a hard error in Rust 2018
 
 error[E0038]: the trait `issue_3907::Foo` cannot be made into an object
   --> $DIR/issue-3907-2.rs:21:1
diff --git a/src/test/ui/structs/struct-path-alias-bounds.stderr b/src/test/ui/structs/struct-path-alias-bounds.stderr
index 8ed4282b66a0d..e04f7aa7fe911 100644
--- a/src/test/ui/structs/struct-path-alias-bounds.stderr
+++ b/src/test/ui/structs/struct-path-alias-bounds.stderr
@@ -1,12 +1,9 @@
-error: the trait bound `NoClone: std::clone::Clone` is not satisfied
+error[E0277]: the trait bound `NoClone: std::clone::Clone` is not satisfied
   --> $DIR/struct-path-alias-bounds.rs:16:10
    |
 LL | type A = S<NoClone>;
    |          ^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `NoClone`
-   |
-   = note: #[deny(type_alias_missing_bounds)] on by default
-   = help: missing bounds in type aliases were previously allowed
-   = help: this is a hard error in Rust 2018
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0277`.

From 1713f899d14fd099211088f99c220d1f522923ab Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Thu, 20 Sep 2018 17:53:34 +0300
Subject: [PATCH 4/4] rustc: make type_alias_missing_bounds warn-by-default.

---
 src/librustc/lint/builtin.rs                  |  2 +-
 src/test/ui/type/issue-51626.rs               |  2 ++
 src/test/ui/type/issue-51626.stderr           | 10 +++++++---
 src/test/ui/type/type-alias-bounds-err.rs     |  1 +
 src/test/ui/type/type-alias-bounds-err.stderr | 10 +++++++---
 5 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 87877a087e78a..fc5a65aaaa94c 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -340,7 +340,7 @@ declare_lint! {
 
 declare_lint! {
     pub TYPE_ALIAS_MISSING_BOUNDS,
-    Deny,
+    Warn,
     "type aliases missing bounds required by the type being aliased, are now deprecated"
 }
 
diff --git a/src/test/ui/type/issue-51626.rs b/src/test/ui/type/issue-51626.rs
index f8c7a5f6b14f7..8068ba15c3996 100644
--- a/src/test/ui/type/issue-51626.rs
+++ b/src/test/ui/type/issue-51626.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![deny(type_alias_missing_bounds)]
+
 pub trait Trait {}
 
 pub struct Foo<T: Trait>(T);
diff --git a/src/test/ui/type/issue-51626.stderr b/src/test/ui/type/issue-51626.stderr
index 7debf69fa196a..526a76ec9baee 100644
--- a/src/test/ui/type/issue-51626.stderr
+++ b/src/test/ui/type/issue-51626.stderr
@@ -1,16 +1,20 @@
 error: the trait bound `T: Trait` is not satisfied
-  --> $DIR/issue-51626.rs:17:25
+  --> $DIR/issue-51626.rs:19:25
    |
 LL | pub type Bar<T = Qux> = Foo<T>;
    |                         ^^^^^^ the trait `Trait` is not implemented for `T`
    |
-   = note: #[deny(type_alias_missing_bounds)] on by default
+note: lint level defined here
+  --> $DIR/issue-51626.rs:11:9
+   |
+LL | #![deny(type_alias_missing_bounds)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: consider adding a `where T: Trait` bound
    = help: missing bounds in type aliases were previously allowed
    = help: this is a hard error in Rust 2018
 
 error: the trait bound `Qux: Trait` is not satisfied
-  --> $DIR/issue-51626.rs:20:1
+  --> $DIR/issue-51626.rs:22:1
    |
 LL | pub type Baz<T: Trait = Qux> = Foo<T>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `Qux`
diff --git a/src/test/ui/type/type-alias-bounds-err.rs b/src/test/ui/type/type-alias-bounds-err.rs
index 6676561bcbf7a..134060adcc369 100644
--- a/src/test/ui/type/type-alias-bounds-err.rs
+++ b/src/test/ui/type/type-alias-bounds-err.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![allow(dead_code)]
+#![deny(type_alias_missing_bounds)]
 
 // This test contains examples originally in `type-alias-bounds.rs`,
 // that now produce errors instead of being silently accepted.
diff --git a/src/test/ui/type/type-alias-bounds-err.stderr b/src/test/ui/type/type-alias-bounds-err.stderr
index 342a58661a48d..dbc21f5b9a34c 100644
--- a/src/test/ui/type/type-alias-bounds-err.stderr
+++ b/src/test/ui/type/type-alias-bounds-err.stderr
@@ -1,17 +1,21 @@
 error: `T` cannot be sent between threads safely
-  --> $DIR/type-alias-bounds-err.rs:18:22
+  --> $DIR/type-alias-bounds-err.rs:19:22
    |
 LL | type MySendable<T> = Sendable<T>;
    |                      ^^^^^^^^^^^ `T` cannot be sent between threads safely
    |
-   = note: #[deny(type_alias_missing_bounds)] on by default
+note: lint level defined here
+  --> $DIR/type-alias-bounds-err.rs:12:9
+   |
+LL | #![deny(type_alias_missing_bounds)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: the trait `std::marker::Send` is not implemented for `T`
    = help: consider adding a `where T: std::marker::Send` bound
    = help: missing bounds in type aliases were previously allowed
    = help: this is a hard error in Rust 2018
 
 error: the trait bound `U: Bound` is not satisfied
-  --> $DIR/type-alias-bounds-err.rs:22:14
+  --> $DIR/type-alias-bounds-err.rs:23:14
    |
 LL | type T4<U> = <U as Bound>::Assoc;
    |              ^^^^^^^^^^^^^^^^^^^ the trait `Bound` is not implemented for `U`