about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/infer/error_reporting.rs95
-rw-r--r--src/librustc/infer/mod.rs47
-rw-r--r--src/librustc/lint/builtin.rs9
-rw-r--r--src/librustc/lint/context.rs122
-rw-r--r--src/librustc/lint/mod.rs2
-rw-r--r--src/librustc/session/mod.rs21
-rw-r--r--src/librustc/traits/error_reporting.rs67
-rw-r--r--src/librustc/traits/fulfill.rs2
-rw-r--r--src/librustc/traits/mod.rs11
-rw-r--r--src/librustc/traits/structural_impls.rs27
-rw-r--r--src/librustc/traits/util.rs77
-rw-r--r--src/librustc/ty/outlives.rs22
-rw-r--r--src/librustc/ty/wf.rs5
-rw-r--r--src/librustc_errors/diagnostic.rs202
-rw-r--r--src/librustc_errors/diagnostic_builder.rs196
-rw-r--r--src/librustc_errors/lib.rs243
-rw-r--r--src/librustc_lint/lib.rs4
-rw-r--r--src/librustc_typeck/check/compare_method.rs833
-rw-r--r--src/librustc_typeck/check/mod.rs43
-rw-r--r--src/librustc_typeck/check/regionck.rs17
-rw-r--r--src/librustc_typeck/diagnostics.rs2
-rw-r--r--src/libsyntax_pos/lib.rs2
-rw-r--r--src/test/compile-fail/issue-14853.rs2
-rw-r--r--src/test/compile-fail/issue-18937.rs53
-rw-r--r--src/test/compile-fail/regions-bound-missing-bound-in-impl.rs2
-rw-r--r--src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs2
-rw-r--r--src/test/parse-fail/generic-non-trailing-defaults.rs2
-rw-r--r--src/test/parse-fail/issue-17904.rs2
-rw-r--r--src/test/parse-fail/lex-bad-octal-literal.rs2
-rw-r--r--src/test/parse-fail/lifetime-no-keyword.rs2
-rw-r--r--src/test/parse-fail/raw-byte-string-literals.rs6
-rw-r--r--src/test/parse-fail/removed-syntax-field-let.rs2
-rw-r--r--src/test/parse-fail/syntax-trait-polarity.rs2
-rw-r--r--src/test/parse-fail/trailing-plus-in-bounds.rs2
-rw-r--r--src/test/parse-fail/trait-bounds-not-on-impl.rs2
-rw-r--r--src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs2
-rw-r--r--src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs2
-rw-r--r--src/test/run-pass/issue-18937-1.rs30
-rw-r--r--src/test/run-pass/traits-elaborate-type-region.rs58
-rw-r--r--src/test/ui/compare-method/proj-outlives-region.rs27
-rw-r--r--src/test/ui/compare-method/proj-outlives-region.stderr19
-rw-r--r--src/test/ui/compare-method/proj-outlives-region.stdout0
-rw-r--r--src/test/ui/compare-method/region-extra-2.rs (renamed from src/test/compile-fail/region-bound-extra-bound-in-impl.rs)2
-rw-r--r--src/test/ui/compare-method/region-extra-2.stderr11
-rw-r--r--src/test/ui/compare-method/region-extra.rs27
-rw-r--r--src/test/ui/compare-method/region-extra.stderr11
-rw-r--r--src/test/ui/compare-method/region-extra.stdout0
-rw-r--r--src/test/ui/compare-method/region-unrelated.rs28
-rw-r--r--src/test/ui/compare-method/region-unrelated.stderr19
-rw-r--r--src/test/ui/compare-method/region-unrelated.stdout0
-rw-r--r--src/test/ui/compare-method/reordered-type-param.rs (renamed from src/test/compile-fail/issue-2611-5.rs)2
-rw-r--r--src/test/ui/compare-method/reordered-type-param.stderr14
-rw-r--r--src/test/ui/compare-method/trait-bound-on-type-parameter.rs (renamed from src/test/compile-fail/issue-2611-4.rs)9
-rw-r--r--src/test/ui/compare-method/trait-bound-on-type-parameter.stderr11
-rw-r--r--src/test/ui/compare-method/traits-misc-mismatch-1.rs (renamed from src/test/compile-fail/trait-bounds-impl-comparison-1.rs)14
-rw-r--r--src/test/ui/compare-method/traits-misc-mismatch-1.stderr65
-rw-r--r--src/test/ui/compare-method/traits-misc-mismatch-2.rs (renamed from src/test/compile-fail/trait-bounds-impl-comparison-2.rs)2
-rw-r--r--src/test/ui/compare-method/traits-misc-mismatch-2.stderr11
-rwxr-xr-xsrc/test/ui/update-references.sh4
59 files changed, 1713 insertions, 785 deletions
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 5e3925b0b3c..47c0bc5fd60 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -245,6 +245,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         debug!("report_region_errors: {} errors after preprocessing", errors.len());
 
         for error in errors {
+            debug!("report_region_errors: error = {:?}", error);
             match error.clone() {
                 ConcreteFailure(origin, sub, sup) => {
                     self.report_concrete_failure(origin, sub, sup).emit();
@@ -299,44 +300,64 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         let mut bound_failures = Vec::new();
 
         for error in errors {
+            // Check whether we can process this error into some other
+            // form; if not, fall through.
             match *error {
                 ConcreteFailure(ref origin, sub, sup) => {
                     debug!("processing ConcreteFailure");
-                    match free_regions_from_same_fn(self.tcx, sub, sup) {
-                        Some(ref same_frs) => {
-                            origins.push(
-                                ProcessedErrorOrigin::ConcreteFailure(
-                                    origin.clone(),
-                                    sub,
-                                    sup));
-                            append_to_same_regions(&mut same_regions, same_frs);
-                        }
-                        _ => {
-                            other_errors.push(error.clone());
-                        }
+                    if let SubregionOrigin::CompareImplMethodObligation { .. } = *origin {
+                        // When comparing an impl method against a
+                        // trait method, it is not helpful to suggest
+                        // changes to the impl method.  This is
+                        // because the impl method signature is being
+                        // checked using the trait's environment, so
+                        // usually the changes we suggest would
+                        // actually have to be applied to the *trait*
+                        // method (and it's not clear that the trait
+                        // method is even under the user's control).
+                    } else if let Some(same_frs) = free_regions_from_same_fn(self.tcx, sub, sup) {
+                        origins.push(
+                            ProcessedErrorOrigin::ConcreteFailure(
+                                origin.clone(),
+                                sub,
+                                sup));
+                        append_to_same_regions(&mut same_regions, &same_frs);
+                        continue;
                     }
                 }
-                SubSupConflict(ref var_origin, _, sub_r, _, sup_r) => {
-                    debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub_r, sup_r);
-                    match free_regions_from_same_fn(self.tcx, sub_r, sup_r) {
-                        Some(ref same_frs) => {
-                            origins.push(
-                                ProcessedErrorOrigin::VariableFailure(
-                                    var_origin.clone()));
-                            append_to_same_regions(&mut same_regions, same_frs);
+                SubSupConflict(ref var_origin, ref sub_origin, sub, ref sup_origin, sup) => {
+                    debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub, sup);
+                    match (sub_origin, sup_origin) {
+                        (&SubregionOrigin::CompareImplMethodObligation { .. }, _) => {
+                            // As above, when comparing an impl method
+                            // against a trait method, it is not helpful
+                            // to suggest changes to the impl method.
                         }
-                        None => {
-                            other_errors.push(error.clone());
+                        (_, &SubregionOrigin::CompareImplMethodObligation { .. }) => {
+                            // See above.
+                        }
+                        _ => {
+                            if let Some(same_frs) = free_regions_from_same_fn(self.tcx, sub, sup) {
+                                origins.push(
+                                    ProcessedErrorOrigin::VariableFailure(
+                                        var_origin.clone()));
+                                append_to_same_regions(&mut same_regions, &same_frs);
+                                continue;
+                            }
                         }
                     }
                 }
                 GenericBoundFailure(ref origin, ref kind, region) => {
                     bound_failures.push((origin.clone(), kind.clone(), region));
+                    continue;
                 }
                 ProcessedErrors(..) => {
                     bug!("should not encounter a `ProcessedErrors` yet: {:?}", error)
                 }
             }
+
+            // No changes to this error.
+            other_errors.push(error.clone());
         }
 
         // ok, let's pull together the errors, sorted in an order that
@@ -630,6 +651,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 format!("the associated type `{}`", p),
         };
 
+        if let SubregionOrigin::CompareImplMethodObligation {
+            span, item_name, impl_item_def_id, trait_item_def_id, lint_id
+        } = origin {
+            self.report_extra_impl_obligation(span,
+                                              item_name,
+                                              impl_item_def_id,
+                                              trait_item_def_id,
+                                              &format!("`{}: {}`", bound_kind, sub),
+                                              lint_id)
+                .emit();
+            return;
+        }
+
         let mut err = match *sub {
             ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
                 // Does the required lifetime have a nice name we can print?
@@ -947,6 +981,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     "");
                 err
             }
+            infer::CompareImplMethodObligation { span,
+                                                 item_name,
+                                                 impl_item_def_id,
+                                                 trait_item_def_id,
+                                                 lint_id } => {
+                self.report_extra_impl_obligation(span,
+                                                  item_name,
+                                                  impl_item_def_id,
+                                                  trait_item_def_id,
+                                                  &format!("`{}: {}`", sup, sub),
+                                                  lint_id)
+            }
         }
     }
 
@@ -1792,6 +1838,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     "...so that references are valid when the destructor \
                      runs");
             }
+            infer::CompareImplMethodObligation { span, .. } => {
+                err.span_note(
+                    span,
+                    "...so that the definition in impl matches the definition from the trait");
+            }
         }
     }
 }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 4c097965bb0..35802aef593 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -355,6 +355,19 @@ pub enum SubregionOrigin<'tcx> {
 
     // Region constraint arriving from destructor safety
     SafeDestructor(Span),
+
+    // Comparing the signature and requirements of an impl method against
+    // the containing trait.
+    CompareImplMethodObligation {
+        span: Span,
+        item_name: ast::Name,
+        impl_item_def_id: DefId,
+        trait_item_def_id: DefId,
+
+        // this is `Some(_)` if this error arises from the bug fix for
+        // #18937. This is a temporary measure.
+        lint_id: Option<ast::NodeId>,
+    },
 }
 
 /// Places that type/region parameters can appear.
@@ -1147,16 +1160,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn region_outlives_predicate(&self,
-                                     span: Span,
+                                     cause: &traits::ObligationCause<'tcx>,
                                      predicate: &ty::PolyRegionOutlivesPredicate<'tcx>)
         -> UnitResult<'tcx>
     {
         self.commit_if_ok(|snapshot| {
             let (ty::OutlivesPredicate(r_a, r_b), skol_map) =
                 self.skolemize_late_bound_regions(predicate, snapshot);
-            let origin = RelateRegionParamBound(span);
+            let origin =
+                SubregionOrigin::from_obligation_cause(cause,
+                                                       || RelateRegionParamBound(cause.span));
             self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
-            self.leak_check(false, span, &skol_map, snapshot)?;
+            self.leak_check(false, cause.span, &skol_map, snapshot)?;
             Ok(self.pop_skolemized(skol_map, snapshot))
         })
     }
@@ -1786,6 +1801,32 @@ impl<'tcx> SubregionOrigin<'tcx> {
             AddrOf(a) => a,
             AutoBorrow(a) => a,
             SafeDestructor(a) => a,
+            CompareImplMethodObligation { span, .. } => span,
+        }
+    }
+
+    pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>,
+                                    default: F)
+                                    -> Self
+        where F: FnOnce() -> Self
+    {
+        match cause.code {
+            traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) =>
+                SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span),
+
+            traits::ObligationCauseCode::CompareImplMethodObligation { item_name,
+                                                                       impl_item_def_id,
+                                                                       trait_item_def_id,
+                                                                       lint_id } =>
+                SubregionOrigin::CompareImplMethodObligation {
+                    span: cause.span,
+                    item_name: item_name,
+                    impl_item_def_id: impl_item_def_id,
+                    trait_item_def_id: trait_item_def_id,
+                    lint_id: lint_id,
+                },
+
+            _ => default(),
         }
     }
 }
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 3472c77cf42..82a46f76401 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -198,6 +198,12 @@ declare_lint! {
     "patterns in functions without body were erroneously allowed"
 }
 
+declare_lint! {
+    pub EXTRA_REQUIREMENT_IN_IMPL,
+    Warn,
+    "detects extra requirements in impls that were erroneously allowed"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -235,7 +241,8 @@ impl LintPass for HardwiredLints {
             HR_LIFETIME_IN_ASSOC_TYPE,
             LIFETIME_UNDERSCORE,
             SAFE_EXTERN_STATICS,
-            PATTERNS_IN_FNS_WITHOUT_BODY
+            PATTERNS_IN_FNS_WITHOUT_BODY,
+            EXTRA_REQUIREMENT_IN_IMPL
         )
     }
 }
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 20463f42d3b..f08aa2eb49f 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -38,11 +38,12 @@ use util::nodemap::FnvHashMap;
 use std::cmp;
 use std::default::Default as StdDefault;
 use std::mem;
+use std::fmt;
 use syntax::attr;
 use syntax::parse::token::InternedString;
 use syntax::ast;
-use syntax_pos::Span;
-use errors::DiagnosticBuilder;
+use syntax_pos::{MultiSpan, Span};
+use errors::{self, Diagnostic, DiagnosticBuilder};
 use hir;
 use hir::intravisit as hir_visit;
 use syntax::visit as ast_visit;
@@ -80,6 +81,46 @@ pub struct LintStore {
     lint_cap: Option<Level>,
 }
 
+/// When you call `add_lint` on the session, you wind up storing one
+/// of these, which records a "potential lint" at a particular point.
+#[derive(PartialEq)]
+pub struct EarlyLint {
+    /// what lint is this? (e.g., `dead_code`)
+    pub id: LintId,
+
+    /// the main message
+    pub diagnostic: Diagnostic,
+}
+
+impl fmt::Debug for EarlyLint {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("EarlyLint")
+            .field("id", &self.id)
+            .field("span", &self.diagnostic.span)
+            .field("diagnostic", &self.diagnostic)
+            .finish()
+    }
+}
+
+pub trait IntoEarlyLint {
+    fn into_early_lint(self, id: LintId) -> EarlyLint;
+}
+
+impl<'a> IntoEarlyLint for (Span, &'a str) {
+    fn into_early_lint(self, id: LintId) -> EarlyLint {
+        let (span, msg) = self;
+        let mut diagnostic = Diagnostic::new(errors::Level::Warning, msg);
+        diagnostic.set_span(span);
+        EarlyLint { id: id, diagnostic: diagnostic }
+    }
+}
+
+impl IntoEarlyLint for Diagnostic {
+    fn into_early_lint(self, id: LintId) -> EarlyLint {
+        EarlyLint { id: id, diagnostic: self }
+    }
+}
+
 /// Extra information for a future incompatibility lint. See the call
 /// to `register_future_incompatible` in `librustc_lint/lib.rs` for
 /// guidelines.
@@ -388,22 +429,24 @@ pub fn gather_attr(attr: &ast::Attribute)
 /// in trans that run after the main lint pass is finished. Most
 /// lints elsewhere in the compiler should call
 /// `Session::add_lint()` instead.
