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 +