]> git.lizzy.rs Git - rust.git/commitdiff
Reimplement unused_labels lint as a compiler builtin in the resolver
authorKyle Stachowicz <kylestach99@gmail.com>
Fri, 18 May 2018 00:20:30 +0000 (17:20 -0700)
committerKyle Stachowicz <kylestach99@gmail.com>
Fri, 18 May 2018 23:57:15 +0000 (16:57 -0700)
src/librustc/lint/builtin.rs
src/librustc_resolve/check_unused.rs
src/librustc_resolve/lib.rs
src/test/ui/lint/unused_labels.rs [new file with mode: 0644]
src/test/ui/lint/unused_labels.stderr [new file with mode: 0644]
src/test/ui/loops-reject-duplicate-labels-2.rs
src/test/ui/loops-reject-duplicate-labels-2.stderr
src/test/ui/loops-reject-duplicate-labels.rs
src/test/ui/loops-reject-duplicate-labels.stderr
src/test/ui/suggestions/suggest-labels.rs

index c55c71f85dab78582fd0c433c28d74846a96bcc3..71eefec2210e46fb324b8e33fb2f85634425f833 100644 (file)
     "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)]
@@ -325,6 +331,7 @@ fn get_lints(&self) -> LintArray {
             UNUSED_MUT,
             SINGLE_USE_LIFETIME,
             UNUSED_LIFETIME,
+            UNUSED_LABELS,
             TYVAR_BEHIND_RAW_POINTER,
             ELIDED_LIFETIME_IN_PATH,
             BARE_TRAIT_OBJECT,
index 163f6a64010b502968cd733d202d37af5abe879d..590ce168d5d0fdac64d6dd81967a5aa308d5d881 100644 (file)
@@ -142,6 +142,10 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) {
         }
     }
 
+    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(),
index e13e6bc6b745677f9b60009920a89a60626102b5..feb5af571e43505038bc9753a711ddda8f6f0793 100644 (file)
@@ -1473,6 +1473,10 @@ pub struct Resolver<'a> {
     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
@@ -1752,6 +1756,8 @@ pub fn new(session: &'a Session,
             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(),
@@ -3694,6 +3700,7 @@ fn with_resolved_label<F>(&mut self, label: Option<Label>, id: NodeId, f: F)
         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);
@@ -3742,9 +3749,10 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
                                       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!");
diff --git a/src/test/ui/lint/unused_labels.rs b/src/test/ui/lint/unused_labels.rs
new file mode 100644 (file)
index 0000000..86abb34
--- /dev/null
@@ -0,0 +1,75 @@
+// 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
+    }
+}
diff --git a/src/test/ui/lint/unused_labels.stderr b/src/test/ui/lint/unused_labels.stderr
new file mode 100644 (file)
index 0000000..425b0b1
--- /dev/null
@@ -0,0 +1,53 @@
+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
+
index 598c7370b89069220733fa0d37428196d265ec0c..b273e7a0c7c9e750e02fc085d2ef8c31603b70d9 100644 (file)
@@ -18,6 +18,7 @@
 // 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
index 830270a99d1123a9845ba4dc5be3f3e1e1f360f8..41b4a850f1bfb28c5c426665c45ad2b494e88b52 100644 (file)
@@ -1,5 +1,5 @@
 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
@@ -7,7 +7,7 @@ LL |     { 'fl: loop { break; } }             //~ WARN label name `'fl` shadows
    |       ^^^ 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
@@ -15,7 +15,7 @@ LL |     { 'lf: for _ in 0..10 { break; } }   //~ WARN label name `'lf` shadows
    |       ^^^ 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
@@ -23,7 +23,7 @@ LL |     { 'wl: loop { break; } }             //~ WARN label name `'wl` shadows
    |       ^^^ 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
@@ -31,7 +31,7 @@ LL |     { 'lw: while 2 > 1 { break; } }      //~ WARN label name `'lw` shadows
    |       ^^^ 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
@@ -39,7 +39,7 @@ LL |     { 'fw: while 2 > 1 { break; } }      //~ WARN label name `'fw` shadows
    |       ^^^ 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
@@ -47,7 +47,7 @@ LL |     { 'wf: for _ in 0..10 { break; } }   //~ WARN label name `'wf` shadows
    |       ^^^ 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
@@ -55,7 +55,7 @@ LL |     { 'tl: loop { break; } }             //~ WARN label name `'tl` shadows
    |       ^^^ 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
@@ -63,7 +63,7 @@ LL |     { 'lt: while let Some(_) = None::<i32> { break; } }
    |       ^^^ 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();
index d768b002ab10cbd079863ad3e246ac55743b569c..ad24f69871c85cdf3bd4e1076d4e4a4dac401695 100644 (file)
@@ -15,6 +15,7 @@
 // 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
index a71f98b812a8c136b6b9dea934367e7de6784bb1..d0cb81544f8280840c91e866b01c3bc00f7af807 100644 (file)
@@ -1,5 +1,5 @@
 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
@@ -7,7 +7,7 @@ LL |     'fl: loop { break; }           //~ WARN label name `'fl` shadows a labe
    |     ^^^ 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
@@ -15,7 +15,7 @@ LL |     'lf: for _ in 0..10 { break; } //~ WARN label name `'lf` shadows a labe
    |     ^^^ 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
@@ -23,7 +23,7 @@ LL |     'wl: loop { break; }           //~ WARN label name `'wl` shadows a labe
    |     ^^^ 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
@@ -31,7 +31,7 @@ LL |     'lw: while 2 > 1 { break; }    //~ WARN label name `'lw` shadows a labe
    |     ^^^ 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
@@ -39,7 +39,7 @@ LL |     'fw: while 2 > 1 { break; }    //~ WARN label name `'fw` shadows a labe
    |     ^^^ 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
@@ -47,7 +47,7 @@ LL |     'wf: for _ in 0..10 { break; } //~ WARN label name `'wf` shadows a labe
    |     ^^^ 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
@@ -55,7 +55,7 @@ LL |     'tl: loop { break; }           //~ WARN label name `'tl` shadows a labe
    |     ^^^ 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
@@ -63,7 +63,7 @@ LL |     'lt: while let Some(_) = None::<i32> { break; }
    |     ^^^ 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;
index 8c97301f40b91c1a23221d70d53b753170ec531b..9fb519c57edf35dbfade0332a3fa1fe5eb2d8b05 100644 (file)
@@ -8,7 +8,7 @@
 // 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