-pub fn raw_emit_lint(sess: &Session,
-                     lints: &LintStore,
-                     lint: &'static Lint,
-                     lvlsrc: LevelSource,
-                     span: Option<Span>,
-                     msg: &str) {
+pub fn raw_emit_lint<S: Into<MultiSpan>>(sess: &Session,
+                                         lints: &LintStore,
+                                         lint: &'static Lint,
+                                         lvlsrc: LevelSource,
+                                         span: Option<S>,
+                                         msg: &str) {
     raw_struct_lint(sess, lints, lint, lvlsrc, span, msg).emit();
 }
 
-pub fn raw_struct_lint<'a>(sess: &'a Session,
-                           lints: &LintStore,
-                           lint: &'static Lint,
-                           lvlsrc: LevelSource,
-                           span: Option<Span>,
-                           msg: &str)
-                           -> DiagnosticBuilder<'a> {
+pub fn raw_struct_lint<'a, S>(sess: &'a Session,
+                              lints: &LintStore,
+                              lint: &'static Lint,
+                              lvlsrc: LevelSource,
+                              span: Option<S>,
+                              msg: &str)
+                              -> DiagnosticBuilder<'a>
+    where S: Into<MultiSpan>
+{
     let (mut level, source) = lvlsrc;
     if level == Allow {
         return sess.diagnostic().struct_dummy();
@@ -496,11 +539,11 @@ pub trait LintContext: Sized {
         raw_emit_lint(&self.sess(), self.lints(), lint, (level, src), span, msg);
     }
 
-    fn lookup(&self,
-              lint: &'static Lint,
-              span: Option<Span>,
-              msg: &str)
-              -> DiagnosticBuilder {
+    fn lookup<S: Into<MultiSpan>>(&self,
+                                  lint: &'static Lint,
+                                  span: Option<S>,
+                                  msg: &str)
+                                  -> DiagnosticBuilder {
         let (level, src) = match self.level_src(lint) {
             None => return self.sess().diagnostic().struct_dummy(),
             Some(pair) => pair,
@@ -514,11 +557,20 @@ pub trait LintContext: Sized {
         self.lookup_and_emit(lint, Some(span), msg);
     }
 
-    fn struct_span_lint(&self,
-                        lint: &'static Lint,
-                        span: Span,
-                        msg: &str)
-                        -> DiagnosticBuilder {
+    fn early_lint(&self, early_lint: EarlyLint) {
+        let span = early_lint.diagnostic.span.primary_span().expect("early lint w/o primary span");
+        let mut err = self.struct_span_lint(early_lint.id.lint,
+                                            span,
+                                            &early_lint.diagnostic.message);
+        err.copy_details_not_message(&early_lint.diagnostic);
+        err.emit();
+    }
+
+    fn struct_span_lint<S: Into<MultiSpan>>(&self,
+                                            lint: &'static Lint,
+                                            span: S,
+                                            msg: &str)
+                                            -> DiagnosticBuilder {
         self.lookup(lint, Some(span), msg)
     }
 
@@ -1065,8 +1117,8 @@ impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> {
     fn visit_id(&mut self, id: ast::NodeId) {
         if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) {
             debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);
-            for (lint_id, span, msg) in lints {
-                self.cx.span_lint(lint_id.lint, span, &msg[..])
+            for early_lint in lints {
+                self.cx.early_lint(early_lint);
             }
         }
     }
@@ -1211,10 +1263,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // If we missed any lints added to the session, then there's a bug somewhere
     // in the iteration code.
     for (id, v) in tcx.sess.lints.borrow().iter() {
-        for &(lint, span, ref msg) in v {
-            span_bug!(span,
-                      "unprocessed lint {} at {}: {}",
-                      lint.to_string(), tcx.map.node_to_string(*id), *msg)
+        for early_lint in v {
+            span_bug!(early_lint.diagnostic.span.clone(),
+                      "unprocessed lint {:?} at {}",
+                      early_lint, tcx.map.node_to_string(*id));
         }
     }
 
@@ -1229,8 +1281,8 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
     cx.with_lint_attrs(&krate.attrs, |cx| {
         // Lints may be assigned to the whole crate.
         if let Some(lints) = cx.sess.lints.borrow_mut().remove(&ast::CRATE_NODE_ID) {
-            for (lint_id, span, msg) in lints {
-                cx.span_lint(lint_id.lint, span, &msg[..])
+            for early_lint in lints {
+                cx.early_lint(early_lint);
             }
         }
 
@@ -1249,8 +1301,8 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
     // If we missed any lints added to the session, then there's a bug somewhere
     // in the iteration code.
     for (_, v) in sess.lints.borrow().iter() {
-        for &(lint, span, ref msg) in v {
-            span_bug!(span, "unprocessed lint {}: {}", lint.to_string(), *msg)
+        for early_lint in v {
+            span_bug!(early_lint.diagnostic.span.clone(), "unprocessed lint {:?}", early_lint);
         }
     }
 }
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 7eea6a2fcf2..34e0ce7da14 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -41,7 +41,7 @@ use hir;
 
 pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
                         raw_emit_lint, check_crate, check_ast_crate, gather_attrs,
-                        raw_struct_lint, FutureIncompatibleInfo};
+                        raw_struct_lint, FutureIncompatibleInfo, EarlyLint, IntoEarlyLint};
 
 /// Specification of a single lint.
 #[derive(Copy, Clone, Debug)]
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 1ce5b223fbe..b4dadbf7961 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -74,7 +74,7 @@ pub struct Session {
     pub local_crate_source_file: Option<PathBuf>,
     pub working_dir: PathBuf,
     pub lint_store: RefCell<lint::LintStore>,
-    pub lints: RefCell<NodeMap<Vec<(lint::LintId, Span, String)>>>,
+    pub lints: RefCell<NodeMap<Vec<lint::EarlyLint>>>,
     /// Set of (LintId, span, message) tuples tracking lint (sub)diagnostics
     /// that have been set once, but should not be set again, in order to avoid
     /// redundantly verbose output (Issue #24690).
@@ -262,17 +262,26 @@ impl Session {
                     lint: &'static lint::Lint,
                     id: ast::NodeId,
                     sp: Span,
-                    msg: String) {
+                    msg: String)
+    {
+        self.add_lint_diagnostic(lint, id, (sp, &msg[..]))
+    }
+    pub fn add_lint_diagnostic<M>(&self,
+                                  lint: &'static lint::Lint,
+                                  id: ast::NodeId,
+                                  msg: M)
+        where M: lint::IntoEarlyLint,
+    {
         let lint_id = lint::LintId::of(lint);
         let mut lints = self.lints.borrow_mut();
+        let early_lint = msg.into_early_lint(lint_id);
         if let Some(arr) = lints.get_mut(&id) {
-            let tuple = (lint_id, sp, msg);
-            if !arr.contains(&tuple) {
-                arr.push(tuple);
+            if !arr.contains(&early_lint) {
+                arr.push(early_lint);
             }
             return;
         }
-        lints.insert(id, vec![(lint_id, sp, msg)]);
+        lints.insert(id, vec![early_lint]);
     }
     pub fn reserve_node_ids(&self, count: usize) -> ast::NodeId {
         let id = self.next_node_id.get();
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 9435f96c08a..89c8162456c 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -27,6 +27,7 @@ use super::{
 use fmt_macros::{Parser, Piece, Position};
 use hir::def_id::DefId;
 use infer::{self, InferCtxt, TypeOrigin};
+use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
 use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use ty::error::ExpectedFound;
 use ty::fast_reject;
@@ -36,6 +37,7 @@ use util::nodemap::{FnvHashMap, FnvHashSet};
 
 use std::cmp;
 use std::fmt;
+use syntax::ast;
 use syntax_pos::Span;
 use errors::DiagnosticBuilder;
 
@@ -417,6 +419,45 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.report_overflow_error(&cycle[0], false);
     }
 
+    pub fn report_extra_impl_obligation(&self,
+                                        error_span: Span,
+                                        item_name: ast::Name,
+                                        _impl_item_def_id: DefId,
+                                        trait_item_def_id: DefId,
+                                        requirement: &fmt::Display,
+                                        lint_id: Option<ast::NodeId>) // (*)
+                                        -> DiagnosticBuilder<'tcx>
+    {
+        // (*) This parameter is temporary and used only for phasing
+        // in the bug fix to #18937. If it is `Some`, it has a kind of
+        // weird effect -- the diagnostic is reported as a lint, and
+        // the builder which is returned is marked as canceled.
+
+        let mut err =
+            struct_span_err!(self.tcx.sess,
+                             error_span,
+                             E0276,
+                             "impl has stricter requirements than trait");
+
+        if let Some(trait_item_span) = self.tcx.map.span_if_local(trait_item_def_id) {
+            err.span_label(trait_item_span,
+                           &format!("definition of `{}` from trait", item_name));
+        }
+
+        err.span_label(
+            error_span,
+            &format!("impl has extra requirement {}", requirement));
+
+        if let Some(node_id) = lint_id {
+            self.tcx.sess.add_lint_diagnostic(EXTRA_REQUIREMENT_IN_IMPL,
+                                              node_id,
+                                              (*err).clone());
+            err.cancel();
+        }
+
+        err
+    }
+
     pub fn report_selection_error(&self,
                                   obligation: &PredicateObligation<'tcx>,
                                   error: &SelectionError<'tcx>)
@@ -424,12 +465,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         let span = obligation.cause.span;
         let mut err = match *error {
             SelectionError::Unimplemented => {
-                if let ObligationCauseCode::CompareImplMethodObligation = obligation.cause.code {
-                    span_err!(
-                        self.tcx.sess, span, E0276,
-                        "the requirement `{}` appears on the impl \
-                         method but not on the corresponding trait method",
-                        obligation.predicate);
+                if let ObligationCauseCode::CompareImplMethodObligation {
+                    item_name, impl_item_def_id, trait_item_def_id, lint_id
+                } = obligation.cause.code {
+                    self.report_extra_impl_obligation(
+                        span,
+                        item_name,
+                        impl_item_def_id,
+                        trait_item_def_id,
+                        &format!("`{}`", obligation.predicate),
+                        lint_id)
+                        .emit();
                     return;
                 } else {
                     match obligation.predicate {
@@ -492,7 +538,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
                         ty::Predicate::RegionOutlives(ref predicate) => {
                             let predicate = self.resolve_type_vars_if_possible(predicate);
-                            let err = self.region_outlives_predicate(span,
+                            let err = self.region_outlives_predicate(&obligation.cause,
                                                                      &predicate).err().unwrap();
                             struct_span_err!(self.tcx.sess, span, E0279,
                                 "the requirement `{}` is not satisfied (`{}`)",
@@ -822,6 +868,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 err.note(&format!("required so that reference `{}` does not outlive its referent",
                                   ref_ty));
             }
+            ObligationCauseCode::ObjectTypeBound(object_ty, region) => {
+                err.note(&format!("required so that the lifetime bound of `{}` for `{}` \
+                                   is satisfied",
+                                  region, object_ty));
+            }
             ObligationCauseCode::ItemObligation(item_def_id) => {
                 let item_name = tcx.item_path_str(item_def_id);
                 err.note(&format!("required by `{}`", item_name));
@@ -886,7 +937,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                 &parent_predicate,
                                                 &data.parent_code);
             }
-            ObligationCauseCode::CompareImplMethodObligation => {
+            ObligationCauseCode::CompareImplMethodObligation { .. } => {
                 err.note(
                     &format!("the requirement `{}` appears on the impl method \
                               but not on the corresponding trait method",
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index ded2fdc58b4..906da429036 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -526,7 +526,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
         }
 
         ty::Predicate::RegionOutlives(ref binder) => {
-            match selcx.infcx().region_outlives_predicate(obligation.cause.span, binder) {
+            match selcx.infcx().region_outlives_predicate(&obligation.cause, binder) {
                 Ok(()) => Ok(Some(Vec::new())),
                 Err(_) => Err(CodeSelectionError(Unimplemented)),
             }
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 7ba10d9c0a5..017b34d914f 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -111,6 +111,9 @@ pub enum ObligationCauseCode<'tcx> {
     /// A type like `&'a T` is WF only if `T: 'a`.
     ReferenceOutlivesReferent(Ty<'tcx>),
 
+    /// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`.
+    ObjectTypeBound(Ty<'tcx>, &'tcx ty::Region),
+
     /// Obligation incurred due to an object cast.
     ObjectCastObligation(/* Object type */ Ty<'tcx>),
 
@@ -138,7 +141,13 @@ pub enum ObligationCauseCode<'tcx> {
 
     ImplDerivedObligation(DerivedObligationCause<'tcx>),
 
-    CompareImplMethodObligation,
+    // error derived when matching traits/impls; see ObligationCause for more details
+    CompareImplMethodObligation {
+        item_name: ast::Name,
+        impl_item_def_id: DefId,
+        trait_item_def_id: DefId,
+        lint_id: Option<ast::NodeId>,
+    },
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 022566642f6..d33e8b5675f 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -175,6 +175,13 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
             super::ReferenceOutlivesReferent(ty) => {
                 tcx.lift(&ty).map(super::ReferenceOutlivesReferent)
             }
+            super::ObjectTypeBound(ty, r) => {
+                tcx.lift(&ty).and_then(|ty| {
+                    tcx.lift(&r).and_then(|r| {
+                        Some(super::ObjectTypeBound(ty, r))
+                    })
+                })
+            }
             super::ObjectCastObligation(ty) => {
                 tcx.lift(&ty).map(super::ObjectCastObligation)
             }
@@ -195,8 +202,16 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
             super::ImplDerivedObligation(ref cause) => {
                 tcx.lift(cause).map(super::ImplDerivedObligation)
             }
-            super::CompareImplMethodObligation => {
-                Some(super::CompareImplMethodObligation)
+            super::CompareImplMethodObligation { item_name,
+                                                 impl_item_def_id,
+                                                 trait_item_def_id,
+                                                 lint_id } => {
+                Some(super::CompareImplMethodObligation {
+                    item_name: item_name,
+                    impl_item_def_id: impl_item_def_id,
+                    trait_item_def_id: trait_item_def_id,
+                    lint_id: lint_id,
+                })
             }
         }
     }
@@ -459,12 +474,15 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
             super::FieldSized |
             super::ConstSized |
             super::SharedStatic |
-            super::CompareImplMethodObligation => self.clone(),
+            super::CompareImplMethodObligation { .. } => self.clone(),
 
             super::ProjectionWf(proj) => super::ProjectionWf(proj.fold_with(folder)),
             super::ReferenceOutlivesReferent(ty) => {
                 super::ReferenceOutlivesReferent(ty.fold_with(folder))
             }
+            super::ObjectTypeBound(ty, r) => {
+                super::ObjectTypeBound(ty.fold_with(folder), r.fold_with(folder))
+            }
             super::ObjectCastObligation(ty) => {
                 super::ObjectCastObligation(ty.fold_with(folder))
             }
@@ -492,10 +510,11 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
             super::FieldSized |
             super::ConstSized |
             super::SharedStatic |
-            super::CompareImplMethodObligation => false,
+            super::CompareImplMethodObligation { .. } => false,
 
             super::ProjectionWf(proj) => proj.visit_with(visitor),
             super::ReferenceOutlivesReferent(ty) => ty.visit_with(visitor),
+            super::ObjectTypeBound(ty, r) => ty.visit_with(visitor) || r.visit_with(visitor),
             super::ObjectCastObligation(ty) => ty.visit_with(visitor),
             super::BuiltinDerivedObligation(ref cause) => cause.visit_with(visitor),
             super::ImplDerivedObligation(ref cause) => cause.visit_with(visitor)
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index a0792dcf4dd..a3d974216b6 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -11,6 +11,7 @@
 use hir::def_id::DefId;
 use ty::subst::{Subst, Substs};
 use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef};
+use ty::outlives::Component;
 use util::common::ErrorReported;
 use util::nodemap::FnvHashSet;
 
@@ -166,27 +167,63 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
             ty::Predicate::ClosureKind(..) => {
                 // Nothing to elaborate when waiting for a closure's kind to be inferred.
             }
-            ty::Predicate::RegionOutlives(..) |
-            ty::Predicate::TypeOutlives(..) => {
-                // Currently, we do not "elaborate" predicates like
-                // `'a : 'b` or `T : 'a`.  We could conceivably do
-                // more here.  For example,
-                //
-                //     &'a int : 'b
-                //
-                // implies that
-                //
-                //     'a : 'b
-                //
-                // and we could get even more if we took WF
-                // constraints into account. For example,
-                //
-                //     &'a &'b int : 'c
-                //
-                // implies that
+
+            ty::Predicate::RegionOutlives(..) => {
+                // Nothing to elaborate from `'a: 'b`.
+            }
+
+            ty::Predicate::TypeOutlives(ref data) => {
+                // We know that `T: 'a` for some type `T`. We can
+                // often elaborate this. For example, if we know that
+                // `[U]: 'a`, that implies that `U: 'a`. Similarly, if
+                // we know `&'a U: 'b`, then we know that `'a: 'b` and
+                // `U: 'b`.
                 //
-                //     'b : 'a
-                //     'a : 'c
+                // We can basically ignore bound regions here. So for
+                // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to
+                // `'a: 'b`.
+
+                // Ignore `for<'a> T: 'a` -- we might in the future
+                // consider this as evidence that `T: 'static`, but
+                // I'm a bit wary of such constructions and so for now
+                // I want to be conservative. --nmatsakis
+                let ty_max = data.skip_binder().0;
+                let r_min = data.skip_binder().1;
+                if r_min.is_bound() {
+                    return;
+                }
+
+                let visited = &mut self.visited;
+                self.stack.extend(
+                    tcx.outlives_components(ty_max)
+                       .into_iter()
+                       .filter_map(|component| match component {
+                           Component::Region(r) => if r.is_bound() {
+                               None
+                           } else {
+                               Some(ty::Predicate::RegionOutlives(
+                                   ty::Binder(ty::OutlivesPredicate(r, r_min))))
+                           },
+
+                           Component::Param(p) => {
+                               let ty = tcx.mk_param(p.idx, p.name);
+                               Some(ty::Predicate::TypeOutlives(
+                                   ty::Binder(ty::OutlivesPredicate(ty, r_min))))
+                           },
+
+                           Component::UnresolvedInferenceVariable(_) => {
+                               None
+                           },
+
+                           Component::Projection(_) |
+                           Component::EscapingProjection(_) => {
+                               // We can probably do more here. This
+                               // corresponds to a case like `<T as
+                               // Foo<'a>>::U: 'b`.
+                               None
+                           },
+                       })
+                       .filter(|p| visited.insert(p)));
             }
         }
     }
diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs
index a4edd3b93c9..51feab9d40c 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -12,8 +12,7 @@
 // refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
 // RFC for reference.
 
-use infer::InferCtxt;
-use ty::{self, Ty, TypeFoldable};
+use ty::{self, Ty, TyCtxt, TypeFoldable};
 
 #[derive(Debug)]
 pub enum Component<'tcx> {
@@ -55,9 +54,9 @@ pub enum Component<'tcx> {
     EscapingProjection(Vec<Component<'tcx>>),
 }
 
-impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Returns all the things that must outlive `'a` for the condition
-    /// `ty0: 'a` to hold.
+    /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
     pub fn outlives_components(&self, ty0: Ty<'tcx>)
                                -> Vec<Component<'tcx>> {
         let mut components = vec![];
@@ -148,16 +147,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 }
             }
 
-            // If we encounter an inference variable, try to resolve it
-            // and proceed with resolved version. If we cannot resolve it,
-            // then record the unresolved variable as a component.
-            ty::TyInfer(_) => {
-                let ty = self.resolve_type_vars_if_possible(&ty);
-                if let ty::TyInfer(infer_ty) = ty.sty {
-                    out.push(Component::UnresolvedInferenceVariable(infer_ty));
-                } else {
-                    self.compute_components(ty, out);
-                }
+            // We assume that inference variables are fully resolved.
+            // So, if we encounter an inference variable, just record
+            // the unresolved variable as a component.
+            ty::TyInfer(infer_ty) => {
+                out.push(Component::UnresolvedInferenceVariable(infer_ty));
             }
 
             // Most types do not introduce any region binders, nor
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 1135199d225..155fa4989ea 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -178,7 +178,8 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>(
                         match infcx.tcx.no_late_bound_regions(data) {
                             None => vec![],
                             Some(ty::OutlivesPredicate(ty_a, r_b)) => {
-                                let components = infcx.outlives_components(ty_a);
+                                let ty_a = infcx.resolve_type_vars_if_possible(&ty_a);
+                                let components = infcx.tcx.outlives_components(ty_a);
                                 implied_bounds_from_components(r_b, components)
                             }
                         },
@@ -497,7 +498,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
             let explicit_bound = data.region_bound;
 
             for implicit_bound in implicit_bounds {
-                let cause = self.cause(traits::ReferenceOutlivesReferent(ty));
+                let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound));
                 let outlives = ty::Binder(ty::OutlivesPredicate(explicit_bound, implicit_bound));
                 self.out.push(traits::Obligation::new(cause, outlives.to_predicate()));
             }
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
new file mode 100644
index 00000000000..730ca8f9e2e
--- /dev/null
+++ b/src/librustc_errors/diagnostic.rs
@@ -0,0 +1,202 @@
+// Copyright 2012-2015 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.
+
+use CodeSuggestion;
+use Level;
+use RenderSpan;
+use RenderSpan::Suggestion;
+use std::fmt;
+use syntax_pos::{MultiSpan, Span};
+
+#[must_use]
+#[derive(Clone, Debug, PartialEq)]
+pub struct Diagnostic {
+    pub level: Level,
+    pub message: String,
+    pub code: Option<String>,
+    pub span: MultiSpan,
+    pub children: Vec<SubDiagnostic>,
+}
+
+/// For example a note attached to an error.
+#[derive(Clone, Debug, PartialEq)]
+pub struct SubDiagnostic {
+    pub level: Level,
+    pub message: String,
+    pub span: MultiSpan,
+    pub render_span: Option<RenderSpan>,
+}
+
+impl Diagnostic {
+    pub fn new(level: Level, message: &str) -> Self {
+        Diagnostic::new_with_code(level, None, message)
+    }
+
+    pub fn new_with_code(level: Level, code: Option<String>, message: &str) -> Self {
+        Diagnostic {
+            level: level,
+            message: message.to_owned(),
+            code: code,
+            span: MultiSpan::new(),
+            children: vec![],
+        }
+    }
+
+    /// Cancel the diagnostic (a structured diagnostic must either be emitted or
+    /// cancelled or it will panic when dropped).
+    /// BEWARE: if this DiagnosticBuilder is an error, then creating it will
+    /// bump the error count on the Handler and cancelling it won't undo that.
+    /// If you want to decrement the error count you should use `Handler::cancel`.
+    pub fn cancel(&mut self) {
+        self.level = Level::Cancelled;
+    }
+
+    pub fn cancelled(&self) -> bool {
+        self.level == Level::Cancelled
+    }
+
+    pub fn is_fatal(&self) -> bool {
+        self.level == Level::Fatal
+    }
+
+    /// Add a span/label to be included in the resulting snippet.
+    /// This is pushed onto the `MultiSpan` that was created when the
+    /// diagnostic was first built. If you don't call this function at
+    /// all, and you just supplied a `Span` to create the diagnostic,
+    /// then the snippet will just include that `Span`, which is
+    /// called the primary span.
+    pub fn span_label(&mut self, span: Span, label: &fmt::Display)
+                      -> &mut Self {
+        self.span.push_span_label(span, format!("{}", label));
+        self
+    }
+
+    pub fn note_expected_found(&mut self,
+                               label: &fmt::Display,
+                               expected: &fmt::Display,
+                               found: &fmt::Display)
+                               -> &mut Self
+    {
+        self.note_expected_found_extra(label, expected, found, &"", &"")
+    }
+
+    pub fn note_expected_found_extra(&mut self,
+                                     label: &fmt::Display,
+                                     expected: &fmt::Display,
+                                     found: &fmt::Display,
+                                     expected_extra: &fmt::Display,
+                                     found_extra: &fmt::Display)
+                                     -> &mut Self
+    {
+        // For now, just attach these as notes
+        self.note(&format!("expected {} `{}`{}", label, expected, expected_extra));
+        self.note(&format!("   found {} `{}`{}", label, found, found_extra));
+        self
+    }
+
+    pub fn note(&mut self, msg: &str) -> &mut Self {
+        self.sub(Level::Note, msg, MultiSpan::new(), None);
+        self
+    }
+
+    pub fn span_note<S: Into<MultiSpan>>(&mut self,
+                                         sp: S,
+                                         msg: &str)
+                                         -> &mut Self {
+        self.sub(Level::Note, msg, sp.into(), None);
+        self
+    }
+
+    pub fn warn(&mut self, msg: &str) -> &mut Self {
+        self.sub(Level::Warning, msg, MultiSpan::new(), None);
+        self
+    }
+
+    pub fn span_warn<S: Into<MultiSpan>>(&mut self,
+                                         sp: S,
+                                         msg: &str)
+                                         -> &mut Self {
+        self.sub(Level::Warning, msg, sp.into(), None);
+        self
+    }
+
+    pub fn help(&mut self , msg: &str) -> &mut Self {
+        self.sub(Level::Help, msg, MultiSpan::new(), None);
+        self
+    }
+
+    pub fn span_help<S: Into<MultiSpan>>(&mut self,
+                                         sp: S,
+                                         msg: &str)
+                                         -> &mut Self {
+        self.sub(Level::Help, msg, sp.into(), None);
+        self
+    }
+
+    /// Prints out a message with a suggested edit of the code.
+    ///
+    /// See `diagnostic::RenderSpan::Suggestion` for more information.
+    pub fn span_suggestion<S: Into<MultiSpan>>(&mut self,
+                                               sp: S,
+                                               msg: &str,
+                                               suggestion: String)
+                                               -> &mut Self {
+        self.sub(Level::Help,
+                 msg,
+                 MultiSpan::new(),
+                 Some(Suggestion(CodeSuggestion {
+                     msp: sp.into(),
+                     substitutes: vec![suggestion],
+                 })));
+        self
+    }
+
+    pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
+        self.span = sp.into();
+        self
+    }
+
+    pub fn code(&mut self, s: String) -> &mut Self {
+        self.code = Some(s);
+        self
+    }
+
+    pub fn message(&self) -> &str {
+        &self.message
+    }
+
+    pub fn level(&self) -> Level {
+        self.level
+    }
+
+    /// Used by a lint. Copies over all details *but* the "main
+    /// message".
+    pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
+        self.span = from.span.clone();
+        self.code = from.code.clone();
+        self.children.extend(from.children.iter().cloned())
+    }
+
+    /// Convenience function for internal use, clients should use one of the
+    /// public methods above.
+    fn sub(&mut self,
+           level: Level,
+           message: &str,
+           span: MultiSpan,
+           render_span: Option<RenderSpan>) {
+        let sub = SubDiagnostic {
+            level: level,
+            message: message.to_owned(),
+            span: span,
+            render_span: render_span,
+        };
+        self.children.push(sub);
+    }
+}
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
new file mode 100644
index 00000000000..7dfea6b8951
--- /dev/null
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -0,0 +1,196 @@
+// Copyright 2012-2015 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.
+
+use Diagnostic;
+use Level;
+use Handler;
+use std::fmt::{self, Debug};
+use std::ops::{Deref, DerefMut};
+use std::thread::panicking;
+use syntax_pos::{MultiSpan, Span};
+
+/// Used for emitting structured error messages and other diagnostic information.
+#[must_use]
+#[derive(Clone)]
+pub struct DiagnosticBuilder<'a> {
+    handler: &'a Handler,
+    diagnostic: Diagnostic,
+}
+
+/// In general, the `DiagnosticBuilder` uses deref to allow access to
+/// the fields and methods of the embedded `diagnostic` in a
+/// transparent way.  *However,* many of the methods are intended to
+/// be used in a chained way, and hence ought to return `self`. In
+/// that case, we can't just naively forward to the method on the
+/// `diagnostic`, because the return type would be a `&Diagnostic`
+/// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes
+/// it easy to declare such methods on the builder.
+macro_rules! forward {
+    // Forward pattern for &self -> &Self
+    (pub fn $n:ident(&self, $($name:ident: $ty:ty),*) -> &Self) => {
+        pub fn $n(&self, $($name: $ty),*) -> &Self {
+            self.diagnostic.$n($($name),*);
+            self
+        }
+    };
+
+    // Forward pattern for &mut self -> &mut Self
+    (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => {
+        pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
+            self.diagnostic.$n($($name),*);
+            self
+        }
+    };
+
+    // Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
+    // type parameter. No obvious way to make this more generic.
+    (pub fn $n:ident<S: Into<MultiSpan>>(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => {
+        pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
+            self.diagnostic.$n($($name),*);
+            self
+        }
+    };
+}
+
+impl<'a> Deref for DiagnosticBuilder<'a> {
+    type Target = Diagnostic;
+
+    fn deref(&self) -> &Diagnostic {
+        &self.diagnostic
+    }
+}
+
+impl<'a> DerefMut for DiagnosticBuilder<'a> {
+    fn deref_mut(&mut self) -> &mut Diagnostic {
+        &mut self.diagnostic
+    }
+}
+
+impl<'a> DiagnosticBuilder<'a> {
+    /// Emit the diagnostic.
+    pub fn emit(&mut self) {
+        if self.cancelled() {
+            return;
+        }
+
+        match self.level {
+            Level::Bug |
+            Level::Fatal |
+            Level::PhaseFatal |
+            Level::Error => {
+                self.handler.bump_err_count();
+            }
+
+            Level::Warning |
+            Level::Note |
+            Level::Help |
+            Level::Cancelled => {
+            }
+        }
+
+        self.handler.emitter.borrow_mut().emit(&self);
+        self.cancel();
+        self.handler.panic_if_treat_err_as_bug();
+
+        // if self.is_fatal() {
+        //     panic!(FatalError);
+        // }
+    }
+
+    /// Add a span/label to be included in the resulting snippet.
+    /// This is pushed onto the `MultiSpan` that was created when the
+    /// diagnostic was first built. If you don't call this function at
+    /// all, and you just supplied a `Span` to create the diagnostic,
+    /// then the snippet will just include that `Span`, which is
+    /// called the primary span.
+    forward!(pub fn span_label(&mut self, span: Span, label: &fmt::Display)
+                               -> &mut Self);
+
+    forward!(pub fn note_expected_found(&mut self,
+                                        label: &fmt::Display,
+                                        expected: &fmt::Display,
+                                        found: &fmt::Display)
+                                        -> &mut Self);
+
+    forward!(pub fn note_expected_found_extra(&mut self,
+                                              label: &fmt::Display,
+                                              expected: &fmt::Display,
+                                              found: &fmt::Display,
+                                              expected_extra: &fmt::Display,
+                                              found_extra: &fmt::Display)
+                                              -> &mut Self);
+
+    forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
+    forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
+                                                  sp: S,
+                                                  msg: &str)
+                                                  -> &mut Self);
+    forward!(pub fn warn(&mut self, msg: &str) -> &mut Self);
+    forward!(pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self);
+    forward!(pub fn help(&mut self , msg: &str) -> &mut Self);
+    forward!(pub fn span_help<S: Into<MultiSpan>>(&mut self,
+                                                  sp: S,
+                                                  msg: &str)
+                                                  -> &mut Self);
+    forward!(pub fn span_suggestion<S: Into<MultiSpan>>(&mut self,
+                                                        sp: S,
+                                                        msg: &str,
+                                                        suggestion: String)
+                                                        -> &mut Self);
+    forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
+    forward!(pub fn code(&mut self, s: String) -> &mut Self);
+
+    /// Convenience function for internal use, clients should use one of the
+    /// struct_* methods on Handler.
+    pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
+        DiagnosticBuilder::new_with_code(handler, level, None, message)
+    }
+
+    /// Convenience function for internal use, clients should use one of the
+    /// struct_* methods on Handler.
+    pub fn new_with_code(handler: &'a Handler,
+                         level: Level,
+                         code: Option<String>,
+                         message: &str)
+                         -> DiagnosticBuilder<'a> {
+        DiagnosticBuilder {
+            handler: handler,
+            diagnostic: Diagnostic::new_with_code(level, code, message)
+        }
+    }
+
+    pub fn into_diagnostic(mut self) -> Diagnostic {
+        // annoyingly, the Drop impl means we can't actually move
+        let result = self.diagnostic.clone();
+        self.cancel();
+        result
+    }
+}
+
+impl<'a> Debug for DiagnosticBuilder<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.diagnostic.fmt(f)
+    }
+}
+
+/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or
+/// we emit a bug.
+impl<'a> Drop for DiagnosticBuilder<'a> {
+    fn drop(&mut self) {
+        if !panicking() && !self.cancelled() {
+            let mut db = DiagnosticBuilder::new(self.handler,
+                                                Level::Bug,
+                                                "Error constructed but not emitted");
+            db.emit();
+            panic!();
+        }
+    }
+}
+
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 25b314256b0..badee66b83d 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -39,15 +39,15 @@ extern crate syntax_pos;
 pub use emitter::ColorConfig;
 
 use self::Level::*;
-use self::RenderSpan::*;
 
 use emitter::{Emitter, EmitterWriter};
 
 use std::cell::{RefCell, Cell};
 use std::{error, fmt};
 use std::rc::Rc;
-use std::thread::panicking;
 
+pub mod diagnostic;
+pub mod diagnostic_builder;
 pub mod emitter;
 pub mod snippet;
 pub mod registry;
@@ -57,7 +57,7 @@ mod lock;
 use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION};
 use syntax_pos::MacroBacktrace;
 
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub enum RenderSpan {
     /// A FullSpan renders with both with an initial line for the
     /// message, prefixed by file:linenum, followed by a summary of
@@ -71,7 +71,7 @@ pub enum RenderSpan {
     Suggestion(CodeSuggestion),
 }
 
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct CodeSuggestion {
     pub msp: MultiSpan,
     pub substitutes: Vec<String>,
@@ -211,219 +211,8 @@ impl error::Error for ExplicitBug {
     }
 }
 
-/// Used for emitting structured error messages and other diagnostic information.
-#[must_use]
-#[derive(Clone)]
-pub struct DiagnosticBuilder<'a> {
-    handler: &'a Handler,
-    pub level: Level,
-    pub message: String,
-    pub code: Option<String>,
-    pub span: MultiSpan,
-    pub children: Vec<SubDiagnostic>,
-}
-
-/// For example a note attached to an error.
-#[derive(Clone)]
-pub struct SubDiagnostic {
-    pub level: Level,
-    pub message: String,
-    pub span: MultiSpan,
-    pub render_span: Option<RenderSpan>,
-}
-
-impl<'a> DiagnosticBuilder<'a> {
-    /// Emit the diagnostic.
-    pub fn emit(&mut self) {
-        if self.cancelled() {
-            return;
-        }
-
-        self.handler.emitter.borrow_mut().emit(&self);
-        self.cancel();
-        self.handler.panic_if_treat_err_as_bug();
-
-        // if self.is_fatal() {
-        //     panic!(FatalError);
-        // }
-    }
-
-    /// Cancel the diagnostic (a structured diagnostic must either be emitted or
-    /// cancelled or it will panic when dropped).
-    /// BEWARE: if this DiagnosticBuilder is an error, then creating it will
-    /// bump the error count on the Handler and cancelling it won't undo that.
-    /// If you want to decrement the error count you should use `Handler::cancel`.
-    pub fn cancel(&mut self) {
-        self.level = Level::Cancelled;
-    }
-
-    pub fn cancelled(&self) -> bool {
-        self.level == Level::Cancelled
-    }
-
-    pub fn is_fatal(&self) -> bool {
-        self.level == Level::Fatal
-    }
-
-    /// Add a span/label to be included in the resulting snippet.
-    /// This is pushed onto the `MultiSpan` that was created when the
-    /// diagnostic was first built. If you don't call this function at
-    /// all, and you just supplied a `Span` to create the diagnostic,
-    /// then the snippet will just include that `Span`, which is
-    /// called the primary span.
-    pub fn span_label(&mut self, span: Span, label: &fmt::Display) -> &mut DiagnosticBuilder<'a> {
-        self.span.push_span_label(span, format!("{}", label));
-        self
-    }
-
-    pub fn note_expected_found(&mut self,
-                               label: &fmt::Display,
-                               expected: &fmt::Display,
-                               found: &fmt::Display)
-                               -> &mut DiagnosticBuilder<'a> {
-        self.note_expected_found_extra(label, expected, found, &"", &"")
-    }
-
-    pub fn note_expected_found_extra(&mut self,
-                                     label: &fmt::Display,
-                                     expected: &fmt::Display,
-                                     found: &fmt::Display,
-                                     expected_extra: &fmt::Display,
-                                     found_extra: &fmt::Display)
-                                     -> &mut DiagnosticBuilder<'a> {
-        // For now, just attach these as notes
-        self.note(&format!("expected {} `{}`{}", label, expected, expected_extra));
-        self.note(&format!("   found {} `{}`{}", label, found, found_extra));
-        self
-    }
-
-    pub fn note(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
-        self.sub(Level::Note, msg, MultiSpan::new(), None);
-        self
-    }
-    pub fn span_note<S: Into<MultiSpan>>(&mut self,
-                                         sp: S,
-                                         msg: &str)
-                                         -> &mut DiagnosticBuilder<'a> {
-        self.sub(Level::Note, msg, sp.into(), None);
-        self
-    }
-    pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
-        self.sub(Level::Warning, msg, MultiSpan::new(), None);
-        self
-    }
-    pub fn span_warn<S: Into<MultiSpan>>(&mut self,
-                                         sp: S,
-                                         msg: &str)
-                                         -> &mut DiagnosticBuilder<'a> {
-        self.sub(Level::Warning, msg, sp.into(), None);
-        self
-    }
-    pub fn help(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
-        self.sub(Level::Help, msg, MultiSpan::new(), None);
-        self
-    }
-    pub fn span_help<S: Into<MultiSpan>>(&mut self,
-                                         sp: S,
-                                         msg: &str)
-                                         -> &mut DiagnosticBuilder<'a> {
-        self.sub(Level::Help, msg, sp.into(), None);
-        self
-    }
-    /// Prints out a message with a suggested edit of the code.
-    ///
-    /// See `diagnostic::RenderSpan::Suggestion` for more information.
-    pub fn span_suggestion<S: Into<MultiSpan>>(&mut self,
-                                               sp: S,
-                                               msg: &str,
-                                               suggestion: String)
-                                               -> &mut DiagnosticBuilder<'a> {
-        self.sub(Level::Help,
-                 msg,
-                 MultiSpan::new(),
-                 Some(Suggestion(CodeSuggestion {
-                     msp: sp.into(),
-                     substitutes: vec![suggestion],
-                 })));
-        self
-    }
-
-    pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
-        self.span = sp.into();
-        self
-    }
-
-    pub fn code(&mut self, s: String) -> &mut Self {
-        self.code = Some(s);
-        self
-    }
-
-    pub fn message(&self) -> &str {
-        &self.message
-    }
-
-    pub fn level(&self) -> Level {
-        self.level
-    }
-
-    /// Convenience function for internal use, clients should use one of the
-    /// struct_* methods on Handler.
-    fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
-        DiagnosticBuilder::new_with_code(handler, level, None, message)
-    }
-
-    /// Convenience function for internal use, clients should use one of the
-    /// struct_* methods on Handler.
-    fn new_with_code(handler: &'a Handler,
-                     level: Level,
-                     code: Option<String>,
-                     message: &str)
-                     -> DiagnosticBuilder<'a> {
-        DiagnosticBuilder {
-            handler: handler,
-            level: level,
-            message: message.to_owned(),
-            code: code,
-            span: MultiSpan::new(),
-            children: vec![],
-        }
-    }
-
-    /// Convenience function for internal use, clients should use one of the
-    /// public methods above.
-    fn sub(&mut self,
-           level: Level,
-           message: &str,
-           span: MultiSpan,
-           render_span: Option<RenderSpan>) {
-        let sub = SubDiagnostic {
-            level: level,
-            message: message.to_owned(),
-            span: span,
-            render_span: render_span,
-        };
-        self.children.push(sub);
-    }
-}
-
-impl<'a> fmt::Debug for DiagnosticBuilder<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.message.fmt(f)
-    }
-}
-
-/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or
-/// we emit a bug.
-impl<'a> Drop for DiagnosticBuilder<'a> {
-    fn drop(&mut self) {
-        if !panicking() && !self.cancelled() {
-            let mut db =
-                DiagnosticBuilder::new(self.handler, Bug, "Error constructed but not emitted");
-            db.emit();
-            panic!();
-        }
-    }
-}
+pub use diagnostic::{Diagnostic, SubDiagnostic};
+pub use diagnostic_builder::DiagnosticBuilder;
 
 /// A handler deals with errors; certain errors
 /// (fatal, bug, unimpl) may cause immediate exit,
