diff --git a/src/doc/index.md b/src/doc/index.md
index 982e24ef69549..1f262b360e3ed 100644
--- a/src/doc/index.md
+++ b/src/doc/index.md
@@ -28,6 +28,7 @@ Rust provides a number of book-length sets of documentation, collectively
 nicknamed 'The Rust Bookshelf.'
 
 * [The Rust Programming Language][book] teaches you how to program in Rust.
+* [The Unstable Book][unstable-book] has documentation for unstable features.
 * [The Rustonomicon][nomicon] is your guidebook to the dark arts of unsafe Rust.
 * [The Reference][ref] is not a formal spec, but is more detailed and comprehensive than the book.
 
@@ -44,4 +45,5 @@ landed before then. That work is being tracked [here][38643].
 [err]: error-index.html
 [book]: book/index.html
 [nomicon]: nomicon/index.html
+[unstable-book]: unstable-book/index.html
 
diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs
index 4979107ccadc7..43323676ab459 100644
--- a/src/libcollections/string.rs
+++ b/src/libcollections/string.rs
@@ -433,6 +433,10 @@ impl String {
     ///
     /// [`str::from_utf8()`]: ../../std/str/fn.from_utf8.html
     ///
+    /// The inverse of this method is [`as_bytes`].
+    ///
+    /// [`as_bytes`]: #method.as_bytes
+    ///
     /// # Errors
     ///
     /// Returns `Err` if the slice is not UTF-8 with a description as to why the
@@ -979,6 +983,10 @@ impl String {
 
     /// Returns a byte slice of this `String`'s contents.
     ///
+    /// The inverse of this method is [`from_utf8`].
+    ///
+    /// [`from_utf8`]: #method.from_utf8
+    ///
     /// # Examples
     ///
     /// Basic usage:
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 72a47c0028162..bd67dd2e6b25d 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -152,7 +152,11 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
                         Some(&adt_def.variants[variant_index])
                     }
                     _ => if let ty::TyAdt(adt, _) = self.ty.sty {
-                        Some(adt.struct_variant())
+                        if adt.is_univariant() {
+                            Some(&adt.variants[0])
+                        } else {
+                            None
+                        }
                     } else {
                         None
                     }
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 28ce9126019eb..f9b7c68587678 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -189,11 +189,38 @@ impl LintPass for UnusedUnsafe {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedUnsafe {
     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
+        /// Return the NodeId for an enclosing scope that is also `unsafe`
+        fn is_enclosed(cx: &LateContext, id: ast::NodeId) -> Option<(String, ast::NodeId)> {
+            let parent_id = cx.tcx.hir.get_parent_node(id);
+            if parent_id != id {
+                if cx.tcx.used_unsafe.borrow().contains(&parent_id) {
+                    Some(("block".to_string(), parent_id))
+                } else if let Some(hir::map::NodeItem(&hir::Item {
+                    node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _),
+                    ..
+                })) = cx.tcx.hir.find(parent_id) {
+                    Some(("fn".to_string(), parent_id))
+                } else {
+                    is_enclosed(cx, parent_id)
+                }
+            } else {
+                None
+            }
+        }
         if let hir::ExprBlock(ref blk) = e.node {
             // Don't warn about generated blocks, that'll just pollute the output.
             if blk.rules == hir::UnsafeBlock(hir::UserProvided) &&
                !cx.tcx.used_unsafe.borrow().contains(&blk.id) {
-                cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block");
+
+                let mut db = cx.struct_span_lint(UNUSED_UNSAFE, blk.span,
+                                                 "unnecessary `unsafe` block");
+
+                db.span_label(blk.span, &"unnecessary `unsafe` block");
+                if let Some((kind, id)) = is_enclosed(cx, blk.id) {
+                    db.span_note(cx.tcx.hir.span(id),
+                                 &format!("because it's nested under this `unsafe` {}", kind));
+                }
+                db.emit();
             }
         }
     }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 093994ba8257d..d51ec268ec217 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -69,6 +69,7 @@ use errors::DiagnosticBuilder;
 
 use std::cell::{Cell, RefCell};
 use std::cmp;
+use std::collections::BTreeSet;
 use std::fmt;
 use std::mem::replace;
 use std::rc::Rc;
@@ -97,6 +98,31 @@ enum AssocSuggestion {
     AssocItem,
 }
 
+#[derive(Eq)]
+struct BindingError {
+    name: Name,
+    origin: BTreeSet<Span>,
+    target: BTreeSet<Span>,
+}
+
+impl PartialOrd for BindingError {
+    fn partial_cmp(&self, other: &BindingError) -> Option<cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl PartialEq for BindingError {
+    fn eq(&self, other: &BindingError) -> bool {
+        self.name == other.name
+    }
+}
+
+impl Ord for BindingError {
+    fn cmp(&self, other: &BindingError) -> cmp::Ordering {
+        self.name.cmp(&other.name)
+    }
+}
+
 enum ResolutionError<'a> {
     /// error E0401: can't use type parameters from outer function
     TypeParametersFromOuterFunction,
@@ -110,10 +136,10 @@ enum ResolutionError<'a> {
     TypeNotMemberOfTrait(Name, &'a str),
     /// error E0438: const is not a member of trait
     ConstNotMemberOfTrait(Name, &'a str),
-    /// error E0408: variable `{}` from pattern #{} is not bound in pattern #{}
-    VariableNotBoundInPattern(Name, usize, usize),
-    /// error E0409: variable is bound with different mode in pattern #{} than in pattern #1
-    VariableBoundWithDifferentMode(Name, usize, Span),
+    /// error E0408: variable `{}` is not bound in all patterns
+    VariableNotBoundInPattern(&'a BindingError),
+    /// error E0409: variable `{}` is bound in inconsistent ways within the same match arm
+    VariableBoundWithDifferentMode(Name, Span),
     /// error E0415: identifier is bound more than once in this parameter list
     IdentifierBoundMoreThanOnceInParameterList(&'a str),
     /// error E0416: identifier is bound more than once in the same pattern
@@ -207,27 +233,28 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
             err.span_label(span, &format!("not a member of trait `{}`", trait_));
             err
         }
-        ResolutionError::VariableNotBoundInPattern(variable_name, from, to) => {
-            let mut err = struct_span_err!(resolver.session,
-                             span,
-                             E0408,
-                             "variable `{}` from pattern #{} is not bound in pattern #{}",
-                             variable_name,
-                             from,
-                             to);
-            err.span_label(span, &format!("pattern doesn't bind `{}`", variable_name));
+        ResolutionError::VariableNotBoundInPattern(binding_error) => {
+            let target_sp = binding_error.target.iter().map(|x| *x).collect::<Vec<_>>();
+            let msp = MultiSpan::from_spans(target_sp.clone());
+            let msg = format!("variable `{}` is not bound in all patterns", binding_error.name);
+            let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408");
+            for sp in target_sp {
+                err.span_label(sp, &format!("pattern doesn't bind `{}`", binding_error.name));
+            }
+            let origin_sp = binding_error.origin.iter().map(|x| *x).collect::<Vec<_>>();
+            for sp in origin_sp {
+                err.span_label(sp, &"variable not in all patterns");
+            }
             err
         }
         ResolutionError::VariableBoundWithDifferentMode(variable_name,
-                                                        pattern_number,
                                                         first_binding_span) => {
             let mut err = struct_span_err!(resolver.session,
                              span,
                              E0409,
-                             "variable `{}` is bound with different mode in pattern #{} than in \
-                              pattern #1",
-                             variable_name,
-                             pattern_number);
+                             "variable `{}` is bound in inconsistent \
+                             ways within the same match arm",
+                             variable_name);
             err.span_label(span, &format!("bound in different ways"));
             err.span_label(first_binding_span, &format!("first binding"));
             err
@@ -335,7 +362,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
     }
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 struct BindingInfo {
     span: Span,
     binding_mode: BindingMode,
@@ -1904,36 +1931,66 @@ impl<'a> Resolver<'a> {
         if arm.pats.is_empty() {
             return;
         }
-        let map_0 = self.binding_mode_map(&arm.pats[0]);
+
+        let mut missing_vars = FxHashMap();
+        let mut inconsistent_vars = FxHashMap();
         for (i, p) in arm.pats.iter().enumerate() {
             let map_i = self.binding_mode_map(&p);
 
-            for (&key, &binding_0) in &map_0 {
-                match map_i.get(&key) {
-                    None => {
-                        let error = ResolutionError::VariableNotBoundInPattern(key.name, 1, i + 1);
-                        resolve_error(self, p.span, error);
+            for (j, q) in arm.pats.iter().enumerate() {
+                if i == j {
+                    continue;
+                }
+
+                let map_j = self.binding_mode_map(&q);
+                for (&key, &binding_i) in &map_i {
+                    if map_j.len() == 0 {                   // Account for missing bindings when
+                        let binding_error = missing_vars    // map_j has none.
+                            .entry(key.name)
+                            .or_insert(BindingError {
+                                name: key.name,
+                                origin: BTreeSet::new(),
+                                target: BTreeSet::new(),
+                            });
+                        binding_error.origin.insert(binding_i.span);
+                        binding_error.target.insert(q.span);
                     }
-                    Some(binding_i) => {
-                        if binding_0.binding_mode != binding_i.binding_mode {
-                            resolve_error(self,
-                                          binding_i.span,
-                                          ResolutionError::VariableBoundWithDifferentMode(
-                                              key.name,
-                                              i + 1,
-                                              binding_0.span));
+                    for (&key_j, &binding_j) in &map_j {
+                        match map_i.get(&key_j) {
+                            None => {  // missing binding
+                                let binding_error = missing_vars
+                                    .entry(key_j.name)
+                                    .or_insert(BindingError {
+                                        name: key_j.name,
+                                        origin: BTreeSet::new(),
+                                        target: BTreeSet::new(),
+                                    });
+                                binding_error.origin.insert(binding_j.span);
+                                binding_error.target.insert(p.span);
+                            }
+                            Some(binding_i) => {  // check consistent binding
+                                if binding_i.binding_mode != binding_j.binding_mode {
+                                    inconsistent_vars
+                                        .entry(key.name)
+                                        .or_insert((binding_j.span, binding_i.span));
+                                }
+                            }
                         }
                     }
                 }
             }
-
-            for (&key, &binding) in &map_i {
-                if !map_0.contains_key(&key) {
-                    resolve_error(self,
-                                  binding.span,
-                                  ResolutionError::VariableNotBoundInPattern(key.name, i + 1, 1));
-                }
-            }
+        }
+        let mut missing_vars = missing_vars.iter().collect::<Vec<_>>();
+        missing_vars.sort();
+        for (_, v) in missing_vars {
+            resolve_error(self,
+                          *v.origin.iter().next().unwrap(),
+                          ResolutionError::VariableNotBoundInPattern(v));
+        }
+        let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>();
+        inconsistent_vars.sort();
+        for (name, v) in inconsistent_vars {
+            resolve_error(self, v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
         }
     }
 
diff --git a/src/test/compile-fail/E0408.rs b/src/test/compile-fail/E0408.rs
index d75f612482772..ce77a537e263d 100644
--- a/src/test/compile-fail/E0408.rs
+++ b/src/test/compile-fail/E0408.rs
@@ -12,7 +12,8 @@ fn main() {
     let x = Some(0);
 
     match x {
-        Some(y) | None => {} //~  ERROR variable `y` from pattern #1 is not bound in pattern #2
+        Some(y) | None => {} //~  ERROR variable `y` is not bound in all patterns
         _ => ()              //~| NOTE pattern doesn't bind `y`
+                             //~| NOTE variable not in all patterns
     }
 }
diff --git a/src/test/compile-fail/issue-2848.rs b/src/test/compile-fail/issue-2848.rs
index f5e0c545bb524..38bd7adefd91f 100644
--- a/src/test/compile-fail/issue-2848.rs
+++ b/src/test/compile-fail/issue-2848.rs
@@ -19,7 +19,8 @@ mod bar {
 fn main() {
     use bar::foo::{alpha, charlie};
     match alpha {
-      alpha | beta => {} //~  ERROR variable `beta` from pattern #2 is not bound in pattern #1
+      alpha | beta => {} //~  ERROR variable `beta` is not bound in all patterns
       charlie => {}      //~| NOTE pattern doesn't bind `beta`
+                         //~| NOTE variable not in all patterns
     }
 }
diff --git a/src/test/compile-fail/issue-2849.rs b/src/test/compile-fail/issue-2849.rs
index 48f4cac9711a8..203b28bd5e417 100644
--- a/src/test/compile-fail/issue-2849.rs
+++ b/src/test/compile-fail/issue-2849.rs
@@ -13,6 +13,6 @@ enum foo { alpha, beta(isize) }
 fn main() {
     match foo::alpha {
       foo::alpha | foo::beta(i) => {}
-      //~^ ERROR variable `i` from pattern #2 is not bound in pattern #1
+      //~^ ERROR variable `i` is not bound in all patterns
     }
 }
diff --git a/src/test/compile-fail/resolve-inconsistent-binding-mode.rs b/src/test/compile-fail/resolve-inconsistent-binding-mode.rs
index 284c08ef09b28..63d33a9e5fa6f 100644
--- a/src/test/compile-fail/resolve-inconsistent-binding-mode.rs
+++ b/src/test/compile-fail/resolve-inconsistent-binding-mode.rs
@@ -15,7 +15,7 @@ enum opts {
 fn matcher1(x: opts) {
     match x {
       opts::a(ref i) | opts::b(i) => {}
-      //~^ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1
+      //~^ ERROR variable `i` is bound in inconsistent ways within the same match arm
       //~^^ ERROR mismatched types
       opts::c(_) => {}
     }
@@ -24,7 +24,7 @@ fn matcher1(x: opts) {
 fn matcher2(x: opts) {
     match x {
       opts::a(ref i) | opts::b(i) => {}
-      //~^ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1
+      //~^ ERROR variable `i` is bound in inconsistent ways within the same match arm
       //~^^ ERROR mismatched types
       opts::c(_) => {}
     }
@@ -33,7 +33,7 @@ fn matcher2(x: opts) {
 fn matcher4(x: opts) {
     match x {
       opts::a(ref mut i) | opts::b(ref i) => {}
-      //~^ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1
+      //~^ ERROR variable `i` is bound in inconsistent ways within the same match arm
       //~^^ ERROR mismatched types
       opts::c(_) => {}
     }
diff --git a/src/test/compile-fail/resolve-inconsistent-names.rs b/src/test/compile-fail/resolve-inconsistent-names.rs
index 1e2541502ace8..7fee5aedb06ed 100644
--- a/src/test/compile-fail/resolve-inconsistent-names.rs
+++ b/src/test/compile-fail/resolve-inconsistent-names.rs
@@ -11,9 +11,11 @@
 fn main() {
     let y = 1;
     match y {
-       a | b => {} //~  ERROR variable `a` from pattern #1 is not bound in pattern #2
-                   //~^ ERROR variable `b` from pattern #2 is not bound in pattern #1
+       a | b => {} //~  ERROR variable `a` is not bound in all patterns
+                   //~^ ERROR variable `b` is not bound in all patterns
                    //~| NOTE pattern doesn't bind `a`
                    //~| NOTE pattern doesn't bind `b`
+                   //~| NOTE variable not in all patterns
+                   //~| NOTE variable not in all patterns
     }
 }
diff --git a/src/test/ui/mismatched_types/E0409.stderr b/src/test/ui/mismatched_types/E0409.stderr
index 251e247fa28ba..45a42b1c271f8 100644
--- a/src/test/ui/mismatched_types/E0409.stderr
+++ b/src/test/ui/mismatched_types/E0409.stderr
@@ -1,4 +1,4 @@
-error[E0409]: variable `y` is bound with different mode in pattern #2 than in pattern #1
+error[E0409]: variable `y` is bound in inconsistent ways within the same match arm
   --> $DIR/E0409.rs:15:23
    |
 15 |         (0, ref y) | (y, 0) => {} //~ ERROR E0409
diff --git a/src/test/ui/missing-items/issue-40221.rs b/src/test/ui/missing-items/issue-40221.rs
new file mode 100644
index 0000000000000..9cf1c7d6de8a4
--- /dev/null
+++ b/src/test/ui/missing-items/issue-40221.rs
@@ -0,0 +1,26 @@
+// 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.
+
+enum P {
+    C(PC),
+}
+
+enum PC {
+    Q,
+    QA,
+}
+
+fn test(proto: P) {
+    match proto {
+        P::C(PC::Q) => (),
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/missing-items/issue-40221.stderr b/src/test/ui/missing-items/issue-40221.stderr
new file mode 100644
index 0000000000000..3552da801c6ab
--- /dev/null
+++ b/src/test/ui/missing-items/issue-40221.stderr
@@ -0,0 +1,8 @@
+error[E0004]: non-exhaustive patterns: `C(QA)` not covered
+  --> $DIR/issue-40221.rs:11:11
+   |
+21 |     match proto {
+   |           ^^^^^ pattern `C(QA)` not covered
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/span/issue-39698.rs b/src/test/ui/span/issue-39698.rs
new file mode 100644
index 0000000000000..17b3f1c5a885e
--- /dev/null
+++ b/src/test/ui/span/issue-39698.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.
+
+enum T {
+    T1(i32, i32),
+    T2(i32, i32),
+    T3(i32),
+    T4(i32),
+}
+
+fn main() {
+    match T::T1(123, 456) {
+        T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+    }
+}
diff --git a/src/test/ui/span/issue-39698.stderr b/src/test/ui/span/issue-39698.stderr
new file mode 100644
index 0000000000000..97d802f839831
--- /dev/null
+++ b/src/test/ui/span/issue-39698.stderr
@@ -0,0 +1,42 @@
+error[E0408]: variable `a` is not bound in all patterns
+  --> $DIR/issue-39698.rs:20:23
+   |
+20 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+   |               -       ^^^^^^^^^^^   ^^^^^^^^         - variable not in all patterns
+   |               |       |             |
+   |               |       |             pattern doesn't bind `a`
+   |               |       pattern doesn't bind `a`
+   |               variable not in all patterns
+
+error[E0408]: variable `d` is not bound in all patterns
+  --> $DIR/issue-39698.rs:20:37
+   |
+20 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+   |                  -          -       ^^^^^^^^   ^^^^^^^^ pattern doesn't bind `d`
+   |                  |          |       |
+   |                  |          |       pattern doesn't bind `d`
+   |                  |          variable not in all patterns
+   |                  variable not in all patterns
+
+error[E0408]: variable `b` is not bound in all patterns
+  --> $DIR/issue-39698.rs:20:9
+   |
+20 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+   |         ^^^^^^^^^^^            -    ^^^^^^^^   ^^^^^^^^ pattern doesn't bind `b`
+   |         |                      |    |
+   |         |                      |    pattern doesn't bind `b`
+   |         |                      variable not in all patterns
+   |         pattern doesn't bind `b`
+
+error[E0408]: variable `c` is not bound in all patterns
+  --> $DIR/issue-39698.rs:20:9
+   |
+20 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
+   |         ^^^^^^^^^^^   ^^^^^^^^^^^         -    ^^^^^^^^ pattern doesn't bind `c`
+   |         |             |                   |
+   |         |             |                   variable not in all patterns
+   |         |             pattern doesn't bind `c`
+   |         pattern doesn't bind `c`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/compile-fail/lint-unused-unsafe.rs b/src/test/ui/span/lint-unused-unsafe.rs
similarity index 100%
rename from src/test/compile-fail/lint-unused-unsafe.rs
rename to src/test/ui/span/lint-unused-unsafe.rs
diff --git a/src/test/ui/span/lint-unused-unsafe.stderr b/src/test/ui/span/lint-unused-unsafe.stderr
new file mode 100644
index 0000000000000..0df3fa43022a4
--- /dev/null
+++ b/src/test/ui/span/lint-unused-unsafe.stderr
@@ -0,0 +1,116 @@
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:26:13
+   |
+26 | fn bad1() { unsafe {} }                  //~ ERROR: unnecessary `unsafe` block
+   |             ^^^^^^^^^ unnecessary `unsafe` block
+   |
+note: lint level defined here
+  --> $DIR/lint-unused-unsafe.rs:14:9
+   |
+14 | #![deny(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:27:13
+   |
+27 | fn bad2() { unsafe { bad1() } }          //~ ERROR: unnecessary `unsafe` block
+   |             ^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:28:20
+   |
+28 | unsafe fn bad3() { unsafe {} }           //~ ERROR: unnecessary `unsafe` block
+   |                    ^^^^^^^^^ unnecessary `unsafe` block
+   |
+note: because it's nested under this `unsafe` fn
+  --> $DIR/lint-unused-unsafe.rs:28:1
+   |
+28 | unsafe fn bad3() { unsafe {} }           //~ ERROR: unnecessary `unsafe` block
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:29:13
+   |
+29 | fn bad4() { unsafe { callback(||{}) } }  //~ ERROR: unnecessary `unsafe` block
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:30:20
+   |
+30 | unsafe fn bad5() { unsafe { unsf() } }   //~ ERROR: unnecessary `unsafe` block
+   |                    ^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block
+   |
+note: because it's nested under this `unsafe` fn
+  --> $DIR/lint-unused-unsafe.rs:30:1
+   |
+30 | unsafe fn bad5() { unsafe { unsf() } }   //~ ERROR: unnecessary `unsafe` block
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:33:9
+   |
+33 |           unsafe {                         //~ ERROR: unnecessary `unsafe` block
+   |  _________^ starting here...
+34 | |             unsf()
+35 | |         }
+   | |_________^ ...ending here: unnecessary `unsafe` block
+   |
+note: because it's nested under this `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:32:5
+   |
+32 |       unsafe {                             // don't put the warning here
+   |  _____^ starting here...
+33 | |         unsafe {                         //~ ERROR: unnecessary `unsafe` block
+34 | |             unsf()
+35 | |         }
+36 | |     }
+   | |_____^ ...ending here
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:39:5
+   |
+39 |       unsafe {                             //~ ERROR: unnecessary `unsafe` block
+   |  _____^ starting here...
+40 | |         unsafe {                         //~ ERROR: unnecessary `unsafe` block
+41 | |             unsf()
+42 | |         }
+43 | |     }
+   | |_____^ ...ending here: unnecessary `unsafe` block
+   |
+note: because it's nested under this `unsafe` fn
+  --> $DIR/lint-unused-unsafe.rs:38:1
+   |
+38 |   unsafe fn bad7() {
+   |  _^ starting here...
+39 | |     unsafe {                             //~ ERROR: unnecessary `unsafe` block
+40 | |         unsafe {                         //~ ERROR: unnecessary `unsafe` block
+41 | |             unsf()
+42 | |         }
+43 | |     }
+44 | | }
+   | |_^ ...ending here
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:40:9
+   |
+40 |           unsafe {                         //~ ERROR: unnecessary `unsafe` block
+   |  _________^ starting here...
+41 | |             unsf()
+42 | |         }
+   | |_________^ ...ending here: unnecessary `unsafe` block
+   |
+note: because it's nested under this `unsafe` fn
+  --> $DIR/lint-unused-unsafe.rs:38:1
+   |
+38 |   unsafe fn bad7() {
+   |  _^ starting here...
+39 | |     unsafe {                             //~ ERROR: unnecessary `unsafe` block
+40 | |         unsafe {                         //~ ERROR: unnecessary `unsafe` block
+41 | |             unsf()
+42 | |         }
+43 | |     }
+44 | | }
+   | |_^ ...ending here
+
+error: aborting due to 8 previous errors
+