"detects name collision with an existing but unstable method"
}
+declare_lint! {
+ pub UNUSED_LABELS,
+ Warn,
+ "detects labels that are never used"
+}
+
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
UNUSED_MUT,
SINGLE_USE_LIFETIME,
UNUSED_LIFETIME,
+ UNUSED_LABELS,
TYVAR_BEHIND_RAW_POINTER,
ELIDED_LIFETIME_IN_PATH,
BARE_TRAIT_OBJECT,
}
}
+ for (id, span) in resolver.unused_labels.iter() {
+ resolver.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
+ }
+
let mut visitor = UnusedImportCheckVisitor {
resolver,
unused_imports: NodeMap(),
pub maybe_unused_trait_imports: NodeSet,
pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
+ /// A list of labels as of yet unused. Labels will be removed from this map when
+ /// they are used (in a `break` or `continue` statement)
+ pub unused_labels: FxHashMap<NodeId, Span>,
+
/// privacy errors are delayed until the end in order to deduplicate them
privacy_errors: Vec<PrivacyError<'a>>,
/// ambiguity errors are delayed for deduplication
maybe_unused_trait_imports: NodeSet(),
maybe_unused_extern_crates: Vec::new(),
+ unused_labels: FxHashMap(),
+
privacy_errors: Vec::new(),
ambiguity_errors: Vec::new(),
use_injections: Vec::new(),
where F: FnOnce(&mut Resolver)
{
if let Some(label) = label {
+ self.unused_labels.insert(id, label.ident.span);
let def = Def::Label(id);
self.with_label_rib(|this| {
this.label_ribs.last_mut().unwrap().bindings.insert(label.ident, def);
ResolutionError::UndeclaredLabel(&label.ident.name.as_str(),
close_match));
}
- Some(def @ Def::Label(_)) => {
+ Some(Def::Label(id)) => {
// Since this def is a label, it is never read.
- self.record_def(expr.id, PathResolution::new(def));
+ self.record_def(expr.id, PathResolution::new(Def::Label(id)));
+ self.unused_labels.remove(&id);
}
Some(_) => {
span_bug!(expr.span, "label wasn't mapped to a label def!");
--- /dev/null
+// 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.
+
+// The output should warn when a loop label is not used. However, it
+// should also deal with the edge cases where a label is shadowed,
+// within nested loops
+
+// compile-pass
+
+fn main() {
+ 'unused_while_label: while 0 == 0 {
+ //~^ WARN unused label
+ }
+
+ let opt = Some(0);
+ 'unused_while_let_label: while let Some(_) = opt {
+ //~^ WARN unused label
+ }
+
+ 'unused_for_label: for _ in 0..10 {
+ //~^ WARN unused label
+ }
+
+ 'used_loop_label: loop {
+ break 'used_loop_label;
+ }
+
+ 'used_loop_label_outer_1: for _ in 0..10 {
+ 'used_loop_label_inner_1: for _ in 0..10 {
+ break 'used_loop_label_inner_1;
+ }
+ break 'used_loop_label_outer_1;
+ }
+
+ 'used_loop_label_outer_2: for _ in 0..10 {
+ 'unused_loop_label_inner_2: for _ in 0..10 {
+ //~^ WARN unused label
+ break 'used_loop_label_outer_2;
+ }
+ }
+
+ 'unused_loop_label_outer_3: for _ in 0..10 {
+ //~^ WARN unused label
+ 'used_loop_label_inner_3: for _ in 0..10 {
+ break 'used_loop_label_inner_3;
+ }
+ }
+
+ // Test breaking many times with the same inner label doesn't break the
+ // warning on the outer label
+ 'many_used_shadowed: for _ in 0..10 {
+ //~^ WARN unused label
+ 'many_used_shadowed: for _ in 0..10 {
+ //~^ WARN label name `'many_used_shadowed` shadows a label name that is already in scope
+ if 1 % 2 == 0 {
+ break 'many_used_shadowed;
+ } else {
+ break 'many_used_shadowed;
+ }
+ }
+ }
+
+ // This is diverging, so put it at the end so we don't get
+ // unreachable_code errors everywhere else
+ 'unused_loop_label: loop {
+ //~^ WARN unused label
+ }
+}
--- /dev/null
+warning: unused label
+ --> $DIR/unused_labels.rs:18:5
+ |
+LL | 'unused_while_label: while 0 == 0 {
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: #[warn(unused_labels)] on by default
+
+warning: unused label
+ --> $DIR/unused_labels.rs:23:5
+ |
+LL | 'unused_while_let_label: while let Some(_) = opt {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: unused label
+ --> $DIR/unused_labels.rs:27:5
+ |
+LL | 'unused_for_label: for _ in 0..10 {
+ | ^^^^^^^^^^^^^^^^^
+
+warning: unused label
+ --> $DIR/unused_labels.rs:43:9
+ |
+LL | 'unused_loop_label_inner_2: for _ in 0..10 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: unused label
+ --> $DIR/unused_labels.rs:49:5
+ |
+LL | 'unused_loop_label_outer_3: for _ in 0..10 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: unused label
+ --> $DIR/unused_labels.rs:58:5
+ |
+LL | 'many_used_shadowed: for _ in 0..10 {
+ | ^^^^^^^^^^^^^^^^^^^
+
+warning: unused label
+ --> $DIR/unused_labels.rs:72:5
+ |
+LL | 'unused_loop_label: loop {
+ | ^^^^^^^^^^^^^^^^^^
+
+warning: label name `'many_used_shadowed` shadows a label name that is already in scope
+ --> $DIR/unused_labels.rs:60:9
+ |
+LL | 'many_used_shadowed: for _ in 0..10 {
+ | ------------------- first declared here
+LL | //~^ WARN unused label
+LL | 'many_used_shadowed: for _ in 0..10 {
+ | ^^^^^^^^^^^^^^^^^^^ lifetime 'many_used_shadowed already in scope
+
// discussed here:
// https://internals.rust-lang.org/t/psa-rejecting-duplicate-loop-labels/1833
+#[allow(unused_labels)]
pub fn foo() {
{ 'fl: for _ in 0..10 { break; } }
{ 'fl: loop { break; } } //~ WARN label name `'fl` shadows a label name that is already in scope
warning: label name `'fl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:23:7
+ --> $DIR/loops-reject-duplicate-labels-2.rs:24:7
|
LL | { 'fl: for _ in 0..10 { break; } }
| --- first declared here
| ^^^ lifetime 'fl already in scope
warning: label name `'lf` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:25:7
+ --> $DIR/loops-reject-duplicate-labels-2.rs:26:7
|
LL | { 'lf: loop { break; } }
| --- first declared here
| ^^^ lifetime 'lf already in scope
warning: label name `'wl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:27:7
+ --> $DIR/loops-reject-duplicate-labels-2.rs:28:7
|
LL | { 'wl: while 2 > 1 { break; } }
| --- first declared here
| ^^^ lifetime 'wl already in scope
warning: label name `'lw` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:29:7
+ --> $DIR/loops-reject-duplicate-labels-2.rs:30:7
|
LL | { 'lw: loop { break; } }
| --- first declared here
| ^^^ lifetime 'lw already in scope
warning: label name `'fw` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:31:7
+ --> $DIR/loops-reject-duplicate-labels-2.rs:32:7
|
LL | { 'fw: for _ in 0..10 { break; } }
| --- first declared here
| ^^^ lifetime 'fw already in scope
warning: label name `'wf` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:33:7
+ --> $DIR/loops-reject-duplicate-labels-2.rs:34:7
|
LL | { 'wf: while 2 > 1 { break; } }
| --- first declared here
| ^^^ lifetime 'wf already in scope
warning: label name `'tl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:35:7
+ --> $DIR/loops-reject-duplicate-labels-2.rs:36:7
|
LL | { 'tl: while let Some(_) = None::<i32> { break; } }
| --- first declared here
| ^^^ lifetime 'tl already in scope
warning: label name `'lt` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:37:7
+ --> $DIR/loops-reject-duplicate-labels-2.rs:38:7
|
LL | { 'lt: loop { break; } }
| --- first declared here
| ^^^ lifetime 'lt already in scope
error: compilation successful
- --> $DIR/loops-reject-duplicate-labels-2.rs:42:1
+ --> $DIR/loops-reject-duplicate-labels-2.rs:43:1
|
LL | / pub fn main() { //~ ERROR compilation successful
LL | | foo();
// Issue #21633: reject duplicate loop labels in function bodies.
// This is testing the exact cases that are in the issue description.
+#[allow(unused_labels)]
fn foo() {
'fl: for _ in 0..10 { break; }
'fl: loop { break; } //~ WARN label name `'fl` shadows a label name that is already in scope
warning: label name `'fl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:20:5
+ --> $DIR/loops-reject-duplicate-labels.rs:21:5
|
LL | 'fl: for _ in 0..10 { break; }
| --- first declared here
| ^^^ lifetime 'fl already in scope
warning: label name `'lf` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:23:5
+ --> $DIR/loops-reject-duplicate-labels.rs:24:5
|
LL | 'lf: loop { break; }
| --- first declared here
| ^^^ lifetime 'lf already in scope
warning: label name `'wl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:25:5
+ --> $DIR/loops-reject-duplicate-labels.rs:26:5
|
LL | 'wl: while 2 > 1 { break; }
| --- first declared here
| ^^^ lifetime 'wl already in scope
warning: label name `'lw` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:27:5
+ --> $DIR/loops-reject-duplicate-labels.rs:28:5
|
LL | 'lw: loop { break; }
| --- first declared here
| ^^^ lifetime 'lw already in scope
warning: label name `'fw` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:29:5
+ --> $DIR/loops-reject-duplicate-labels.rs:30:5
|
LL | 'fw: for _ in 0..10 { break; }
| --- first declared here
| ^^^ lifetime 'fw already in scope
warning: label name `'wf` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:31:5
+ --> $DIR/loops-reject-duplicate-labels.rs:32:5
|
LL | 'wf: while 2 > 1 { break; }
| --- first declared here
| ^^^ lifetime 'wf already in scope
warning: label name `'tl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:33:5
+ --> $DIR/loops-reject-duplicate-labels.rs:34:5
|
LL | 'tl: while let Some(_) = None::<i32> { break; }
| --- first declared here
| ^^^ lifetime 'tl already in scope
warning: label name `'lt` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:35:5
+ --> $DIR/loops-reject-duplicate-labels.rs:36:5
|
LL | 'lt: loop { break; }
| --- first declared here
| ^^^ lifetime 'lt already in scope
error: compilation successful
- --> $DIR/loops-reject-duplicate-labels.rs:49:1
+ --> $DIR/loops-reject-duplicate-labels.rs:50:1
|
LL | / pub fn main() { //~ ERROR compilation successful
LL | | let s = S;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[allow(unreachable_code)]
+#[allow(unreachable_code, unused_labels)]
fn main() {
'foo: loop {
break 'fo; //~ ERROR use of undeclared label