@@ -504,7 +293,6 @@ impl Handler {
                                                    sp: S,
                                                    msg: &str)
                                                    -> DiagnosticBuilder<'a> {
-        self.bump_err_count();
         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
         result.set_span(sp);
         result
@@ -514,21 +302,18 @@ impl Handler {
                                                              msg: &str,
                                                              code: &str)
                                                              -> DiagnosticBuilder<'a> {
-        self.bump_err_count();
         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
         result.set_span(sp);
         result.code(code.to_owned());
         result
     }
     pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
-        self.bump_err_count();
         DiagnosticBuilder::new(self, Level::Error, msg)
     }
     pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
                                                      sp: S,
                                                      msg: &str)
                                                      -> DiagnosticBuilder<'a> {
-        self.bump_err_count();
         let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
         result.set_span(sp);
         result
@@ -538,24 +323,16 @@ impl Handler {
                                                                msg: &str,
                                                                code: &str)
                                                                -> DiagnosticBuilder<'a> {
-        self.bump_err_count();
         let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
         result.set_span(sp);
         result.code(code.to_owned());
         result
     }
     pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
-        self.bump_err_count();
         DiagnosticBuilder::new(self, Level::Fatal, msg)
     }
 
     pub fn cancel(&self, err: &mut DiagnosticBuilder) {
-        if err.level == Level::Error || err.level == Level::Fatal {
-            self.err_count.set(self.err_count
-                .get()
-                .checked_sub(1)
-                .expect("cancelled an error but err_count is 0"));
-        }
         err.cancel();
     }
 
