Skip to content

Commit 88f4063

Browse files
committed
Reimplement unused_labels lint as a compiler builtin in the resolver
1 parent 7676982 commit 88f4063

10 files changed

+170
-21
lines changed

src/librustc/lint/builtin.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,12 @@ declare_lint! {
279279
"detects name collision with an existing but unstable method"
280280
}
281281

282+
declare_lint! {
283+
pub UNUSED_LABELS,
284+
Warn,
285+
"detects labels that are never used"
286+
}
287+
282288
/// Does nothing as a lint pass, but registers some `Lint`s
283289
/// which are used by other parts of the compiler.
284290
#[derive(Copy, Clone)]
@@ -325,6 +331,7 @@ impl LintPass for HardwiredLints {
325331
UNUSED_MUT,
326332
SINGLE_USE_LIFETIME,
327333
UNUSED_LIFETIME,
334+
UNUSED_LABELS,
328335
TYVAR_BEHIND_RAW_POINTER,
329336
ELIDED_LIFETIME_IN_PATH,
330337
BARE_TRAIT_OBJECT,

src/librustc_resolve/check_unused.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) {
142142
}
143143
}
144144

145+
for (id, span) in resolver.unused_labels.iter() {
146+
resolver.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
147+
}
148+
145149
let mut visitor = UnusedImportCheckVisitor {
146150
resolver,
147151
unused_imports: NodeMap(),

src/librustc_resolve/lib.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,10 @@ pub struct Resolver<'a> {
14731473
pub maybe_unused_trait_imports: NodeSet,
14741474
pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
14751475

1476+
/// A list of labels as of yet unused. Labels will be removed from this map when
1477+
/// they are used (in a `break` or `continue` statement)
1478+
pub unused_labels: FxHashMap<NodeId, Span>,
1479+
14761480
/// privacy errors are delayed until the end in order to deduplicate them
14771481
privacy_errors: Vec<PrivacyError<'a>>,
14781482
/// ambiguity errors are delayed for deduplication
@@ -1752,6 +1756,8 @@ impl<'a> Resolver<'a> {
17521756
maybe_unused_trait_imports: NodeSet(),
17531757
maybe_unused_extern_crates: Vec::new(),
17541758

1759+
unused_labels: FxHashMap(),
1760+
17551761
privacy_errors: Vec::new(),
17561762
ambiguity_errors: Vec::new(),
17571763
use_injections: Vec::new(),
@@ -3694,6 +3700,7 @@ impl<'a> Resolver<'a> {
36943700
where F: FnOnce(&mut Resolver)
36953701
{
36963702
if let Some(label) = label {
3703+
self.unused_labels.insert(id, label.ident.span);
36973704
let def = Def::Label(id);
36983705
self.with_label_rib(|this| {
36993706
this.label_ribs.last_mut().unwrap().bindings.insert(label.ident, def);
@@ -3742,9 +3749,10 @@ impl<'a> Resolver<'a> {
37423749
ResolutionError::UndeclaredLabel(&label.ident.name.as_str(),
37433750
close_match));
37443751
}
3745-
Some(def @ Def::Label(_)) => {
3752+
Some(Def::Label(id)) => {
37463753
// Since this def is a label, it is never read.
3747-
self.record_def(expr.id, PathResolution::new(def));
3754+
self.record_def(expr.id, PathResolution::new(Def::Label(id)));
3755+
self.unused_labels.remove(&id);
37483756
}
37493757
Some(_) => {
37503758
span_bug!(expr.span, "label wasn't mapped to a label def!");

src/test/ui/lint/unused_labels.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// The output should warn when a loop label is not used. However, it
12+
// should also deal with the edge cases where a label is shadowed,
13+
// within nested loops
14+
15+
// compile-pass
16+
17+
fn main() {
18+
'unused_while_label: while 0 == 0 {
19+
//~^ WARN unused label
20+
}
21+
22+
let opt = Some(0);
23+
'unused_while_let_label: while let Some(_) = opt {
24+
//~^ WARN unused label
25+
}
26+
27+
'unused_for_label: for _ in 0..10 {
28+
//~^ WARN unused label
29+
}
30+
31+
'used_loop_label: loop {
32+
break 'used_loop_label;
33+
}
34+
35+
'used_loop_label_outer_1: for _ in 0..10 {
36+
'used_loop_label_inner_1: for _ in 0..10 {
37+
break 'used_loop_label_inner_1;
38+
}
39+
break 'used_loop_label_outer_1;
40+
}
41+
42+
'used_loop_label_outer_2: for _ in 0..10 {
43+
'unused_loop_label_inner_2: for _ in 0..10 {
44+
//~^ WARN unused label
45+
break 'used_loop_label_outer_2;
46+
}
47+
}
48+
49+
'unused_loop_label_outer_3: for _ in 0..10 {
50+
//~^ WARN unused label
51+
'used_loop_label_inner_3: for _ in 0..10 {
52+
break 'used_loop_label_inner_3;
53+
}
54+
}
55+
56+
// Test breaking many times with the same inner label doesn't break the
57+
// warning on the outer label
58+
'many_used_shadowed: for _ in 0..10 {
59+
//~^ WARN unused label
60+
'many_used_shadowed: for _ in 0..10 {
61+
//~^ WARN label name `'many_used_shadowed` shadows a label name that is already in scope
62+
if 1 % 2 == 0 {
63+
break 'many_used_shadowed;
64+
} else {
65+
break 'many_used_shadowed;
66+
}
67+
}
68+
}
69+
70+
// This is diverging, so put it at the end so we don't get
71+
// unreachable_code errors everywhere else
72+
'unused_loop_label: loop {
73+
//~^ WARN unused label
74+
}
75+
}

