diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 62bedcdfcbe61..873d39ec9e9fb 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -2170,12 +2170,12 @@ impl<'a> LoweringContext<'a> {
                 //     let result = match ::std::iter::IntoIterator::into_iter(<head>) {
                 //       mut iter => {
                 //         [opt_ident]: loop {
-                //           let mut _next;
+                //           let mut __next;
                 //           match ::std::iter::Iterator::next(&mut iter) {
-                //             ::std::option::Option::Some(val) => _next = val,
+                //             ::std::option::Option::Some(val) => __next = val,
                 //             ::std::option::Option::None => break
                 //           };
-                //           let <pat> = _next;
+                //           let <pat> = __next;
                 //           StmtExpr(<body>);
                 //         }
                 //       }
@@ -2188,7 +2188,7 @@ impl<'a> LoweringContext<'a> {
 
                 let iter = self.str_to_ident("iter");
 
-                let next_ident = self.str_to_ident("_next");
+                let next_ident = self.str_to_ident("__next");
                 let next_pat = self.pat_ident_binding_mode(e.span,
                                                            next_ident,
                                                            hir::BindByValue(hir::MutMutable));
@@ -2237,13 +2237,13 @@ impl<'a> LoweringContext<'a> {
 
                 let next_expr = P(self.expr_ident(e.span, next_ident, next_pat.id));
 
-                // `let mut _next`
+                // `let mut __next`
                 let next_let = self.stmt_let_pat(e.span,
                     None,
                     next_pat,
                     hir::LocalSource::ForLoopDesugar);
 
-                // `let <pat> = _next`
+                // `let <pat> = __next`
                 let pat = self.lower_pat(pat);
                 let pat_let = self.stmt_let_pat(e.span,
                     Some(next_expr),
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index a9e0ef511024f..466d163854f1d 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -291,16 +291,13 @@ impl LintStore {
         self.by_name.insert(name.into(), Removed(reason.into()));
     }
 
-    #[allow(unused_variables)]
-    fn find_lint(&self, lint_name: &str, sess: &Session, span: Option<Span>)
-                 -> Result<LintId, FindLintError>
-    {
+    fn find_lint(&self, lint_name: &str) -> Result<LintId, FindLintError> {
         match self.by_name.get(lint_name) {
             Some(&Id(lint_id)) => Ok(lint_id),
             Some(&Renamed(_, lint_id)) => {
                 Ok(lint_id)
             },
-            Some(&Removed(ref reason)) => {
+            Some(&Removed(_)) => {
                 Err(FindLintError::Removed)
             },
             None => Err(FindLintError::NotFound)
@@ -313,7 +310,7 @@ impl LintStore {
                                     &lint_name[..], level);
 
             let lint_flag_val = Symbol::intern(&lint_name);
-            match self.find_lint(&lint_name[..], sess, None) {
+            match self.find_lint(&lint_name[..]) {
                 Ok(lint_id) => self.levels.set(lint_id, (level, CommandLine(lint_flag_val))),
                 Err(FindLintError::Removed) => { }
                 Err(_) => {
@@ -724,21 +721,22 @@ pub trait LintContext<'tcx>: Sized {
         let mut pushed = 0;
 
         for result in gather_attrs(attrs) {
-            let v = match result {
+            let (is_group, lint_level_spans) = match result {
                 Err(span) => {
                     span_err!(self.sess(), span, E0452,
                               "malformed lint attribute");
                     continue;
                 }
                 Ok((lint_name, level, span)) => {
-                    match self.lints().find_lint(&lint_name.as_str(), &self.sess(), Some(span)) {
-                        Ok(lint_id) => vec![(lint_id, level, span)],
+                    match self.lints().find_lint(&lint_name.as_str()) {
+                        Ok(lint_id) => (false, vec![(lint_id, level, span)]),
                         Err(FindLintError::NotFound) => {
                             match self.lints().lint_groups.get(&*lint_name.as_str()) {
-                                Some(&(ref v, _)) => v.iter()
+                                Some(&(ref v, _)) => (true,
+                                                      v.iter()
                                                       .map(|lint_id: &LintId|
                                                            (*lint_id, level, span))
-                                                      .collect(),
+                                                      .collect()),
                                 None => {
                                     // The lint or lint group doesn't exist.
                                     // This is an error, but it was handled
@@ -754,14 +752,18 @@ pub trait LintContext<'tcx>: Sized {
 
             let lint_attr_name = result.expect("lint attribute should be well-formed").0;
 
-            for (lint_id, level, span) in v {
+            for (lint_id, level, span) in lint_level_spans {
                 let (now, now_source) = self.lint_sess().get_source(lint_id);
                 if now == Forbid && level != Forbid {
-                    let lint_name = lint_id.to_string();
+                    let forbidden_lint_name = match now_source {
+                        LintSource::Default => lint_id.to_string(),
+                        LintSource::Node(name, _) => name.to_string(),
+                        LintSource::CommandLine(name) => name.to_string(),
+                    };
                     let mut diag_builder = struct_span_err!(self.sess(), span, E0453,
                                                             "{}({}) overruled by outer forbid({})",
-                                                            level.as_str(), lint_name,
-                                                            lint_name);
+                                                            level.as_str(), lint_attr_name,
+                                                            forbidden_lint_name);
                     diag_builder.span_label(span, "overruled by previous forbid");
                     match now_source {
                         LintSource::Default => &mut diag_builder,
@@ -772,7 +774,10 @@ pub trait LintContext<'tcx>: Sized {
                         LintSource::CommandLine(_) => {
                             diag_builder.note("`forbid` lint level was set on command line")
                         }
-                    }.emit()
+                    }.emit();
+                    if is_group { // don't set a separate error for every lint in the group
+                        break;
+                    }
                 } else if now != level {
                     let cx = self.lint_sess_mut();
                     cx.stack.push((lint_id, (now, now_source)));
@@ -1420,7 +1425,7 @@ impl Decodable for LintId {
     fn decode<D: Decoder>(d: &mut D) -> Result<LintId, D::Error> {
         let s = d.read_str()?;
         ty::tls::with(|tcx| {
-            match tcx.sess.lint_store.borrow().find_lint(&s, tcx.sess, None) {
+            match tcx.sess.lint_store.borrow().find_lint(&s) {
                 Ok(id) => Ok(id),
                 Err(_) => panic!("invalid lint-id `{}`", s),
             }
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 91aeade65aa4c..ea08f1f624e67 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -40,9 +40,11 @@
 
 use super::{Diverges, FnCtxt};
 
-use lint;
+use errors::DiagnosticBuilder;
 use hir::def_id::DefId;
+use lint;
 use rustc::hir;
+use rustc::session::Session;
 use rustc::traits;
 use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::ty::cast::{CastKind, CastTy};
@@ -112,6 +114,18 @@ enum CastError {
     NonScalar,
 }
 
+fn make_invalid_casting_error<'a, 'gcx, 'tcx>(sess: &'a Session,
+                                              span: Span,
+                                              expr_ty: Ty<'tcx>,
+                                              cast_ty: Ty<'tcx>,
+                                              fcx: &FnCtxt<'a, 'gcx, 'tcx>)
+                                              -> DiagnosticBuilder<'a> {
+    type_error_struct!(sess, span, expr_ty, E0606,
+                       "casting `{}` as `{}` is invalid",
+                       fcx.ty_to_string(expr_ty),
+                       fcx.ty_to_string(cast_ty))
+}
+
 impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
     pub fn new(fcx: &FnCtxt<'a, 'gcx, 'tcx>,
                expr: &'tcx hir::Expr,
@@ -146,14 +160,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
         match e {
             CastError::NeedDeref => {
                 let error_span = self.span;
+                let mut err = make_invalid_casting_error(fcx.tcx.sess, self.span, self.expr_ty,
+                                                         self.cast_ty, fcx);
                 let cast_ty = fcx.ty_to_string(self.cast_ty);
-                let mut err = fcx.type_error_struct(error_span,
-                                       |actual| {
-                                           format!("casting `{}` as `{}` is invalid",
-                                                   actual,
-                                                   cast_ty)
-                                       },
-                                       self.expr_ty);
                 err.span_label(error_span,
                                format!("cannot cast `{}` as `{}`",
                                         fcx.ty_to_string(self.expr_ty),
@@ -166,13 +175,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
             }
             CastError::NeedViaThinPtr |
             CastError::NeedViaPtr => {
-                let mut err = fcx.type_error_struct(self.span,
-                                                    |actual| {
-                                                        format!("casting `{}` as `{}` is invalid",
-                                                                actual,
-                                                                fcx.ty_to_string(self.cast_ty))
-                                                    },
-                                                    self.expr_ty);
+                let mut err = make_invalid_casting_error(fcx.tcx.sess, self.span, self.expr_ty,
+                                                         self.cast_ty, fcx);
                 if self.cast_ty.is_uint() {
                     err.help(&format!("cast through {} first",
                                       match e {
@@ -184,13 +188,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
                 err.emit();
             }
             CastError::NeedViaInt => {
-                fcx.type_error_struct(self.span,
-                                      |actual| {
-                                          format!("casting `{}` as `{}` is invalid",
-                                                  actual,
-                                                  fcx.ty_to_string(self.cast_ty))
-                                      },
-                                      self.expr_ty)
+                make_invalid_casting_error(fcx.tcx.sess, self.span, self.expr_ty, self.cast_ty, fcx)
                    .help(&format!("cast through {} first",
                                   match e {
                                       CastError::NeedViaInt => "an integer",
@@ -198,6 +196,15 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
                                   }))
                    .emit();
             }
+            CastError::IllegalCast => {
+                make_invalid_casting_error(fcx.tcx.sess, self.span, self.expr_ty, self.cast_ty, fcx)
+                    .emit();
+            }
+            CastError::DifferingKinds => {
+                make_invalid_casting_error(fcx.tcx.sess, self.span, self.expr_ty, self.cast_ty, fcx)
+                    .note("vtable kinds may not match")
+                    .emit();
+            }
             CastError::CastToBool => {
                 struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`")
                     .span_label(self.span, "unsupported cast")
@@ -205,51 +212,23 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
                     .emit();
             }
             CastError::CastToChar => {
-                fcx.type_error_message(self.span,
-                                       |actual| {
-                                           format!("only `u8` can be cast as `char`, not `{}`",
-                                                   actual)
-                                       },
-                                       self.expr_ty);
+                type_error_struct!(fcx.tcx.sess, self.span, self.expr_ty, E0604,
+                                 "only `u8` can be cast as `char`, not `{}`", self.expr_ty).emit();
             }
             CastError::NonScalar => {
-                fcx.type_error_message(self.span,
-                                       |actual| {
-                                           format!("non-scalar cast: `{}` as `{}`",
-                                                   actual,
-                                                   fcx.ty_to_string(self.cast_ty))
-                                       },
-                                       self.expr_ty);
-            }
-            CastError::IllegalCast => {
-                fcx.type_error_message(self.span,
-                                       |actual| {
-                                           format!("casting `{}` as `{}` is invalid",
-                                                   actual,
-                                                   fcx.ty_to_string(self.cast_ty))
-                                       },
-                                       self.expr_ty);
+                type_error_struct!(fcx.tcx.sess, self.span, self.expr_ty, E0605,
+                                 "non-primitive cast: `{}` as `{}`",
+                                 self.expr_ty,
+                                 fcx.ty_to_string(self.cast_ty))
+                                .note("an `as` expression can only be used to convert between \
+                                       primitive types. Consider using the `From` trait")
+                                .emit();
             }
             CastError::SizedUnsizedCast => {
-                fcx.type_error_message(self.span,
-                                       |actual| {
-                                           format!("cannot cast thin pointer `{}` to fat pointer \
-                                                    `{}`",
-                                                   actual,
-                                                   fcx.ty_to_string(self.cast_ty))
-                                       },
-                                       self.expr_ty)
-            }
-            CastError::DifferingKinds => {
-                fcx.type_error_struct(self.span,
-                                       |actual| {
-                                           format!("casting `{}` as `{}` is invalid",
-                                                   actual,
-                                                   fcx.ty_to_string(self.cast_ty))
-                                       },
-                                       self.expr_ty)
-                    .note("vtable kinds may not match")
-                    .emit();
+                type_error_struct!(fcx.tcx.sess, self.span, self.expr_ty, E0607,
+                                 "cannot cast thin pointer `{}` to fat pointer `{}`",
+                                 self.expr_ty,
+                                 fcx.ty_to_string(self.cast_ty)).emit();
             }
         }
     }
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index bc5ba4c323dc1..b2fa2cc7c61d2 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4208,6 +4208,104 @@ println!("{}", v[2]);
 ```
 "##,
 
+E0604: r##"
+A cast to `char` was attempted on a type other than `u8`.
+
+Erroneous code example:
+
+```compile_fail,E0604
+0u32 as char; // error: only `u8` can be cast as `char`, not `u32`
+```
+
+As the error message indicates, only `u8` can be cast into `char`. Example:
+
+```
+let c = 86u8 as char; // ok!
+assert_eq!(c, 'V');
+```
+
+For more information about casts, take a look at The Book:
+https://doc.rust-lang.org/book/first-edition/casting-between-types.html
+"##,
+
+E0605: r##"
+An invalid cast was attempted.
+
+Erroneous code examples:
+
+```compile_fail,E0605
+let x = 0u8;
+x as Vec<u8>; // error: non-primitive cast: `u8` as `std::vec::Vec<u8>`
+
+// Another example
+
+let v = 0 as *const u8; // So here, `v` is a `*const u8`.
+v as &u8; // error: non-primitive cast: `*const u8` as `&u8`
+```
+
+Only primitive types can be cast into each other. Examples:
+
+```
+let x = 0u8;
+x as u32; // ok!
+
+let v = 0 as *const u8;
+v as *const i8; // ok!
+```
+
+For more information about casts, take a look at The Book:
+https://doc.rust-lang.org/book/first-edition/casting-between-types.html
+"##,
+
+E0606: r##"
+An incompatible cast was attempted.
+
+Erroneous code example:
+
+```compile_fail,E0606
+let x = &0u8; // Here, `x` is a `&u8`.
+let y: u32 = x as u32; // error: casting `&u8` as `u32` is invalid
+```
+
+When casting, keep in mind that only primitive types can be cast into each
+other. Example:
+
+```
+let x = &0u8;
+let y: u32 = *x as u32; // We dereference it first and then cast it.
+```
+
+For more information about casts, take a look at The Book:
+https://doc.rust-lang.org/book/first-edition/casting-between-types.html
+"##,
+
+E0607: r##"
+A cast between a thin and a fat pointer was attempted.
+
+Erroneous code example:
+
+```compile_fail,E0607
+let v = 0 as *const u8;
+v as *const [u8];
+```
+
+First: what are thin and fat pointers?
+
+Thin pointers are "simple" pointers: they are purely a reference to a memory
+address.
+
+Fat pointers are pointers referencing Dynamically Sized Types (also called DST).
+DST don't have a statically known size, therefore they can only exist behind
+some kind of pointers that contain additional information. Slices and trait
+objects are DSTs. In the case of slices, the additional information the fat
+pointer holds is their size.
+
+To fix this error, don't try to cast directly between thin and fat pointers.
+
+For more information about casts, take a look at The Book:
+https://doc.rust-lang.org/book/first-edition/casting-between-types.html
+"##,
+
 E0609: r##"
 Attempted to access a non-existent field in a struct.
 
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index f54d79c201f48..e9296f33b9e0f 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -29,7 +29,7 @@ use sys_common::{AsInner, IntoInner, FromInner};
 /// * On Windows, strings are often arbitrary sequences of non-zero 16-bit
 ///   values, interpreted as UTF-16 when it is valid to do so.
 ///
-/// * In Rust, strings are always valid UTF-8, but may contain zeros.
+/// * In Rust, strings are always valid UTF-8, which may contain zeros.
 ///
 /// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust
 /// and platform-native string values, and in particular allowing a Rust string
diff --git a/src/test/compile-fail/E0604.rs b/src/test/compile-fail/E0604.rs
new file mode 100644
index 0000000000000..c5bf3a77b6c8f
--- /dev/null
+++ b/src/test/compile-fail/E0604.rs
@@ -0,0 +1,13 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    1u32 as char; //~ ERROR E0604
+}
diff --git a/src/test/compile-fail/E0605.rs b/src/test/compile-fail/E0605.rs
new file mode 100644
index 0000000000000..add3fd8fd8ac2
--- /dev/null
+++ b/src/test/compile-fail/E0605.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    let x = 0u8;
+    x as Vec<u8>; //~ ERROR E0605
+                  //~| NOTE an `as` expression can only be used to convert between primitive types
+
+    let v = 0 as *const u8;
+    v as &u8; //~ ERROR E0605
+              //~| NOTE an `as` expression can only be used to convert between primitive types
+}
diff --git a/src/test/compile-fail/E0606.rs b/src/test/compile-fail/E0606.rs
new file mode 100644
index 0000000000000..55071736bfe51
--- /dev/null
+++ b/src/test/compile-fail/E0606.rs
@@ -0,0 +1,13 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    &0u8 as u8; //~ ERROR E0606
+}
diff --git a/src/test/compile-fail/E0607.rs b/src/test/compile-fail/E0607.rs
new file mode 100644
index 0000000000000..fa761f2c17896
--- /dev/null
+++ b/src/test/compile-fail/E0607.rs
@@ -0,0 +1,14 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    let v = 0 as *const u8;
+    v as *const [u8]; //~ ERROR E0607
+}
diff --git a/src/test/compile-fail/cast-from-nil.rs b/src/test/compile-fail/cast-from-nil.rs
index 4c6dcaccc9aed..ab22d35248073 100644
--- a/src/test/compile-fail/cast-from-nil.rs
+++ b/src/test/compile-fail/cast-from-nil.rs
@@ -8,5 +8,5 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: non-scalar cast: `()` as `u32`
+// error-pattern: non-primitive cast: `()` as `u32`
 fn main() { let u = (assert!(true) as u32); }
diff --git a/src/test/compile-fail/cast-to-bare-fn.rs b/src/test/compile-fail/cast-to-bare-fn.rs
index 7cc5c727bc7df..d5a998c6e4b6b 100644
--- a/src/test/compile-fail/cast-to-bare-fn.rs
+++ b/src/test/compile-fail/cast-to-bare-fn.rs
@@ -13,8 +13,8 @@ fn foo(_x: isize) { }
 fn main() {
     let v: u64 = 5;
     let x = foo as extern "C" fn() -> isize;
-    //~^ ERROR non-scalar cast
+    //~^ ERROR non-primitive cast
     let y = v as extern "Rust" fn(isize) -> (isize, isize);
-    //~^ ERROR non-scalar cast
+    //~^ ERROR non-primitive cast
     y(x());
 }
diff --git a/src/test/compile-fail/cast-to-nil.rs b/src/test/compile-fail/cast-to-nil.rs
index e5fd5bb33eb90..27d9e8a42b188 100644
--- a/src/test/compile-fail/cast-to-nil.rs
+++ b/src/test/compile-fail/cast-to-nil.rs
@@ -8,5 +8,5 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: non-scalar cast: `u32` as `()`
+// error-pattern: non-primitive cast: `u32` as `()`
 fn main() { let u = 0u32 as (); }
diff --git a/src/test/compile-fail/closure-no-fn-3.rs b/src/test/compile-fail/closure-no-fn-3.rs
index 85dbc899208f6..6584c16c9dec6 100644
--- a/src/test/compile-fail/closure-no-fn-3.rs
+++ b/src/test/compile-fail/closure-no-fn-3.rs
@@ -14,5 +14,5 @@
 fn main() {
     let b = 0u8;
     let baz: fn() -> u8 = (|| { b }) as fn() -> u8;
-    //~^ ERROR non-scalar cast
+    //~^ ERROR non-primitive cast
 }
diff --git a/src/test/compile-fail/coerce-to-bang-cast.rs b/src/test/compile-fail/coerce-to-bang-cast.rs
index 57d2192e6356b..0479f5cce6537 100644
--- a/src/test/compile-fail/coerce-to-bang-cast.rs
+++ b/src/test/compile-fail/coerce-to-bang-cast.rs
@@ -17,7 +17,7 @@ fn cast_a() {
 }
 
 fn cast_b() {
-    let y = 22 as !; //~ ERROR non-scalar cast
+    let y = 22 as !; //~ ERROR non-primitive cast
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs
index c62987a5b900e..bc2dc1cc5d4c8 100644
--- a/src/test/compile-fail/fat-ptr-cast.rs
+++ b/src/test/compile-fail/fat-ptr-cast.rs
@@ -22,7 +22,7 @@ fn main() {
     a as isize; //~ ERROR casting
     a as i16; //~ ERROR casting `&[i32]` as `i16` is invalid
     a as u32; //~ ERROR casting `&[i32]` as `u32` is invalid
-    b as usize; //~ ERROR non-scalar cast
+    b as usize; //~ ERROR non-primitive cast
     p as usize;
     //~^ ERROR casting
     //~^^ HELP cast through a thin pointer
diff --git a/src/test/compile-fail/issue-10991.rs b/src/test/compile-fail/issue-10991.rs
index 25060b94dcf37..2d00f339f33a0 100644
--- a/src/test/compile-fail/issue-10991.rs
+++ b/src/test/compile-fail/issue-10991.rs
@@ -10,5 +10,5 @@
 
 fn main() {
     let nil = ();
-    let _t = nil as usize; //~ ERROR: non-scalar cast: `()` as `usize`
+    let _t = nil as usize; //~ ERROR: non-primitive cast: `()` as `usize`
 }
diff --git a/src/test/compile-fail/issue-22289.rs b/src/test/compile-fail/issue-22289.rs
index bcbc414d3534b..c23fc4f334472 100644
--- a/src/test/compile-fail/issue-22289.rs
+++ b/src/test/compile-fail/issue-22289.rs
@@ -9,5 +9,5 @@
 // except according to those terms.
 
 fn main() {
-    0 as &std::any::Any; //~ ERROR non-scalar cast
+    0 as &std::any::Any; //~ ERROR non-primitive cast
 }
diff --git a/src/test/compile-fail/issue-22312.rs b/src/test/compile-fail/issue-22312.rs
index 4d6e6eded2118..2128c4206301b 100644
--- a/src/test/compile-fail/issue-22312.rs
+++ b/src/test/compile-fail/issue-22312.rs
@@ -19,7 +19,7 @@ pub trait Array2D: Index<usize> {
         }
         let i = y * self.columns() + x;
         let indexer = &(*self as &Index<usize, Output = <Self as Index<usize>>::Output>);
-        //~^ERROR non-scalar cast
+        //~^ERROR non-primitive cast
         Some(indexer.index(i))
     }
 }
diff --git a/src/test/compile-fail/issue-2995.rs b/src/test/compile-fail/issue-2995.rs
index 8fbf97411cc7d..d735e184d5cd5 100644
--- a/src/test/compile-fail/issue-2995.rs
+++ b/src/test/compile-fail/issue-2995.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 fn bad (p: *const isize) {
-    let _q: &isize = p as &isize; //~ ERROR non-scalar cast
+    let _q: &isize = p as &isize; //~ ERROR non-primitive cast
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/nonscalar-cast.rs b/src/test/compile-fail/nonscalar-cast.rs
index d6f274da967d1..0abbc05eef05d 100644
--- a/src/test/compile-fail/nonscalar-cast.rs
+++ b/src/test/compile-fail/nonscalar-cast.rs
@@ -8,13 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern:non-scalar cast
-
 #[derive(Debug)]
 struct foo {
     x: isize
 }
 
 fn main() {
-    println!("{}", foo{ x: 1 } as isize);
+    println!("{}", foo{ x: 1 } as isize); //~ non-primitive cast: `foo` as `isize` [E0605]
 }
diff --git a/src/test/compile-fail/tag-variant-cast-non-nullary.rs b/src/test/compile-fail/tag-variant-cast-non-nullary.rs
index b01063291266c..220537633eaf1 100644
--- a/src/test/compile-fail/tag-variant-cast-non-nullary.rs
+++ b/src/test/compile-fail/tag-variant-cast-non-nullary.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//error-pattern: non-scalar cast
-
 enum non_nullary {
     nullary,
     other(isize),
@@ -17,5 +15,5 @@ enum non_nullary {
 
 fn main() {
     let v = non_nullary::nullary;
-    let val = v as isize;
+    let val = v as isize; //~ ERROR non-primitive cast: `non_nullary` as `isize` [E0605]
 }
diff --git a/src/test/compile-fail/uninhabited-enum-cast.rs b/src/test/compile-fail/uninhabited-enum-cast.rs
index b4df5fb1e2acc..2a5d25e6b98dd 100644
--- a/src/test/compile-fail/uninhabited-enum-cast.rs
+++ b/src/test/compile-fail/uninhabited-enum-cast.rs
@@ -11,7 +11,7 @@
 enum E {}
 
 fn f(e: E) {
-    println!("{}", (e as isize).to_string());   //~ ERROR non-scalar cast
+    println!("{}", (e as isize).to_string());   //~ ERROR non-primitive cast
 }
 
 fn main() {}
diff --git a/src/test/ui/lint/outer-forbid.rs b/src/test/ui/lint/outer-forbid.rs
new file mode 100644
index 0000000000000..d71da58829a72
--- /dev/null
+++ b/src/test/ui/lint/outer-forbid.rs
@@ -0,0 +1,22 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Forbidding a group (here, `unused`) overrules subsequent allowance of both
+// the group, and an individual lint in the group (here, `unused_variables`);
+// and, forbidding an individual lint (here, `non_snake_case`) overrules
+// subsequent allowance of a lint group containing it (here, `bad_style`). See
+// Issue #42873.
+
+#![forbid(unused, non_snake_case)]
+
+#[allow(unused, unused_variables, bad_style)]
+fn main() {
+    println!("hello forbidden world")
+}
diff --git a/src/test/ui/lint/outer-forbid.stderr b/src/test/ui/lint/outer-forbid.stderr
new file mode 100644
index 0000000000000..831b3f65634b2
--- /dev/null
+++ b/src/test/ui/lint/outer-forbid.stderr
@@ -0,0 +1,29 @@
+error[E0453]: allow(unused) overruled by outer forbid(unused)
+  --> $DIR/outer-forbid.rs:19:9
+   |
+17 | #![forbid(unused, non_snake_case)]
+   |           ------ `forbid` level set here
+18 | 
+19 | #[allow(unused, unused_variables, bad_style)]
+   |         ^^^^^^ overruled by previous forbid
+
+error[E0453]: allow(unused_variables) overruled by outer forbid(unused)
+  --> $DIR/outer-forbid.rs:19:17
+   |
+17 | #![forbid(unused, non_snake_case)]
+   |           ------ `forbid` level set here
+18 | 
+19 | #[allow(unused, unused_variables, bad_style)]
+   |                 ^^^^^^^^^^^^^^^^ overruled by previous forbid
+
+error[E0453]: allow(bad_style) overruled by outer forbid(non_snake_case)
+  --> $DIR/outer-forbid.rs:19:35
+   |
+17 | #![forbid(unused, non_snake_case)]
+   |                   -------------- `forbid` level set here
+18 | 
+19 | #[allow(unused, unused_variables, bad_style)]
+   |                                   ^^^^^^^^^ overruled by previous forbid
+
+error: aborting due to previous error(s)
+
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr
index 58cd130dcc253..879acbcf9d9d1 100644
--- a/src/test/ui/mismatched_types/cast-rfc0401.stderr
+++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr
@@ -1,4 +1,4 @@
-error: casting `*const U` as `*const V` is invalid
+error[E0606]: casting `*const U` as `*const V` is invalid
   --> $DIR/cast-rfc0401.rs:13:5
    |
 13 |     u as *const V
@@ -6,7 +6,7 @@ error: casting `*const U` as `*const V` is invalid
    |
    = note: vtable kinds may not match
 
-error: casting `*const U` as `*const str` is invalid
+error[E0606]: casting `*const U` as `*const str` is invalid
   --> $DIR/cast-rfc0401.rs:18:5
    |
 18 |     u as *const str
@@ -20,49 +20,59 @@ error[E0609]: no field `f` on type `fn() {main}`
 75 |     let _ = main.f as *const u32;
    |                  ^
 
-error: non-scalar cast: `*const u8` as `&u8`
+error[E0605]: non-primitive cast: `*const u8` as `&u8`
   --> $DIR/cast-rfc0401.rs:39:13
    |
 39 |     let _ = v as &u8;
    |             ^^^^^^^^
+   |
+   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
 
-error: non-scalar cast: `*const u8` as `E`
+error[E0605]: non-primitive cast: `*const u8` as `E`
   --> $DIR/cast-rfc0401.rs:40:13
    |
 40 |     let _ = v as E;
    |             ^^^^^^
+   |
+   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
 
-error: non-scalar cast: `*const u8` as `fn()`
+error[E0605]: non-primitive cast: `*const u8` as `fn()`
   --> $DIR/cast-rfc0401.rs:41:13
    |
 41 |     let _ = v as fn();
    |             ^^^^^^^^^
+   |
+   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
 
-error: non-scalar cast: `*const u8` as `(u32,)`
+error[E0605]: non-primitive cast: `*const u8` as `(u32,)`
   --> $DIR/cast-rfc0401.rs:42:13
    |
 42 |     let _ = v as (u32,);
    |             ^^^^^^^^^^^
+   |
+   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
 
-error: non-scalar cast: `std::option::Option<&*const u8>` as `*const u8`
+error[E0605]: non-primitive cast: `std::option::Option<&*const u8>` as `*const u8`
   --> $DIR/cast-rfc0401.rs:43:13
    |
 43 |     let _ = Some(&v) as *const u8;
    |             ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
 
-error: casting `*const u8` as `f32` is invalid
+error[E0606]: casting `*const u8` as `f32` is invalid
   --> $DIR/cast-rfc0401.rs:45:13
    |
 45 |     let _ = v as f32;
    |             ^^^^^^^^
 
-error: casting `fn() {main}` as `f64` is invalid
+error[E0606]: casting `fn() {main}` as `f64` is invalid
   --> $DIR/cast-rfc0401.rs:46:13
    |
 46 |     let _ = main as f64;
    |             ^^^^^^^^^^^
 
-error: casting `&*const u8` as `usize` is invalid
+error[E0606]: casting `&*const u8` as `usize` is invalid
   --> $DIR/cast-rfc0401.rs:47:13
    |
 47 |     let _ = &v as usize;
@@ -70,7 +80,7 @@ error: casting `&*const u8` as `usize` is invalid
    |
    = help: cast through a raw pointer first
 
-error: casting `f32` as `*const u8` is invalid
+error[E0606]: casting `f32` as `*const u8` is invalid
   --> $DIR/cast-rfc0401.rs:48:13
    |
 48 |     let _ = f as *const u8;
@@ -92,13 +102,13 @@ error[E0054]: cannot cast as `bool`
    |
    = help: compare with zero instead
 
-error: only `u8` can be cast as `char`, not `u32`
+error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/cast-rfc0401.rs:51:13
    |
 51 |     let _ = 0x61u32 as char;
    |             ^^^^^^^^^^^^^^^
 
-error: casting `bool` as `f32` is invalid
+error[E0606]: casting `bool` as `f32` is invalid
   --> $DIR/cast-rfc0401.rs:53:13
    |
 53 |     let _ = false as f32;
@@ -106,7 +116,7 @@ error: casting `bool` as `f32` is invalid
    |
    = help: cast through an integer first
 
-error: casting `E` as `f32` is invalid
+error[E0606]: casting `E` as `f32` is invalid
   --> $DIR/cast-rfc0401.rs:54:13
    |
 54 |     let _ = E::A as f32;
@@ -114,7 +124,7 @@ error: casting `E` as `f32` is invalid
    |
    = help: cast through an integer first
 
-error: casting `char` as `f32` is invalid
+error[E0606]: casting `char` as `f32` is invalid
   --> $DIR/cast-rfc0401.rs:55:13
    |
 55 |     let _ = 'a' as f32;
@@ -122,67 +132,67 @@ error: casting `char` as `f32` is invalid
    |
    = help: cast through an integer first
 
-error: casting `bool` as `*const u8` is invalid
+error[E0606]: casting `bool` as `*const u8` is invalid
   --> $DIR/cast-rfc0401.rs:57:13
    |
 57 |     let _ = false as *const u8;
    |             ^^^^^^^^^^^^^^^^^^
 
-error: casting `E` as `*const u8` is invalid
+error[E0606]: casting `E` as `*const u8` is invalid
   --> $DIR/cast-rfc0401.rs:58:13
    |
 58 |     let _ = E::A as *const u8;
    |             ^^^^^^^^^^^^^^^^^
 
-error: casting `char` as `*const u8` is invalid
+error[E0606]: casting `char` as `*const u8` is invalid
   --> $DIR/cast-rfc0401.rs:59:13
    |
 59 |     let _ = 'a' as *const u8;
    |             ^^^^^^^^^^^^^^^^
 
-error: casting `usize` as `*const [u8]` is invalid
+error[E0606]: casting `usize` as `*const [u8]` is invalid
   --> $DIR/cast-rfc0401.rs:61:13
    |
 61 |     let _ = 42usize as *const [u8];
    |             ^^^^^^^^^^^^^^^^^^^^^^
 
-error: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
+error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
   --> $DIR/cast-rfc0401.rs:62:13
    |
 62 |     let _ = v as *const [u8];
    |             ^^^^^^^^^^^^^^^^
 
-error: casting `&Foo` as `*const str` is invalid
+error[E0606]: casting `&Foo` as `*const str` is invalid
   --> $DIR/cast-rfc0401.rs:64:13
    |
 64 |     let _ = foo as *const str;
    |             ^^^^^^^^^^^^^^^^^
 
-error: casting `&Foo` as `*mut str` is invalid
+error[E0606]: casting `&Foo` as `*mut str` is invalid
   --> $DIR/cast-rfc0401.rs:65:13
    |
 65 |     let _ = foo as *mut str;
    |             ^^^^^^^^^^^^^^^
 
-error: casting `fn() {main}` as `*mut str` is invalid
+error[E0606]: casting `fn() {main}` as `*mut str` is invalid
   --> $DIR/cast-rfc0401.rs:66:13
    |
 66 |     let _ = main as *mut str;
    |             ^^^^^^^^^^^^^^^^
 
-error: casting `&f32` as `*mut f32` is invalid
+error[E0606]: casting `&f32` as `*mut f32` is invalid
   --> $DIR/cast-rfc0401.rs:67:13
    |
 67 |     let _ = &f as *mut f32;
    |             ^^^^^^^^^^^^^^
 
-error: casting `&f32` as `*const f64` is invalid
+error[E0606]: casting `&f32` as `*const f64` is invalid
   --> $DIR/cast-rfc0401.rs:68:13
    |
 68 |     let _ = &f as *const f64;
    |             ^^^^^^^^^^^^^^^^
 
-error: casting `*const [i8]` as `usize` is invalid
+error[E0606]: casting `*const [i8]` as `usize` is invalid
   --> $DIR/cast-rfc0401.rs:69:13
    |
 69 |     let _ = fat_sv as usize;
@@ -190,7 +200,7 @@ error: casting `*const [i8]` as `usize` is invalid
    |
    = help: cast through a thin pointer first
 
-error: casting `*const Foo` as `*const [u16]` is invalid
+error[E0606]: casting `*const Foo` as `*const [u16]` is invalid
   --> $DIR/cast-rfc0401.rs:78:13
    |
 78 |     let _ = cf as *const [u16];
@@ -198,7 +208,7 @@ error: casting `*const Foo` as `*const [u16]` is invalid
    |
    = note: vtable kinds may not match
 
-error: casting `*const Foo` as `*const Bar` is invalid
+error[E0606]: casting `*const Foo` as `*const Bar` is invalid
   --> $DIR/cast-rfc0401.rs:79:13
    |
 79 |     let _ = cf as *const Bar;
@@ -224,7 +234,7 @@ error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
    = help: the trait `std::marker::Sized` is not implemented for `str`
    = note: required for the cast to the object type `Foo`
 
-error: casting `&{float}` as `f32` is invalid
+error[E0606]: casting `&{float}` as `f32` is invalid
   --> $DIR/cast-rfc0401.rs:81:30
    |
 81 |     vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>();
diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr
index dc3764a376cde..9da9042e78ed1 100644
--- a/src/test/ui/mismatched_types/issue-26480.stderr
+++ b/src/test/ui/mismatched_types/issue-26480.stderr
@@ -7,7 +7,7 @@ error[E0308]: mismatched types
 37 |     write!(hello);
    |     -------------- in this macro invocation
 
-error: non-scalar cast: `{integer}` as `()`
+error[E0605]: non-primitive cast: `{integer}` as `()`
   --> $DIR/issue-26480.rs:32:19
    |
 32 |     ($x:expr) => ($x as ())
@@ -15,6 +15,8 @@ error: non-scalar cast: `{integer}` as `()`
 ...
 38 |     cast!(2);
    |     --------- in this macro invocation
+   |
+   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
 
 error: aborting due to previous error(s)
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 0692e07253fbe..4961609c77fbd 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -692,7 +692,7 @@ actual:\n\
         }
 
         if !debugger_run_result.status.success() {
-            self.fatal("gdb failed to execute");
+            self.fatal_proc_rec("gdb failed to execute", &debugger_run_result);
         }
 
         self.check_debugger_output(&debugger_run_result, &check_lines);