@@ -567,7 +344,6 @@ impl Handler {
 
     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
         self.emit(&sp.into(), msg, Fatal);
-        self.bump_err_count();
         self.panic_if_treat_err_as_bug();
         return FatalError;
     }
@@ -577,13 +353,11 @@ impl Handler {
                                                     code: &str)
                                                     -> FatalError {
         self.emit_with_code(&sp.into(), msg, code, Fatal);
-        self.bump_err_count();
         self.panic_if_treat_err_as_bug();
         return FatalError;
     }
     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.emit(&sp.into(), msg, Error);
-        self.bump_err_count();
         self.panic_if_treat_err_as_bug();
     }
     pub fn mut_span_err<'a, S: Into<MultiSpan>>(&'a self,
@@ -592,12 +366,10 @@ impl Handler {
                                                 -> DiagnosticBuilder<'a> {
         let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
         result.set_span(sp);
-        self.bump_err_count();
         result
     }
     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
         self.emit_with_code(&sp.into(), msg, code, Error);
-        self.bump_err_count();
         self.panic_if_treat_err_as_bug();
     }
     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
@@ -616,7 +388,6 @@ impl Handler {
     }
     pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.emit(&sp.into(), msg, Bug);
-        self.bump_err_count();
     }
     pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.emit(&sp.into(), msg, Note);
@@ -630,7 +401,6 @@ impl Handler {
         }
         let mut db = DiagnosticBuilder::new(self, Fatal, msg);
         db.emit();
-        self.bump_err_count();
         FatalError
     }
     pub fn err(&self, msg: &str) {
@@ -639,7 +409,6 @@ impl Handler {
         }
         let mut db = DiagnosticBuilder::new(self, Error, msg);
         db.emit();
-        self.bump_err_count();
     }
     pub fn warn(&self, msg: &str) {
         let mut db = DiagnosticBuilder::new(self, Warning, msg);
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 6f114e09a6c..c4b631c79b0 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -229,6 +229,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             id: LintId::of(PATTERNS_IN_FNS_WITHOUT_BODY),
             reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
         },
+        FutureIncompatibleInfo {
+            id: LintId::of(EXTRA_REQUIREMENT_IN_IMPL),
+            reference: "issue #37166 <https://github.com/rust-lang/rust/issues/37166>",
+        },
         ]);
 
     // Register renamed and removed lints
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 25e9f1f522c..6f450f57275 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -8,19 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::free_region::FreeRegionMap;
 use rustc::infer::{self, InferOk, TypeOrigin};