src/test/ui/lint/unused_labels.stderr

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
warning: unused label
2+
--> $DIR/unused_labels.rs:18:5
3+
|
4+
LL | 'unused_while_label: while 0 == 0 {
5+
| ^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: #[warn(unused_labels)] on by default
8+
9+
warning: unused label
10+
--> $DIR/unused_labels.rs:23:5
11+
|
12+
LL | 'unused_while_let_label: while let Some(_) = opt {
13+
| ^^^^^^^^^^^^^^^^^^^^^^^
14+
15+
warning: unused label
16+
--> $DIR/unused_labels.rs:27:5
17+
|
18+
LL | 'unused_for_label: for _ in 0..10 {
19+
| ^^^^^^^^^^^^^^^^^
20+
21+
warning: unused label
22+
--> $DIR/unused_labels.rs:43:9
23+
|
24+
LL | 'unused_loop_label_inner_2: for _ in 0..10 {
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
26+
27+
warning: unused label
28+
--> $DIR/unused_labels.rs:49:5
29+
|
30+
LL | 'unused_loop_label_outer_3: for _ in 0..10 {
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
32+
33+
warning: unused label
34+
--> $DIR/unused_labels.rs:58:5
35+
|
36+
LL | 'many_used_shadowed: for _ in 0..10 {
37+
| ^^^^^^^^^^^^^^^^^^^
38+
39+
warning: unused label
40+
--> $DIR/unused_labels.rs:72:5
41+
|
42+
LL | 'unused_loop_label: loop {
43+
| ^^^^^^^^^^^^^^^^^^
44+
45+
warning: label name `'many_used_shadowed` shadows a label name that is already in scope
46+
--> $DIR/unused_labels.rs:60:9
47+
|
48+
LL | 'many_used_shadowed: for _ in 0..10 {
49+
| ------------------- first declared here
50+
LL | //~^ WARN unused label
51+
LL | 'many_used_shadowed: for _ in 0..10 {
52+
| ^^^^^^^^^^^^^^^^^^^ lifetime 'many_used_shadowed already in scope
53+

src/test/ui/loops-reject-duplicate-labels-2.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
// discussed here:
1919
// https://internals.rust-lang.org/t/psa-rejecting-duplicate-loop-labels/1833
2020