+use rustc::middle::free_region::FreeRegionMap;
 use rustc::ty;
 use rustc::traits::{self, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
 use rustc::ty::subst::{Subst, Substs};
 use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
+use rustc::util::common::ErrorReported;
 
 use syntax::ast;
 use syntax_pos::Span;
 
 use CrateCtxt;
 use super::assoc;
+use super::{Inherited, FnCtxt};
 
 /// Checks that a method from an impl conforms to the signature of
 /// the same method as declared in the trait.
@@ -39,188 +41,56 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                      impl_m_body_id: ast::NodeId,
                                      trait_m: &ty::Method<'tcx>,
                                      impl_trait_ref: &ty::TraitRef<'tcx>,
-                                     trait_item_span: Option<Span>) {
-    debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
-
-    debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}",
+                                     trait_item_span: Option<Span>,
+                                     old_broken_mode: bool) {
+    debug!("compare_impl_method(impl_trait_ref={:?})",
            impl_trait_ref);
 
-    let tcx = ccx.tcx;
-
-    let trait_to_impl_substs = &impl_trait_ref.substs;
-
-    // Try to give more informative error messages about self typing
-    // mismatches.  Note that any mismatch will also be detected
-    // below, where we construct a canonical function type that
-    // includes the self parameter as a normal parameter.  It's just
-    // that the error messages you get out of this code are a bit more
-    // inscrutable, particularly for cases where one method has no
-    // self.
-    match (&trait_m.explicit_self, &impl_m.explicit_self) {
-        (&ty::ExplicitSelfCategory::Static, &ty::ExplicitSelfCategory::Static) => {}
-        (&ty::ExplicitSelfCategory::Static, _) => {
-            let mut err = struct_span_err!(tcx.sess,
-                                           impl_m_span,
-                                           E0185,
-                                           "method `{}` has a `{}` declaration in the impl, but \
-                                            not in the trait",
-                                           trait_m.name,
-                                           impl_m.explicit_self);
-            err.span_label(impl_m_span,
-                           &format!("`{}` used in impl", impl_m.explicit_self));
-            if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
-                err.span_label(span,
-                               &format!("trait declared without `{}`", impl_m.explicit_self));
-            }
-            err.emit();
-            return;
-        }
-        (_, &ty::ExplicitSelfCategory::Static) => {
-            let mut err = struct_span_err!(tcx.sess,
-                                           impl_m_span,
-                                           E0186,
-                                           "method `{}` has a `{}` declaration in the trait, but \
-                                            not in the impl",
-                                           trait_m.name,
-                                           trait_m.explicit_self);
-            err.span_label(impl_m_span,
-                           &format!("expected `{}` in impl", trait_m.explicit_self));
-            if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
-                err.span_label(span, &format!("`{}` used in trait", trait_m.explicit_self));
-            }
-            err.emit();
-            return;
-        }
-        _ => {
-            // Let the type checker catch other errors below
-        }
+    if let Err(ErrorReported) = compare_self_type(ccx,
+                                                  impl_m,
+                                                  impl_m_span,
+                                                  trait_m) {
+        return;
     }
 
-    let num_impl_m_type_params = impl_m.generics.types.len();
-    let num_trait_m_type_params = trait_m.generics.types.len();
-    if num_impl_m_type_params != num_trait_m_type_params {
-        let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
-        let span = match tcx.map.expect_impl_item(impl_m_node_id).node {
-            ImplItemKind::Method(ref impl_m_sig, _) => {
-                if impl_m_sig.generics.is_parameterized() {
-                    impl_m_sig.generics.span
-                } else {
-                    impl_m_span
-                }
-            }
-            _ => bug!("{:?} is not a method", impl_m),
-        };
-
-        let mut err = struct_span_err!(tcx.sess,
-                                       span,
-                                       E0049,
-                                       "method `{}` has {} type parameter{} but its trait \
-                                        declaration has {} type parameter{}",
-                                       trait_m.name,
-                                       num_impl_m_type_params,
-                                       if num_impl_m_type_params == 1 { "" } else { "s" },
-                                       num_trait_m_type_params,
-                                       if num_trait_m_type_params == 1 {
-                                           ""
-                                       } else {
-                                           "s"
-                                       });
-
-        let mut suffix = None;
-
-        if let Some(span) = trait_item_span {
-            err.span_label(span,
-                           &format!("expected {}",
-                                    &if num_trait_m_type_params != 1 {
-                                        format!("{} type parameters", num_trait_m_type_params)
-                                    } else {
-                                        format!("{} type parameter", num_trait_m_type_params)
-                                    }));
-        } else {
-            suffix = Some(format!(", expected {}", num_trait_m_type_params));
-        }
-
-        err.span_label(span,
-                       &format!("found {}{}",
-                                &if num_impl_m_type_params != 1 {
-                                    format!("{} type parameters", num_impl_m_type_params)
-                                } else {
-                                    format!("1 type parameter")
-                                },
-                                suffix.as_ref().map(|s| &s[..]).unwrap_or("")));
-
-        err.emit();
+    if let Err(ErrorReported) = compare_number_of_generics(ccx,
+                                                           impl_m,
+                                                           impl_m_span,
+                                                           trait_m,
+                                                           trait_item_span) {
+        return;
+    }
 
+    if let Err(ErrorReported) = compare_number_of_method_arguments(ccx,
+                                                                   impl_m,
+                                                                   impl_m_span,
+                                                                   trait_m,
+                                                                   trait_item_span) {
         return;
     }
 
-    if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() {
-        let trait_number_args = trait_m.fty.sig.0.inputs.len();
-        let impl_number_args = impl_m.fty.sig.0.inputs.len();
-        let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id);
-        let trait_span = if let Some(trait_id) = trait_m_node_id {
-            match tcx.map.expect_trait_item(trait_id).node {
-                TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
-                    if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 {
-                        trait_number_args - 1
-                    } else {
-                        0
-                    }) {
-                        Some(arg.pat.span)
-                    } else {
-                        trait_item_span
-                    }
-                }
-                _ => bug!("{:?} is not a method", impl_m),
-            }
-        } else {
-            trait_item_span
-        };
-        let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
-        let impl_span = match tcx.map.expect_impl_item(impl_m_node_id).node {
-            ImplItemKind::Method(ref impl_m_sig, _) => {
-                if let Some(arg) = impl_m_sig.decl.inputs.get(if impl_number_args > 0 {
-                    impl_number_args - 1
-                } else {
-                    0
-                }) {
-                    arg.pat.span
-                } else {
-                    impl_m_span
-                }
-            }
-            _ => bug!("{:?} is not a method", impl_m),
-        };
-        let mut err = struct_span_err!(tcx.sess,
-                                       impl_span,
-                                       E0050,
-                                       "method `{}` has {} parameter{} but the declaration in \
-                                        trait `{}` has {}",
-                                       trait_m.name,
-                                       impl_number_args,
-                                       if impl_number_args == 1 { "" } else { "s" },
-                                       tcx.item_path_str(trait_m.def_id),
-                                       trait_number_args);
-        if let Some(trait_span) = trait_span {
-            err.span_label(trait_span,
-                           &format!("trait requires {}",
-                                    &if trait_number_args != 1 {
-                                        format!("{} parameters", trait_number_args)
-                                    } else {
-                                        format!("{} parameter", trait_number_args)
-                                    }));
-        }
-        err.span_label(impl_span,
-                       &format!("expected {}, found {}",
-                                &if trait_number_args != 1 {
-                                    format!("{} parameters", trait_number_args)
-                                } else {
-                                    format!("{} parameter", trait_number_args)
-                                },
-                                impl_number_args));
-        err.emit();
+    if let Err(ErrorReported) = compare_predicate_entailment(ccx,
+                                                             impl_m,
+                                                             impl_m_span,
+                                                             impl_m_body_id,
+                                                             trait_m,
+                                                             impl_trait_ref,
+                                                             old_broken_mode) {
         return;
     }
+}
+
+fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                          impl_m: &ty::Method<'tcx>,
+                                          impl_m_span: Span,
+                                          impl_m_body_id: ast::NodeId,
+                                          trait_m: &ty::Method<'tcx>,
+                                          impl_trait_ref: &ty::TraitRef<'tcx>,
+                                          old_broken_mode: bool)
+                                          -> Result<(), ErrorReported> {
+    let tcx = ccx.tcx;
+
+    let trait_to_impl_substs = &impl_trait_ref.substs;
 
     // This code is best explained by example. Consider a trait:
     //
@@ -301,50 +171,48 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     debug!("compare_impl_method: trait_to_skol_substs={:?}",
            trait_to_skol_substs);
 
-    // Check region bounds. FIXME(@jroesch) refactor this away when removing
-    // ParamBounds.
-    if !check_region_bounds_on_impl_method(ccx,
-                                           impl_m_span,
-                                           impl_m,
-                                           &trait_m.generics,
-                                           &impl_m.generics,
-                                           trait_to_skol_substs,
-                                           impl_to_skol_substs) {
-        return;
-    }
-
-    tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|mut infcx| {
-        let mut fulfillment_cx = traits::FulfillmentContext::new();
-
-        // Create obligations for each predicate declared by the impl
-        // definition in the context of the trait's parameter
-        // environment. We can't just use `impl_env.caller_bounds`,
-        // however, because we want to replace all late-bound regions with
-        // region variables.
-        let impl_predicates = tcx.lookup_predicates(impl_m.predicates.parent.unwrap());
-        let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs);
-
-        debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
-
-        // This is the only tricky bit of the new way we check implementation methods
-        // We need to build a set of predicates where only the method-level bounds
-        // are from the trait and we assume all other bounds from the implementation
-        // to be previously satisfied.
-        //
-        // We then register the obligations from the impl_m and check to see
-        // if all constraints hold.
-        hybrid_preds.predicates
-            .extend(trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
-
-        // Construct trait parameter environment and then shift it into the skolemized viewpoint.
-        // The key step here is to update the caller_bounds's predicates to be
-        // the new hybrid bounds we computed.
-        let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
-        let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates);
-        let trait_param_env =
-            traits::normalize_param_env_or_error(tcx, trait_param_env, normalize_cause.clone());
-        // FIXME(@jroesch) this seems ugly, but is a temporary change
-        infcx.parameter_environment = trait_param_env;
+    // Check region bounds.
+    check_region_bounds_on_impl_method(ccx,
+                                       impl_m_span,
+                                       impl_m,
+                                       &trait_m.generics,
+                                       &impl_m.generics,
+                                       trait_to_skol_substs,
+                                       impl_to_skol_substs)?;
+
+    // Create obligations for each predicate declared by the impl
+    // definition in the context of the trait's parameter
+    // environment. We can't just use `impl_env.caller_bounds`,
+    // however, because we want to replace all late-bound regions with
+    // region variables.
+    let impl_predicates = tcx.lookup_predicates(impl_m.predicates.parent.unwrap());
+    let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs);
+
+    debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
+
+    // This is the only tricky bit of the new way we check implementation methods
+    // We need to build a set of predicates where only the method-level bounds
+    // are from the trait and we assume all other bounds from the implementation
+    // to be previously satisfied.
+    //
+    // We then register the obligations from the impl_m and check to see
+    // if all constraints hold.
+    hybrid_preds.predicates
+                .extend(trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
+
+    // Construct trait parameter environment and then shift it into the skolemized viewpoint.
+    // The key step here is to update the caller_bounds's predicates to be
+    // the new hybrid bounds we computed.
+    let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
+    let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates);
+    let trait_param_env = traits::normalize_param_env_or_error(tcx,
+                                                               trait_param_env,
+                                                               normalize_cause.clone());
+
+    tcx.infer_ctxt(None, Some(trait_param_env), Reveal::NotSpecializable).enter(|infcx| {
+        let inh = Inherited::new(ccx, infcx);
+        let infcx = &inh.infcx;
+        let fulfillment_cx = &inh.fulfillment_cx;
 
         debug!("compare_impl_method: caller_bounds={:?}",
                infcx.parameter_environment.caller_bounds);
@@ -362,10 +230,15 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             let cause = traits::ObligationCause {
                 span: impl_m_span,
                 body_id: impl_m_body_id,
-                code: traits::ObligationCauseCode::CompareImplMethodObligation,
+                code: traits::ObligationCauseCode::CompareImplMethodObligation {
+                    item_name: impl_m.name,
+                    impl_item_def_id: impl_m.def_id,
+                    trait_item_def_id: trait_m.def_id,
+                    lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None },
+                },
             };
 
-            fulfillment_cx.register_predicate_obligation(
+            fulfillment_cx.borrow_mut().register_predicate_obligation(
                 &infcx,
                 traits::Obligation::new(cause, predicate));
         }
@@ -387,15 +260,18 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let tcx = infcx.tcx;
         let origin = TypeOrigin::MethodCompatCheck(impl_m_span);
 
-        let (impl_sig, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
-                                                       infer::HigherRankedType,
-                                                       &impl_m.fty.sig);
-        let impl_sig = impl_sig.subst(tcx, impl_to_skol_substs);
-        let impl_sig = assoc::normalize_associated_types_in(&infcx,
-                                                            &mut fulfillment_cx,
-                                                            impl_m_span,
-                                                            impl_m_body_id,
-                                                            &impl_sig);
+        let (impl_sig, _) =
+            infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
+                                                            infer::HigherRankedType,
+                                                            &impl_m.fty.sig);
+        let impl_sig =
+            impl_sig.subst(tcx, impl_to_skol_substs);
+        let impl_sig =
+            assoc::normalize_associated_types_in(&infcx,
+                                                 &mut fulfillment_cx.borrow_mut(),
+                                                 impl_m_span,
+                                                 impl_m_body_id,
+                                                 &impl_sig);
         let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
             unsafety: impl_m.fty.unsafety,
             abi: impl_m.fty.abi,
@@ -403,14 +279,17 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         }));
         debug!("compare_impl_method: impl_fty={:?}", impl_fty);
 
-        let trait_sig = tcx.liberate_late_bound_regions(infcx.parameter_environment.free_id_outlive,
-                                         &trait_m.fty.sig);
-        let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs);
-        let trait_sig = assoc::normalize_associated_types_in(&infcx,
-                                                             &mut fulfillment_cx,
-                                                             impl_m_span,
-                                                             impl_m_body_id,
-                                                             &trait_sig);
+        let trait_sig = tcx.liberate_late_bound_regions(
+            infcx.parameter_environment.free_id_outlive,
+            &trait_m.fty.sig);
+        let trait_sig =
+            trait_sig.subst(tcx, trait_to_skol_substs);
+        let trait_sig =
+            assoc::normalize_associated_types_in(&infcx,
+                                                 &mut fulfillment_cx.borrow_mut(),
+                                                 impl_m_span,
+                                                 impl_m_body_id,
+                                                 &trait_sig);
         let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
             unsafety: trait_m.fty.unsafety,
             abi: trait_m.fty.abi,
@@ -449,171 +328,377 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                 })),
                                 &terr);
             diag.emit();
-            return;
+            return Err(ErrorReported);
         }
 
         // Check that all obligations are satisfied by the implementation's
         // version.
-        if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
+        if let Err(ref errors) = fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
             infcx.report_fulfillment_errors(errors);
-            return;
+            return Err(ErrorReported);
         }
 
         // Finally, resolve all regions. This catches wily misuses of
-        // lifetime parameters. We have to build up a plausible lifetime
-        // environment based on what we find in the trait. We could also
-        // include the obligations derived from the method argument types,
-        // but I don't think it's necessary -- after all, those are still
-        // in effect when type-checking the body, and all the
-        // where-clauses in the header etc should be implied by the trait
-        // anyway, so it shouldn't be needed there either. Anyway, we can
-        // always add more relations later (it's backwards compat).
-        let mut free_regions = FreeRegionMap::new();
-        free_regions.relate_free_regions_from_predicates(
-            &infcx.parameter_environment.caller_bounds);
-
-        infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
-    });
+        // lifetime parameters.
+        if old_broken_mode {
+            // FIXME(#18937) -- this is how the code used to
+            // work. This is buggy because the fulfillment cx creates
+            // region obligations that get overlooked.  The right
+            // thing to do is the code below. But we keep this old
+            // pass around temporarily.
+            let mut free_regions = FreeRegionMap::new();
+            free_regions.relate_free_regions_from_predicates(
+                &infcx.parameter_environment.caller_bounds);
+            infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
+        } else {
+            let fcx = FnCtxt::new(&inh, tcx.types.err, impl_m_body_id);
+            fcx.regionck_item(impl_m_body_id, impl_m_span, &[]);
+        }
+
+        Ok(())
+    })
+}
 
-    fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                                    span: Span,
-                                                    impl_m: &ty::Method<'tcx>,
-                                                    trait_generics: &ty::Generics<'tcx>,
-                                                    impl_generics: &ty::Generics<'tcx>,
-                                                    trait_to_skol_substs: &Substs<'tcx>,
-                                                    impl_to_skol_substs: &Substs<'tcx>)
-                                                    -> bool {
-
-        let trait_params = &trait_generics.regions[..];
-        let impl_params = &impl_generics.regions[..];
-
-        debug!("check_region_bounds_on_impl_method: \
-               trait_generics={:?} \
-               impl_generics={:?} \
-               trait_to_skol_substs={:?} \
-               impl_to_skol_substs={:?}",
-               trait_generics,
-               impl_generics,
-               trait_to_skol_substs,
-               impl_to_skol_substs);
-
-        // Must have same number of early-bound lifetime parameters.
-        // Unfortunately, if the user screws up the bounds, then this
-        // will change classification between early and late.  E.g.,
-        // if in trait we have `<'a,'b:'a>`, and in impl we just have
-        // `<'a,'b>`, then we have 2 early-bound lifetime parameters
-        // in trait but 0 in the impl. But if we report "expected 2
-        // but found 0" it's confusing, because it looks like there
-        // are zero. Since I don't quite know how to phrase things at
-        // the moment, give a kind of vague error message.
-        if trait_params.len() != impl_params.len() {
-            struct_span_err!(ccx.tcx.sess,
-                             span,
-                             E0195,
-                             "lifetime parameters or bounds on method `{}` do not match the \
-                              trait declaration",
-                             impl_m.name)
-                .span_label(span, &format!("lifetimes do not match trait"))
-                .emit();
-            return false;
+fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                                span: Span,
+                                                impl_m: &ty::Method<'tcx>,
+                                                trait_generics: &ty::Generics<'tcx>,
+                                                impl_generics: &ty::Generics<'tcx>,
+                                                trait_to_skol_substs: &Substs<'tcx>,
+                                                impl_to_skol_substs: &Substs<'tcx>)
+                                                -> Result<(), ErrorReported> {
+    let trait_params = &trait_generics.regions[..];
+    let impl_params = &impl_generics.regions[..];
+
+    debug!("check_region_bounds_on_impl_method: \
+            trait_generics={:?} \
+            impl_generics={:?} \
+            trait_to_skol_substs={:?} \
+            impl_to_skol_substs={:?}",
+           trait_generics,
+           impl_generics,
+           trait_to_skol_substs,
+           impl_to_skol_substs);
+
+    // Must have same number of early-bound lifetime parameters.
+    // Unfortunately, if the user screws up the bounds, then this
+    // will change classification between early and late.  E.g.,
+    // if in trait we have `<'a,'b:'a>`, and in impl we just have
+    // `<'a,'b>`, then we have 2 early-bound lifetime parameters
+    // in trait but 0 in the impl. But if we report "expected 2
+    // but found 0" it's confusing, because it looks like there
+    // are zero. Since I don't quite know how to phrase things at
+    // the moment, give a kind of vague error message.
+    if trait_params.len() != impl_params.len() {
+        struct_span_err!(ccx.tcx.sess,
+                         span,
+                         E0195,
+                         "lifetime parameters or bounds on method `{}` do not match the \
+                          trait declaration",
+                         impl_m.name)
+            .span_label(span, &format!("lifetimes do not match trait"))
+            .emit();
+        return Err(ErrorReported);
+    }
+
+    return Ok(());
+}
+
+fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
+                                                     terr: &TypeError,
+                                                     origin: TypeOrigin,
+                                                     impl_m: &ty::Method,
+                                                     impl_sig: ty::FnSig<'tcx>,
+                                                     trait_m: &ty::Method,
+                                                     trait_sig: ty::FnSig<'tcx>)
+                                                     -> (Span, Option<Span>) {
+    let tcx = infcx.tcx;
+    let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
+    let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node {
+        ImplItemKind::Method(ref impl_m_sig, _) => {
+            (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter())
+        }
+        _ => bug!("{:?} is not a method", impl_m),
+    };
+
+    match *terr {
+        TypeError::Mutability => {
+            if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
+                let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
+                    TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+                        trait_m_sig.decl.inputs.iter()
+                    }
+                    _ => bug!("{:?} is not a MethodTraitItem", trait_m),
+                };
+
+                impl_m_iter.zip(trait_m_iter)
+                           .find(|&(ref impl_arg, ref trait_arg)| {
+                               match (&impl_arg.ty.node, &trait_arg.ty.node) {
+                                   (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
+                                   (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => {
+                                       impl_mt.mutbl != trait_mt.mutbl
+                                   }
+                                   _ => false,
+                               }
+                           })
+                           .map(|(ref impl_arg, ref trait_arg)| {
+                               match (impl_arg.to_self(), trait_arg.to_self()) {
+                                   (Some(impl_self), Some(trait_self)) => {
+                                       (impl_self.span, Some(trait_self.span))
+                                   }
+                                   (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
+                                   _ => {
+                                       bug!("impl and trait fns have different first args, impl: \
+                                             {:?}, trait: {:?}",
+                                            impl_arg,
+                                            trait_arg)
+                                   }
+                               }
+                           })
+                           .unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
+            } else {
+                (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+            }
         }
+        TypeError::Sorts(ExpectedFound { .. }) => {
+            if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
+                let (trait_m_output, trait_m_iter) =
+                    match tcx.map.expect_trait_item(trait_m_node_id).node {
+                        TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+                            (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
+                        }
+                        _ => bug!("{:?} is not a MethodTraitItem", trait_m),
+                    };
 
-        return true;
+                let impl_iter = impl_sig.inputs.iter();
+                let trait_iter = trait_sig.inputs.iter();
+                impl_iter.zip(trait_iter)
+                         .zip(impl_m_iter)
+                         .zip(trait_m_iter)
+                         .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
+                             match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) {
+                                 Ok(_) => None,
+                                 Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
+                             }
+                         })
+                         .next()
+                         .unwrap_or_else(|| {
+                             if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output)
+                                     .is_err() {
+                                         (impl_m_output.span(), Some(trait_m_output.span()))
+                                     } else {
+                                         (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+                                     }
+                         })
+            } else {
+                (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+            }
+        }
+        _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)),
     }
+}
 
-    fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
-                                                         terr: &TypeError,
-                                                         origin: TypeOrigin,
-                                                         impl_m: &ty::Method,
-                                                         impl_sig: ty::FnSig<'tcx>,
-                                                         trait_m: &ty::Method,
-                                                         trait_sig: ty::FnSig<'tcx>)
-                                                         -> (Span, Option<Span>) {
-        let tcx = infcx.tcx;
+fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                               impl_m: &ty::Method<'tcx>,
+                               impl_m_span: Span,
+                               trait_m: &ty::Method<'tcx>)
+                               -> Result<(), ErrorReported>
+{
+    let tcx = ccx.tcx;
+    // Try to give more informative error messages about self typing
+    // mismatches.  Note that any mismatch will also be detected
+    // below, where we construct a canonical function type that
+    // includes the self parameter as a normal parameter.  It's just
+    // that the error messages you get out of this code are a bit more
+    // inscrutable, particularly for cases where one method has no
+    // self.
+    match (&trait_m.explicit_self, &impl_m.explicit_self) {
+        (&ty::ExplicitSelfCategory::Static, &ty::ExplicitSelfCategory::Static) => {}
+        (&ty::ExplicitSelfCategory::Static, _) => {
+            let mut err = struct_span_err!(tcx.sess,
+                                           impl_m_span,
+                                           E0185,
+                                           "method `{}` has a `{}` declaration in the impl, but \
+                                            not in the trait",
+                                           trait_m.name,
+                                           impl_m.explicit_self);
+            err.span_label(impl_m_span,
+                           &format!("`{}` used in impl", impl_m.explicit_self));
+            if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
+                err.span_label(span,
+                               &format!("trait declared without `{}`", impl_m.explicit_self));
+            }
+            err.emit();
+            return Err(ErrorReported);
+        }
+        (_, &ty::ExplicitSelfCategory::Static) => {
+            let mut err = struct_span_err!(tcx.sess,
+                                           impl_m_span,
+                                           E0186,
+                                           "method `{}` has a `{}` declaration in the trait, but \
+                                            not in the impl",
+                                           trait_m.name,
+                                           trait_m.explicit_self);
+            err.span_label(impl_m_span,
+                           &format!("expected `{}` in impl", trait_m.explicit_self));
+            if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
+                err.span_label(span, &format!("`{}` used in trait", trait_m.explicit_self));
+            }
+            err.emit();
+            return Err(ErrorReported);
+        }
+        _ => {
+            // Let the type checker catch other errors below
+        }
+    }
+
+    Ok(())
+}
+
+fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                        impl_m: &ty::Method<'tcx>,
+                                        impl_m_span: Span,
+                                        trait_m: &ty::Method<'tcx>,
+                                        trait_item_span: Option<Span>)
+                                        -> Result<(), ErrorReported> {
+    let tcx = ccx.tcx;
+    let num_impl_m_type_params = impl_m.generics.types.len();
+    let num_trait_m_type_params = trait_m.generics.types.len();
+    if num_impl_m_type_params != num_trait_m_type_params {
         let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
-        let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node {
+        let span = match tcx.map.expect_impl_item(impl_m_node_id).node {
             ImplItemKind::Method(ref impl_m_sig, _) => {
-                (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter())
+                if impl_m_sig.generics.is_parameterized() {
+                    impl_m_sig.generics.span
+                } else {
+                    impl_m_span
+                }
             }
             _ => bug!("{:?} is not a method", impl_m),
         };
 
-        match *terr {
-            TypeError::Mutability => {
-                if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
-                    let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
-                        TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
-                            trait_m_sig.decl.inputs.iter()
-                        }
-                        _ => bug!("{:?} is not a MethodTraitItem", trait_m),
-                    };
+        let mut err = struct_span_err!(tcx.sess,
+                                       span,
+                                       E0049,
+                                       "method `{}` has {} type parameter{} but its trait \
+                                        declaration has {} type parameter{}",
+                                       trait_m.name,
+                                       num_impl_m_type_params,
+                                       if num_impl_m_type_params == 1 { "" } else { "s" },
+                                       num_trait_m_type_params,
+                                       if num_trait_m_type_params == 1 {
+                                           ""
+                                       } else {
+                                           "s"
+                                       });
 
-                    impl_m_iter.zip(trait_m_iter)
-                        .find(|&(ref impl_arg, ref trait_arg)| {
-                            match (&impl_arg.ty.node, &trait_arg.ty.node) {
-                                (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
-                                (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => {
-                                    impl_mt.mutbl != trait_mt.mutbl
-                                }
-                                _ => false,
-                            }
-                        })
-                        .map(|(ref impl_arg, ref trait_arg)| {
-                            match (impl_arg.to_self(), trait_arg.to_self()) {
-                                (Some(impl_self), Some(trait_self)) => {
-                                    (impl_self.span, Some(trait_self.span))
-                                }
-                                (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
-                                _ => {
-                                    bug!("impl and trait fns have different first args, impl: \
-                                          {:?}, trait: {:?}",
-                                         impl_arg,
-                                         trait_arg)
-                                }
-                            }
-                        })
-                        .unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
-                } else {
-                    (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+        let mut suffix = None;
+
+        if let Some(span) = trait_item_span {
+            err.span_label(span,
+                           &format!("expected {}",
+                                    &if num_trait_m_type_params != 1 {
+                                        format!("{} type parameters", num_trait_m_type_params)
+                                    } else {
+                                        format!("{} type parameter", num_trait_m_type_params)
+                                    }));
+        } else {
+            suffix = Some(format!(", expected {}", num_trait_m_type_params));
+        }
+
+        err.span_label(span,
+                       &format!("found {}{}",
+                                &if num_impl_m_type_params != 1 {
+                                    format!("{} type parameters", num_impl_m_type_params)
+                                } else {
+                                    format!("1 type parameter")
+                                },
+                                suffix.as_ref().map(|s| &s[..]).unwrap_or("")));
+
+        err.emit();
+
+        return Err(ErrorReported);
+    }
+
+    Ok(())
+}
+
+fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                                impl_m: &ty::Method<'tcx>,
+                                                impl_m_span: Span,
+                                                trait_m: &ty::Method<'tcx>,
+                                                trait_item_span: Option<Span>)
+                                                -> Result<(), ErrorReported> {
+    let tcx = ccx.tcx;
+    if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() {
+        let trait_number_args = trait_m.fty.sig.0.inputs.len();
+        let impl_number_args = impl_m.fty.sig.0.inputs.len();
+        let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id);
+        let trait_span = if let Some(trait_id) = trait_m_node_id {
+            match tcx.map.expect_trait_item(trait_id).node {
+                TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+                    if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 {
+                        trait_number_args - 1
+                    } else {
+                        0
+                    }) {
+                        Some(arg.pat.span)
+                    } else {
+                        trait_item_span
+                    }
                 }
+                _ => bug!("{:?} is not a method", impl_m),
             }
-            TypeError::Sorts(ExpectedFound { .. }) => {
-                if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
-                    let (trait_m_output, trait_m_iter) =
-                        match tcx.map.expect_trait_item(trait_m_node_id).node {
-                            TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
-                                (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
-                            }
-                            _ => bug!("{:?} is not a MethodTraitItem", trait_m),
-                        };
-
-                    let impl_iter = impl_sig.inputs.iter();
-                    let trait_iter = trait_sig.inputs.iter();
-                    impl_iter.zip(trait_iter)
-                        .zip(impl_m_iter)
-                        .zip(trait_m_iter)
-                        .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
-                            match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) {
-                                Ok(_) => None,
-                                Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
-                            }
-                        })
-                        .next()
-                        .unwrap_or_else(|| {
-                            if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output)
-                                .is_err() {
-                                (impl_m_output.span(), Some(trait_m_output.span()))
-                            } else {
-                                (origin.span(), tcx.map.span_if_local(trait_m.def_id))
-                            }
-                        })
+        } else {
+            trait_item_span
+        };
+        let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
+        let impl_span = match tcx.map.expect_impl_item(impl_m_node_id).node {
+            ImplItemKind::Method(ref impl_m_sig, _) => {
+                if let Some(arg) = impl_m_sig.decl.inputs.get(if impl_number_args > 0 {
+                    impl_number_args - 1
                 } else {
-                    (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+                    0
+                }) {
+                    arg.pat.span
+                } else {
+                    impl_m_span
                 }
             }
-            _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)),
+            _ => bug!("{:?} is not a method", impl_m),
+        };
+        let mut err = struct_span_err!(tcx.sess,
+                                       impl_span,
+                                       E0050,
+                                       "method `{}` has {} parameter{} but the declaration in \
+                                        trait `{}` has {}",
+                                       trait_m.name,
+                                       impl_number_args,
+                                       if impl_number_args == 1 { "" } else { "s" },
+                                       tcx.item_path_str(trait_m.def_id),
+                                       trait_number_args);
+        if let Some(trait_span) = trait_span {
+            err.span_label(trait_span,
+                           &format!("trait requires {}",
+                                    &if trait_number_args != 1 {
+                                        format!("{} parameters", trait_number_args)
+                                    } else {
+                                        format!("{} parameter", trait_number_args)
+                                    }));
         }