21+
#[allow(unused_labels)]
2122
pub fn foo() {
2223
{ 'fl: for _ in 0..10 { break; } }
2324
{ 'fl: loop { break; } } //~ WARN label name `'fl` shadows a label name that is already in scope

src/test/ui/loops-reject-duplicate-labels-2.stderr

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,69 @@
11
warning: label name `'fl` shadows a label name that is already in scope
2-
--> $DIR/loops-reject-duplicate-labels-2.rs:23:7
2+
--> $DIR/loops-reject-duplicate-labels-2.rs:24:7
33
|
44
LL | { 'fl: for _ in 0..10 { break; } }
55
| --- first declared here
66
LL | { 'fl: loop { break; } } //~ WARN label name `'fl` shadows a label name that is already in scope
77
| ^^^ lifetime 'fl already in scope
88

99
warning: label name `'lf` shadows a label name that is already in scope
10-
--> $DIR/loops-reject-duplicate-labels-2.rs:25:7
10+
--> $DIR/loops-reject-duplicate-labels-2.rs:26:7
1111
|
1212
LL | { 'lf: loop { break; } }
1313
| --- first declared here
1414
LL | { 'lf: for _ in 0..10 { break; } } //~ WARN label name `'lf` shadows a label name that is already in scope
1515
| ^^^ lifetime 'lf already in scope
1616

1717
warning: label name `'wl` shadows a label name that is already in scope
18-
--> $DIR/loops-reject-duplicate-labels-2.rs:27:7
18+
--> $DIR/loops-reject-duplicate-labels-2.rs:28:7
1919
|
2020
LL | { 'wl: while 2 > 1 { break; } }
2121
| --- first declared here
2222
LL | { 'wl: loop { break; } } //~ WARN label name `'wl` shadows a label name that is already in scope
2323
| ^^^ lifetime 'wl already in scope
2424

2525
warning: label name `'lw` shadows a label name that is already in scope
26-
--> $DIR/loops-reject-duplicate-labels-2.rs:29:7
26+
--> $DIR/loops-reject-duplicate-labels-2.rs:30:7
2727
|
2828
LL | { 'lw: loop { break; } }
2929
| --- first declared here
3030
LL | { 'lw: while 2 > 1 { break; } } //~ WARN label name `'lw` shadows a label name that is already in scope
3131
| ^^^ lifetime 'lw already in scope
3232

3333
warning: label name `'fw` shadows a label name that is already in scope
34-
--> $DIR/loops-reject-duplicate-labels-2.rs:31:7
34+
--> $DIR/loops-reject-duplicate-labels-2.rs:32:7
3535
|
3636
LL | { 'fw: for _ in 0..10 { break; } }
3737
| --- first declared here
3838
LL | { 'fw: while 2 > 1 { break; } } //~ WARN label name `'fw` shadows a label name that is already in scope
3939
| ^^^ lifetime 'fw already in scope
4040

4141
warning: label name `'wf` shadows a label name that is already in scope
42-
--> $DIR/loops-reject-duplicate-labels-2.rs:33:7
42+
--> $DIR/loops-reject-duplicate-labels-2.rs:34:7
4343
|
4444
LL | { 'wf: while 2 > 1 { break; } }
4545
| --- first declared here
4646
LL | { 'wf: for _ in 0..10 { break; } } //~ WARN label name `'wf` shadows a label name that is already in scope
4747
| ^^^ lifetime 'wf already in scope
4848

4949
warning: label name `'tl` shadows a label name that is already in scope
50-
--> $DIR/loops-reject-duplicate-labels-2.rs:35:7
50+
--> $DIR/loops-reject-duplicate-labels-2.rs:36:7
5151
|
5252
LL | { 'tl: while let Some(_) = None::<i32> { break; } }
5353
| --- first declared here
5454
LL | { 'tl: loop { break; } } //~ WARN label name `'tl` shadows a label name that is already in scope
5555
| ^^^ lifetime 'tl already in scope
5656

5757
warning: label name `'lt` shadows a label name that is already in scope
58-
--> $DIR/loops-reject-duplicate-labels-2.rs:37:7
58+
--> $DIR/loops-reject-duplicate-labels-2.rs:38:7
5959
|
6060
LL | { 'lt: loop { break; } }
6161
| --- first declared here
6262
LL | { 'lt: while let Some(_) = None::<i32> { break; } }
6363
| ^^^ lifetime 'lt already in scope
6464

6565
error: compilation successful
66-
--> $DIR/loops-reject-duplicate-labels-2.rs:42:1
66+
--> $DIR/loops-reject-duplicate-labels-2.rs:43:1
6767
|
6868
LL | / pub fn main() { //~ ERROR compilation successful
6969
LL | | foo();

src/test/ui/loops-reject-duplicate-labels.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// Issue #21633: reject duplicate loop labels in function bodies.
1616
// This is testing the exact cases that are in the issue description.
1717

18+
#[allow(unused_labels)]
1819
fn foo() {
1920
'fl: for _ in 0..10 { break; }
2021
'fl: loop { break; } //~ WARN label name `'fl` shadows a label name that is already in scope

src/test/ui/loops-reject-duplicate-labels.stderr

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,69 @@
11
warning: label name `'fl` shadows a label name that is already in scope
2-
--> $DIR/loops-reject-duplicate-labels.rs:20:5
2+
--> $DIR/loops-reject-duplicate-labels.rs:21:5
33
|
44
LL | 'fl: for _ in 0..10 { break; }
55
| --- first declared here
66
LL | 'fl: loop { break; } //~ WARN label name `'fl` shadows a label name that is already in scope
77
| ^^^ lifetime 'fl already in scope
88

99
warning: label name `'lf` shadows a label name that is already in scope
10-
--> $DIR/loops-reject-duplicate-labels.rs:23:5
10+
--> $DIR/loops-reject-duplicate-labels.rs:24:5
1111
|
1212
LL | 'lf: loop { break; }
1313
| --- first declared here
1414
LL | 'lf: for _ in 0..10 { break; } //~ WARN label name `'lf` shadows a label name that is already in scope
1515
| ^^^ lifetime 'lf already in scope
1616

1717
warning: label name `'wl` shadows a label name that is already in scope
18-
--> $DIR/loops-reject-duplicate-labels.rs:25:5
18+
--> $DIR/loops-reject-duplicate-labels.rs:26:5
1919
|
2020
LL | 'wl: while 2 > 1 { break; }
2121
| --- first declared here
2222
LL | 'wl: loop { break; } //~ WARN label name `'wl` shadows a label name that is already in scope
2323
| ^^^ lifetime 'wl already in scope
2424

2525
warning: label name `'lw` shadows a label name that is already in scope
26-
--> $DIR/loops-reject-duplicate-labels.rs:27:5
26+
--> $DIR/loops-reject-duplicate-labels.rs:28:5
2727
|
2828
LL | 'lw: loop { break; }
2929
| --- first declared here
3030
LL | 'lw: while 2 > 1 { break; } //~ WARN label name `'lw` shadows a label name that is already in scope
3131
| ^^^ lifetime 'lw already in scope
3232

3333
warning: label name `'fw` shadows a label name that is already in scope
34-
--> $DIR/loops-reject-duplicate-labels.rs:29:5
34+
--> $DIR/loops-reject-duplicate-labels.rs:30:5
3535
|
3636
LL | 'fw: for _ in 0..10 { break; }
3737
| --- first declared here
3838
LL | 'fw: while 2 > 1 { break; } //~ WARN label name `'fw` shadows a label name that is already in scope
3939
| ^^^ lifetime 'fw already in scope
4040

4141
warning: label name `'wf` shadows a label name that is already in scope
42-
--> $DIR/loops-reject-duplicate-labels.rs:31:5
42+
--> $DIR/loops-reject-duplicate-labels.rs:32:5
4343
|
4444
LL | 'wf: while 2 > 1 { break; }
4545
| --- first declared here
4646
LL | 'wf: for _ in 0..10 { break; } //~ WARN label name `'wf` shadows a label name that is already in scope
4747
| ^^^ lifetime 'wf already in scope
4848

4949
warning: label name `'tl` shadows a label name that is already in scope
50-
--> $DIR/loops-reject-duplicate-labels.rs:33:5
50+
--> $DIR/loops-reject-duplicate-labels.rs:34:5
5151
|
5252
LL | 'tl: while let Some(_) = None::<i32> { break; }
5353
| --- first declared here
5454
LL | 'tl: loop { break; } //~ WARN label name `'tl` shadows a label name that is already in scope
5555
| ^^^ lifetime 'tl already in scope
5656

5757
warning: label name `'lt` shadows a label name that is already in scope
58-
--> $DIR/loops-reject-duplicate-labels.rs:35:5
58+
--> $DIR/loops-reject-duplicate-labels.rs:36:5
5959
|
6060
LL | 'lt: loop { break; }
6161
| --- first declared here
6262
LL | 'lt: while let Some(_) = None::<i32> { break; }
6363
| ^^^ lifetime 'lt already in scope
6464

6565
error: compilation successful
66-
--> $DIR/loops-reject-duplicate-labels.rs:49:1
66+
--> $DIR/loops-reject-duplicate-labels.rs:50:1
6767
|
6868
LL | / pub fn main() { //~ ERROR compilation successful
6969
LL | | let s = S;

src/test/ui/suggestions/suggest-labels.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#[allow(unreachable_code)]
11+
#[allow(unreachable_code, unused_labels)]
1212
fn main() {
1313
'foo: loop {
1414
break 'fo; //~ ERROR use of undeclared label

0 commit comments

Comments
 (0)