+        err.span_label(impl_span,
+                       &format!("expected {}, found {}",
+                                &if trait_number_args != 1 {
+                                    format!("{} parameters", trait_number_args)
+                                } else {
+                                    format!("{} parameter", trait_number_args)
+                                },
+                                impl_number_args));
+        err.emit();
+        return Err(ErrorReported);
     }
+
+    Ok(())
 }
 
 pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 75a14bb3db9..4e0f455e362 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -407,22 +407,26 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> {
         where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R
     {
         let ccx = self.ccx;
-        self.infcx.enter(|infcx| {
-            f(Inherited {
-                ccx: ccx,
-                infcx: infcx,
-                fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
-                locals: RefCell::new(NodeMap()),
-                deferred_call_resolutions: RefCell::new(DefIdMap()),
-                deferred_cast_checks: RefCell::new(Vec::new()),
-                anon_types: RefCell::new(DefIdMap()),
-                deferred_obligations: RefCell::new(Vec::new()),
-            })
-        })
+        self.infcx.enter(|infcx| f(Inherited::new(ccx, infcx)))
     }
 }
 
 impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
+    pub fn new(ccx: &'a CrateCtxt<'a, 'gcx>,
+               infcx: InferCtxt<'a, 'gcx, 'tcx>)
+               -> Self {
+        Inherited {
+            ccx: ccx,
+            infcx: infcx,
+            fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
+            locals: RefCell::new(NodeMap()),
+            deferred_call_resolutions: RefCell::new(DefIdMap()),
+            deferred_cast_checks: RefCell::new(Vec::new()),
+            anon_types: RefCell::new(DefIdMap()),
+            deferred_obligations: RefCell::new(Vec::new()),
+        }
+    }
+
     fn normalize_associated_types_in<T>(&self,
                                         span: Span,
                                         body_id: ast::NodeId,
@@ -1024,13 +1028,26 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
                     let trait_span = tcx.map.span_if_local(ty_trait_item.def_id());
                     if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item {
+                        let err_count = tcx.sess.err_count();
                         compare_impl_method(ccx,
                                             &impl_method,
                                             impl_item.span,
                                             body.id,
                                             &trait_method,
                                             &impl_trait_ref,
-                                            trait_span);
+                                            trait_span,
+                                            true); // start with old-broken-mode
+                        if err_count == tcx.sess.err_count() {
+                            // old broken mode did not report an error. Try with the new mode.
+                            compare_impl_method(ccx,
+                                                &impl_method,
+                                                impl_item.span,
+                                                body.id,
+                                                &trait_method,
+                                                &impl_trait_ref,
+                                                trait_span,
+                                                false); // use the new mode
+                        }
                     } else {
                         let mut err = struct_span_err!(tcx.sess, impl_item.span, E0324,
                                   "item `{}` is an associated method, \
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 939deee27c6..9bfe80dba9d 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -356,7 +356,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
             debug!("visit_region_obligations: r_o={:?} cause={:?}",
                    r_o, r_o.cause);
             let sup_type = self.resolve_type(r_o.sup_type);
-            let origin = self.code_to_origin(r_o.cause.span, sup_type, &r_o.cause.code);
+            let origin = self.code_to_origin(&r_o.cause, sup_type);
             self.type_must_outlive(origin, sup_type, r_o.sub_region);
         }
 
@@ -366,16 +366,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn code_to_origin(&self,
-                      span: Span,
-                      sup_type: Ty<'tcx>,
-                      code: &traits::ObligationCauseCode<'tcx>)
+                      cause: &traits::ObligationCause<'tcx>,
+                      sup_type: Ty<'tcx>)
                       -> SubregionOrigin<'tcx> {
-        match *code {
-            traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) =>
-                infer::ReferenceOutlivesReferent(ref_type, span),
-            _ =>
-                infer::RelateParamBound(span, sup_type),
-        }
+        SubregionOrigin::from_obligation_cause(cause,
+                                               || infer::RelateParamBound(cause.span, sup_type))
     }
 
     /// This method populates the region map's `free_region_map`. It walks over the transformed
@@ -1474,7 +1469,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
         assert!(!ty.has_escaping_regions());
 
-        let components = self.outlives_components(ty);
+        let components = self.tcx.outlives_components(ty);
         self.components_must_outlive(origin, components, region);
     }
 
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 7dd850180d4..be012d8976f 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -458,7 +458,7 @@ Rust only supports variadic parameters for interoperability with C code in its
 FFI. As such, variadic parameters can only be used with functions which are
 using the C ABI. Examples of erroneous code:
 
-```compile_fail,E0045
+```compile_fail
 #![feature(unboxed_closures)]
 
 extern "rust-call" { fn foo(x: u8, ...); }
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index d83d3a6c5cf..d99850332c3 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -67,7 +67,7 @@ pub struct Span {
 ///   the error, and would be rendered with `^^^`.
 /// - they can have a *label*. In this case, the label is written next
 ///   to the mark in the snippet when we render.
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub struct MultiSpan {
     primary_spans: Vec<Span>,
     span_labels: Vec<(Span, String)>,
diff --git a/src/test/compile-fail/issue-14853.rs b/src/test/compile-fail/issue-14853.rs
index c4d88267032..e4da3e4fa43 100644
--- a/src/test/compile-fail/issue-14853.rs
+++ b/src/test/compile-fail/issue-14853.rs
@@ -20,7 +20,7 @@ struct X { data: u32 }
 
 impl Something for X {
     fn yay<T: Str>(_:Option<X>, thing: &[T]) {
-    //~^ ERROR the requirement `T: Str` appears on the impl method
+    //~^ ERROR E0276
     }
 }
 
diff --git a/src/test/compile-fail/issue-18937.rs b/src/test/compile-fail/issue-18937.rs
new file mode 100644
index 00000000000..8ac66bb44d2
--- /dev/null
+++ b/src/test/compile-fail/issue-18937.rs
@@ -0,0 +1,53 @@
+// Copyright 2016 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.
+
+// Regression test for #18937.
+
+#![deny(extra_requirement_in_impl)]
+
+use std::fmt;
+
+#[derive(Debug)]
+struct MyString<'a>(&'a String);
+
+struct B {
+    list: Vec<Box<fmt::Debug>>,
+}
+
+trait A<'a> {
+    fn foo<F>(&mut self, f: F)
+        where F: fmt::Debug + 'a,
+              Self: Sized;
+}
+
+impl<'a> A<'a> for B {
+    fn foo<F>(&mut self, f: F) //~ ERROR E0276
+        //~^ WARNING future release
+        where F: fmt::Debug + 'static,
+    {
+        self.list.push(Box::new(f));
+    }
+}
+
+fn main() {
+    let mut b = B { list: Vec::new() };
+
+    // Create a borrowed pointer, put it in `b`, then drop what's borrowing it
+    let a = "hello".to_string();
+    b.foo(MyString(&a));
+
+    // Drop the data which `b` has a reference to
+    drop(a);
+
+    // Use the data, probably segfaulting
+    for b in b.list.iter() {
+        println!("{:?}", b);
+    }
+}
diff --git a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs
index 6e60a373d9b..1d4ffe0690d 100644
--- a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs
+++ b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs
@@ -52,7 +52,7 @@ impl<'a, 't> Foo<'a, 't> for &'a isize {
     }
 
     fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
-        //~^ ERROR lifetime bound not satisfied
+        //~^ ERROR E0276
     }
 }
 
diff --git a/src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs b/src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs
index 9c7721589d9..70055a10181 100644
--- a/src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs
+++ b/src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
+// compile-flags: -Z parse-only -Z continue-parse-after-error
 
 // Test you can't use a higher-ranked trait bound inside of a qualified
 // path (just won't parse).
diff --git a/src/test/parse-fail/generic-non-trailing-defaults.rs b/src/test/parse-fail/generic-non-trailing-defaults.rs
index 26ee6ce80d6..2bb593258ae 100644
--- a/src/test/parse-fail/generic-non-trailing-defaults.rs
+++ b/src/test/parse-fail/generic-non-trailing-defaults.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
+// compile-flags: -Z parse-only -Z continue-parse-after-error
 
 struct Heap;
 
diff --git a/src/test/parse-fail/issue-17904.rs b/src/test/parse-fail/issue-17904.rs
index 580b8c66c74..de5aeb02ab7 100644
--- a/src/test/parse-fail/issue-17904.rs
+++ b/src/test/parse-fail/issue-17904.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
+// compile-flags: -Z parse-only -Z continue-parse-after-error
 
 struct Baz<U> where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax.
 struct Baz<U> where U: Eq(U) -> R; // Notice this parses as well.
diff --git a/src/test/parse-fail/lex-bad-octal-literal.rs b/src/test/parse-fail/lex-bad-octal-literal.rs
index bf9880cb6cf..c8406af52ae 100644
--- a/src/test/parse-fail/lex-bad-octal-literal.rs
+++ b/src/test/parse-fail/lex-bad-octal-literal.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// compile-flags: -Z parse-only -Z continue-parse-after-error
+
 fn main() {
     0o18; //~ ERROR invalid digit for a base 8 literal
     0o1234_9_5670;  //~ ERROR invalid digit for a base 8 literal
diff --git a/src/test/parse-fail/lifetime-no-keyword.rs b/src/test/parse-fail/lifetime-no-keyword.rs
index 9ca81d9918e..a8771ae93af 100644
--- a/src/test/parse-fail/lifetime-no-keyword.rs
+++ b/src/test/parse-fail/lifetime-no-keyword.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
+// compile-flags: -Z parse-only -Z continue-parse-after-error
 
 fn foo<'a>(a: &'a isize) { }
 fn bar(a: &'static isize) { }
diff --git a/src/test/parse-fail/raw-byte-string-literals.rs b/src/test/parse-fail/raw-byte-string-literals.rs
index d6be8fce53e..2e33f98add6 100644
--- a/src/test/parse-fail/raw-byte-string-literals.rs
+++ b/src/test/parse-fail/raw-byte-string-literals.rs
@@ -8,10 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
+// compile-flags: -Z parse-only -Z continue-parse-after-error
 
 
 pub fn main() {
-    br"é";  //~ raw byte string must be ASCII
-    br##~"a"~##;  //~ only `#` is allowed in raw string delimitation
+    br"é";  //~ ERROR raw byte string must be ASCII
+    br##~"a"~##;  //~ ERROR only `#` is allowed in raw string delimitation
 }
diff --git a/src/test/parse-fail/removed-syntax-field-let.rs b/src/test/parse-fail/removed-syntax-field-let.rs
index 4e542fd7477..6deb3bb2e95 100644
--- a/src/test/parse-fail/removed-syntax-field-let.rs
+++ b/src/test/parse-fail/removed-syntax-field-let.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
+// compile-flags: -Z parse-only -Z continue-parse-after-error
 
 struct s {
     let foo: (),
diff --git a/src/test/parse-fail/syntax-trait-polarity.rs b/src/test/parse-fail/syntax-trait-polarity.rs
index c0d85034383..1971ffeaf26 100644
--- a/src/test/parse-fail/syntax-trait-polarity.rs
+++ b/src/test/parse-fail/syntax-trait-polarity.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
+// compile-flags: -Z parse-only -Z continue-parse-after-error
 
 #![feature(optin_builtin_traits)]
 
diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/parse-fail/trailing-plus-in-bounds.rs
index 4abdbad9a03..44bb1f930c7 100644
--- a/src/test/parse-fail/trailing-plus-in-bounds.rs
+++ b/src/test/parse-fail/trailing-plus-in-bounds.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
+// compile-flags: -Z parse-only -Z continue-parse-after-error
 
 use std::fmt::Debug;
 
diff --git a/src/test/parse-fail/trait-bounds-not-on-impl.rs b/src/test/parse-fail/trait-bounds-not-on-impl.rs
index 3bd8908d18b..b7dcc8a8b3b 100644
--- a/src/test/parse-fail/trait-bounds-not-on-impl.rs
+++ b/src/test/parse-fail/trait-bounds-not-on-impl.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
+// compile-flags: -Z parse-only -Z continue-parse-after-error
 
 trait Foo {
 }
diff --git a/src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs b/src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs
index c1e1cc1c7f7..9e16e29ba50 100644
--- a/src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs
+++ b/src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
+// compile-flags: -Z parse-only -Z continue-parse-after-error
 
 use std::any:: as foo; //~ ERROR expected identifier, found keyword `as`
 //~^ ERROR: expected one of `::`, `;`, or `as`, found `foo`
diff --git a/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs b/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs
index 3ac71176342..45165b76c4a 100644
--- a/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs
+++ b/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
+// compile-flags: -Z parse-only -Z continue-parse-after-error
 
 fn equal1<T>(_: &T, _: &T) -> bool where {
 //~^ ERROR a `where` clause must have at least one predicate in it
diff --git a/src/test/run-pass/issue-18937-1.rs b/src/test/run-pass/issue-18937-1.rs
new file mode 100644
index 00000000000..7a24d087b44
--- /dev/null
+++ b/src/test/run-pass/issue-18937-1.rs
@@ -0,0 +1,30 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we are able to type-check this example. In particular,
+// knowing that `T: 'a` allows us to deduce that `[U]: 'a` (because
+// when `T=[U]` it implies that `U: 'a`).
+//
+// Regr. test for live code we found in the wild when fixing #18937.
+
+pub trait Leak<T : ?Sized> {
+    fn leak<'a>(self) -> &'a T where T: 'a;
+}
+
+impl<U> Leak<[U]> for Vec<U> {
+    fn leak<'a>(mut self) -> &'a [U] where [U]: 'a {
+        let r: *mut [U] = &mut self[..];
+        std::mem::forget(self);
+        unsafe { &mut *r }
+    }
+}
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/run-pass/traits-elaborate-type-region.rs b/src/test/run-pass/traits-elaborate-type-region.rs
new file mode 100644
index 00000000000..4621c2ca4be
--- /dev/null
+++ b/src/test/run-pass/traits-elaborate-type-region.rs
@@ -0,0 +1,58 @@
+// Copyright 2016 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)]
+
+// Test that we elaborate `Type: 'region` constraints and infer various important things.
+
+trait Master<'a, T: ?Sized> {
+    fn foo() where T: 'a;
+}
+
+// [U]: 'a => U: 'a
+impl<'a, U> Master<'a, [U]> for () {
+    fn foo() where U: 'a { }
+}
+
+// &'b U: 'a => 'b: 'a, U: 'a
+impl<'a, 'b, U> Master<'a, &'b U> for () {
+    fn foo() where 'b: 'a, U: 'a { }
+}
+
+// &'b [U]: 'a => 'b: 'a, U: 'a
+impl<'a, 'b, U> Master<'a, &'b [U]> for () {
+    fn foo() where 'b: 'a, U: 'a { }
+}
+
+// Foo<'b>: 'a => 'b: 'a
+struct Foo<'a> { x: &'a () }
+impl<'a, 'b> Master<'a, Foo<'b>> for () {
+    fn foo() where 'b: 'a { }
+}
+
+// Bar<'b, T>: 'a => 'b: 'a, T: 'a
+struct Bar<'a, T: 'a> { x: &'a T }
+impl<'a, 'b, T> Master<'a, Bar<'b, T>> for () {
+    fn foo() where 'b: 'a, T: 'a { }
+}
+
+// fn(T): 'a => T: 'a
+impl<'a, T> Master<'a, fn(T)> for () {
+    fn foo() where T: 'a { }
+}
+
+// fn() -> T: 'a => T: 'a
+impl<'a, T> Master<'a, fn() -> T> for () {
+    fn foo() where T: 'a { }
+}
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/ui/compare-method/proj-outlives-region.rs b/src/test/ui/compare-method/proj-outlives-region.rs
new file mode 100644
index 00000000000..54cfe4be9c1
--- /dev/null
+++ b/src/test/ui/compare-method/proj-outlives-region.rs
@@ -0,0 +1,27 @@
+// Copyright 2016 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)]
+#![deny(extra_requirement_in_impl)]
+
+// Test that we elaborate `Type: 'region` constraints and infer various important things.
+
+trait Master<'a, T: ?Sized, U> {
+    fn foo() where T: 'a;
+}
+
+// `U::Item: 'a` does not imply that `U: 'a`
+impl<'a, U: Iterator> Master<'a, U::Item, U> for () {
+    fn foo() where U: 'a { } //~ ERROR E0276
+}
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/ui/compare-method/proj-outlives-region.stderr b/src/test/ui/compare-method/proj-outlives-region.stderr
new file mode 100644
index 00000000000..79293e0deed
--- /dev/null
+++ b/src/test/ui/compare-method/proj-outlives-region.stderr
@@ -0,0 +1,19 @@
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/proj-outlives-region.rs:22:5
+   |
+17 |     fn foo() where T: 'a;
+   |     --------------------- definition of `foo` from trait
+...
+22 |     fn foo() where U: 'a { } //~ ERROR E0276
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `U: 'a`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #37166 <https://github.com/rust-lang/rust/issues/37166>
+note: lint level defined here
+  --> $DIR/proj-outlives-region.rs:12:9
+   |
+12 | #![deny(extra_requirement_in_impl)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/compare-method/proj-outlives-region.stdout b/src/test/ui/compare-method/proj-outlives-region.stdout
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/src/test/ui/compare-method/proj-outlives-region.stdout
diff --git a/src/test/compile-fail/region-bound-extra-bound-in-impl.rs b/src/test/ui/compare-method/region-extra-2.rs
index 5bcc6be4c3d..b0cd3b8fdd2 100644
--- a/src/test/compile-fail/region-bound-extra-bound-in-impl.rs
+++ b/src/test/ui/compare-method/region-extra-2.rs
@@ -17,7 +17,7 @@ trait Tr<'a, T> {
 
 impl<'a, T> Tr<'a, T> for &'a mut [T] {
     fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
-        //~^ ERROR lifetime bound not satisfied
+        //~^ ERROR E0276
         &mut self[..]
     }
 }
diff --git a/src/test/ui/compare-method/region-extra-2.stderr b/src/test/ui/compare-method/region-extra-2.stderr
new file mode 100644
index 00000000000..54a551bcfed
--- /dev/null
+++ b/src/test/ui/compare-method/region-extra-2.stderr
@@ -0,0 +1,11 @@
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/region-extra-2.rs:19:5
+   |
+15 |     fn renew<'b: 'a>(self) -> &'b mut [T];
+   |     -------------------------------------- definition of `renew` from trait
+...
+19 |     fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
+   |     ^ impl has extra requirement `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/compare-method/region-extra.rs b/src/test/ui/compare-method/region-extra.rs
new file mode 100644
index 00000000000..d61d0250211
--- /dev/null
+++ b/src/test/ui/compare-method/region-extra.rs
@@ -0,0 +1,27 @@
+// Copyright 2016 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)]
+#![deny(extra_requirement_in_impl)]
+
+// Test that you cannot add an extra where clause in the impl relating
+// two regions.
+
+trait Master<'a, 'b> {
+    fn foo();
+}
+
+impl<'a, 'b> Master<'a, 'b> for () {
+    fn foo() where 'a: 'b { }
+}
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/ui/compare-method/region-extra.stderr b/src/test/ui/compare-method/region-extra.stderr
new file mode 100644
index 00000000000..e657813221a
--- /dev/null
+++ b/src/test/ui/compare-method/region-extra.stderr
@@ -0,0 +1,11 @@
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/region-extra.rs:22:5
+   |
+18 |     fn foo();
+   |     --------- definition of `foo` from trait
+...
+22 |     fn foo() where 'a: 'b { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/compare-method/region-extra.stdout b/src/test/ui/compare-method/region-extra.stdout
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/src/test/ui/compare-method/region-extra.stdout
diff --git a/src/test/ui/compare-method/region-unrelated.rs b/src/test/ui/compare-method/region-unrelated.rs
new file mode 100644
index 00000000000..8f79b30bd5f
--- /dev/null
+++ b/src/test/ui/compare-method/region-unrelated.rs
@@ -0,0 +1,28 @@
+// Copyright 2016 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)]
+#![deny(extra_requirement_in_impl)]
+
+// Test that we elaborate `Type: 'region` constraints and infer various important things.
+
+trait Master<'a, T: ?Sized, U> {
+    fn foo() where T: 'a;
+}
+
+// `U: 'a` does not imply `V: 'a`
+impl<'a, U, V> Master<'a, U, V> for () {
+    fn foo() where V: 'a { }
+    //~^ ERROR parameter type `V` may not live long enough
+}
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/ui/compare-method/region-unrelated.stderr b/src/test/ui/compare-method/region-unrelated.stderr
new file mode 100644
index 00000000000..b7cfdf799bc
--- /dev/null
+++ b/src/test/ui/compare-method/region-unrelated.stderr
@@ -0,0 +1,19 @@
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/region-unrelated.rs:22:5
+   |
+17 |     fn foo() where T: 'a;
+   |     --------------------- definition of `foo` from trait
+...
+22 |     fn foo() where V: 'a { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `V: 'a`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #37166 <https://github.com/rust-lang/rust/issues/37166>
+note: lint level defined here
+  --> $DIR/region-unrelated.rs:12:9
+   |
+12 | #![deny(extra_requirement_in_impl)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/compare-method/region-unrelated.stdout b/src/test/ui/compare-method/region-unrelated.stdout
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/src/test/ui/compare-method/region-unrelated.stdout
diff --git a/src/test/compile-fail/issue-2611-5.rs b/src/test/ui/compare-method/reordered-type-param.rs
index 440294f38ae..0b844d4521d 100644
--- a/src/test/compile-fail/issue-2611-5.rs
+++ b/src/test/ui/compare-method/reordered-type-param.rs
@@ -10,6 +10,8 @@
 
 // Tests that ty params get matched correctly when comparing
 // an impl against a trait
+//
+// cc #26111
 
 trait A {
   fn b<C:Clone,D>(&self, x: C) -> C;
diff --git a/src/test/ui/compare-method/reordered-type-param.stderr b/src/test/ui/compare-method/reordered-type-param.stderr
new file mode 100644
index 00000000000..985b85cc4ec
--- /dev/null
+++ b/src/test/ui/compare-method/reordered-type-param.stderr
@@ -0,0 +1,14 @@
+error[E0053]: method `b` has an incompatible type for trait
+  --> $DIR/reordered-type-param.rs:26:30
+   |
+17 |   fn b<C:Clone,D>(&self, x: C) -> C;
+   |                             - type in trait
+...
+26 |   fn b<F:Clone,G>(&self, _x: G) -> G { panic!() } //~ ERROR method `b` has an incompatible type
+   |                              ^ expected type parameter, found a different type parameter
+   |
+   = note: expected type `fn(&E, F) -> F`
+   = note:    found type `fn(&E, G) -> G`
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/issue-2611-4.rs b/src/test/ui/compare-method/trait-bound-on-type-parameter.rs
index 16d7ea46846..09e9fb4ca2b 100644
--- a/src/test/compile-fail/issue-2611-4.rs
+++ b/src/test/ui/compare-method/trait-bound-on-type-parameter.rs
@@ -8,8 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Tests that an impl method's bounds aren't *more* restrictive
-// than the trait method it's implementing
+// Tests that impl can't add extra `F: Sync` bound aren't *more* restrictive
+// than the trait method it's implementing.
+//
+// Regr test for #26111.
 
 trait A {
   fn b<C,D>(&self, x: C) -> C;
@@ -20,8 +22,7 @@ struct E {
 }
 
 impl A for E {
-    fn b<F: Sync, G>(&self, _x: F) -> F { panic!() }
-    //~^ ERROR `F: std::marker::Sync` appears on the impl method
+    fn b<F: Sync, G>(&self, _x: F) -> F { panic!() } //~ ERROR E0276
 }
 
 fn main() {}
diff --git a/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr b/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr
new file mode 100644
index 00000000000..7112a00c7b7
--- /dev/null
+++ b/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr
@@ -0,0 +1,11 @@
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/trait-bound-on-type-parameter.rs:25:5
+   |
+17 |   fn b<C,D>(&self, x: C) -> C;
+   |   ---------------------------- definition of `b` from trait
+...
+25 |     fn b<F: Sync, G>(&self, _x: F) -> F { panic!() } //~ ERROR E0276
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `F: std::marker::Sync`
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/trait-bounds-impl-comparison-1.rs b/src/test/ui/compare-method/traits-misc-mismatch-1.rs
index 9cf65a9d00d..cca282a1d19 100644
--- a/src/test/compile-fail/trait-bounds-impl-comparison-1.rs
+++ b/src/test/ui/compare-method/traits-misc-mismatch-1.rs
@@ -34,15 +34,15 @@ trait Foo {
 impl Foo for isize {
     // invalid bound for T, was defined as Eq in trait
     fn test_error1_fn<T: Ord>(&self) {}
-    //~^ ERROR the requirement `T: std::cmp::Ord` appears on the impl
+    //~^ ERROR E0276
 
     // invalid bound for T, was defined as Eq + Ord in trait
     fn test_error2_fn<T: Eq + B>(&self) {}
-    //~^ ERROR the requirement `T: B` appears on the impl
+    //~^ ERROR E0276
 
     // invalid bound for T, was defined as Eq + Ord in trait
     fn test_error3_fn<T: B + Eq>(&self) {}
-    //~^ ERROR the requirement `T: B` appears on the impl
+    //~^ ERROR E0276
 
     // multiple bounds, same order as in trait
     fn test3_fn<T: Ord + Eq>(&self) {}
@@ -52,16 +52,16 @@ impl Foo for isize {
 
     // parameters in impls must be equal or more general than in the defining trait
     fn test_error5_fn<T: B>(&self) {}
-    //~^ ERROR the requirement `T: B` appears on the impl
+    //~^ ERROR E0276
 
     // bound `std::cmp::Eq` not enforced by this implementation, but this is OK
     fn test6_fn<T: A>(&self) {}
 
     fn test_error7_fn<T: A + Eq>(&self) {}
-    //~^ ERROR the requirement `T: std::cmp::Eq` appears on the impl
+    //~^ ERROR E0276
 
     fn test_error8_fn<T: C>(&self) {}
-    //~^ ERROR the requirement `T: C` appears on the impl
+    //~^ ERROR E0276
 }
 
 trait Getter<T> {
@@ -74,7 +74,7 @@ trait Trait {
 
 impl Trait for usize {
     fn method<G: Getter<usize>>(&self) {}
-    //~^ ERROR `G: Getter<usize>` appears on the impl method
+    //~^ ERROR E0276
 }
 
 fn main() {}
diff --git a/src/test/ui/compare-method/traits-misc-mismatch-1.stderr b/src/test/ui/compare-method/traits-misc-mismatch-1.stderr
new file mode 100644
index 00000000000..f221ebe3302
--- /dev/null
+++ b/src/test/ui/compare-method/traits-misc-mismatch-1.stderr
@@ -0,0 +1,65 @@
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/traits-misc-mismatch-1.rs:36:5
+   |
+23 |     fn test_error1_fn<T: Eq>(&self);
+   |     -------------------------------- definition of `test_error1_fn` from trait
+...
+36 |     fn test_error1_fn<T: Ord>(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::cmp::Ord`
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/traits-misc-mismatch-1.rs:40:5
+   |
+24 |     fn test_error2_fn<T: Eq + Ord>(&self);
+   |     -------------------------------------- definition of `test_error2_fn` from trait
+...
+40 |     fn test_error2_fn<T: Eq + B>(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: B`
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/traits-misc-mismatch-1.rs:44:5
+   |
+25 |     fn test_error3_fn<T: Eq + Ord>(&self);
+   |     -------------------------------------- definition of `test_error3_fn` from trait
+...
+44 |     fn test_error3_fn<T: B + Eq>(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: B`
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/traits-misc-mismatch-1.rs:54:5
+   |
+28 |     fn test_error5_fn<T: A>(&self);
+   |     ------------------------------- definition of `test_error5_fn` from trait
+...
+54 |     fn test_error5_fn<T: B>(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: B`
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/traits-misc-mismatch-1.rs:60:5
+   |
+30 |     fn test_error7_fn<T: A>(&self);
+   |     ------------------------------- definition of `test_error7_fn` from trait
+...
+60 |     fn test_error7_fn<T: A + Eq>(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::cmp::Eq`
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/traits-misc-mismatch-1.rs:63:5
+   |
+31 |     fn test_error8_fn<T: B>(&self);
+   |     ------------------------------- definition of `test_error8_fn` from trait
+...
+63 |     fn test_error8_fn<T: C>(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: C`
+
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/traits-misc-mismatch-1.rs:76:5
+   |
+72 |     fn method<G:Getter<isize>>(&self);
+   |     ---------------------------------- definition of `method` from trait
+...
+76 |     fn method<G: Getter<usize>>(&self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `G: Getter<usize>`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/compile-fail/trait-bounds-impl-comparison-2.rs b/src/test/ui/compare-method/traits-misc-mismatch-2.rs
index 8d587b29ba9..e82cf256df1 100644
--- a/src/test/compile-fail/trait-bounds-impl-comparison-2.rs
+++ b/src/test/ui/compare-method/traits-misc-mismatch-2.rs
@@ -21,7 +21,7 @@ trait IteratorUtil<A>: Sized
 
 impl<A, T: Iterator<A>> IteratorUtil<A> for T {
     fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> {
-    //~^ ERROR the requirement `U: Iterator<B>` appears on the impl method
+    //~^ ERROR E0276
         ZipIterator{a: self, b: other}
     }
 }
diff --git a/src/test/ui/compare-method/traits-misc-mismatch-2.stderr b/src/test/ui/compare-method/traits-misc-mismatch-2.stderr
new file mode 100644
index 00000000000..5003550fd1e
--- /dev/null
+++ b/src/test/ui/compare-method/traits-misc-mismatch-2.stderr
@@ -0,0 +1,11 @@
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/traits-misc-mismatch-2.rs:23:5
+   |
+19 |     fn zip<B, U: Iterator<U>>(self, other: U) -> ZipIterator<Self, U>;
+   |     ------------------------------------------------------------------ definition of `zip` from trait
+...
+23 |     fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> {
+   |     ^ impl has extra requirement `U: Iterator<B>`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/update-references.sh b/src/test/ui/update-references.sh
index f0a6f8a3d44..aa99d35f7aa 100755
--- a/src/test/ui/update-references.sh
+++ b/src/test/ui/update-references.sh
@@ -36,12 +36,12 @@ while [[ "$1" != "" ]]; do
     STDOUT_NAME="${1/%.rs/.stdout}"
     shift
     if [ -f $BUILD_DIR/$STDOUT_NAME ] && \
-           ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME > /dev/null); then
+           ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then
         echo updating $MYDIR/$STDOUT_NAME
         cp $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME
     fi
     if [ -f $BUILD_DIR/$STDERR_NAME ] && \
-           ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME > /dev/null); then
+           ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME >& /dev/null); then
         echo updating $MYDIR/$STDERR_NAME
         cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME
     fi