Skip to content

Commit c657cf4

Browse files
committed
Check for duplicate loop labels in function bodies.
1 parent b41f2df commit c657cf4

File tree

3 files changed

+79
-1
lines changed

3 files changed

+79
-1
lines changed

src/librustc_typeck/check/labels.rs

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2015 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+
//! labels.rs
12+
//!
13+
//! Issue #21633: Check for duplicate loop-labels anywhere in a
14+
//! function body.
15+
16+
17+
use CrateCtxt;
18+
19+
use syntax::ast;
20+
use syntax::codemap::Span;
21+
use syntax::visit::{self, Visitor};
22+
23+
use std::mem::replace;
24+
25+
pub struct CheckLoopLabelsVisitor<'a, 'tcx: 'a> {
26+
ccx: &'a CrateCtxt<'a, 'tcx>,
27+
labels_in_fn: Vec<(ast::Ident, Span)>,
28+
}
29+
30+
impl<'a, 'tcx:'a> CheckLoopLabelsVisitor<'a, 'tcx> {
31+
pub fn new(ccx: &'a CrateCtxt<'a, 'tcx>) -> CheckLoopLabelsVisitor<'a, 'tcx> {
32+
CheckLoopLabelsVisitor { ccx: ccx, labels_in_fn: vec![] }
33+
}
34+
}
35+
36+
impl<'a, 'tcx> Visitor<'tcx> for CheckLoopLabelsVisitor<'a, 'tcx> {
37+
fn visit_fn(&mut self, fk: visit::FnKind<'tcx>, fd: &'tcx ast::FnDecl,
38+
b: &'tcx ast::Block, s: Span, _: ast::NodeId)
39+
{
40+
let saved = replace(&mut self.labels_in_fn, vec![]);
41+
visit::walk_fn(self, fk, fd, b, s);
42+
replace(&mut self.labels_in_fn, saved);
43+
}
44+
45+
fn visit_expr(&mut self, ex: &'tcx ast::Expr) {
46+
let opt_label = match ex.node {
47+
ast::ExprWhile(_, _, label) |
48+
ast::ExprWhileLet(_, _, _, label) |
49+
ast::ExprForLoop(_, _, _, label) |
50+
ast::ExprLoop(_, label) => label,
51+
_ => None,
52+
};
53+
let tcx = self.ccx.tcx;
54+
if let Some(curr_id) = opt_label {
55+
// Note: non-hygienic comparision here may reject code
56+
// that should actually be accepted.
57+
if let Some(&(_, span)) = self.labels_in_fn.iter()
58+
.find(|id_span| curr_id.name == id_span.0.name )
59+
{
60+
span_err!(tcx.sess, ex.span, E0373,
61+
"duplicate loop label {} in function",
62+
curr_id);
63+
span_note!(tcx.sess, span, "first label occurrence here");
64+
} else {
65+
self.labels_in_fn.push((curr_id, ex.span));
66+
}
67+
}
68+
69+
visit::walk_expr(self, ex)
70+
}
71+
}

src/librustc_typeck/check/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ mod closure;
143143
mod callee;
144144
mod compare_method;
145145
mod op;
146+
mod labels;
146147

147148
/// closures defined within the function. For example:
148149
///
@@ -482,6 +483,11 @@ pub fn check_item_types(ccx: &CrateCtxt) {
482483

483484
ccx.tcx.sess.abort_if_errors();
484485

486+
let mut visit = labels::CheckLoopLabelsVisitor::new(ccx);
487+
visit::walk_crate(&mut visit, krate);
488+
489+
ccx.tcx.sess.abort_if_errors();
490+
485491
for drop_method_did in ccx.tcx.destructors.borrow().iter() {
486492
if drop_method_did.krate == ast::LOCAL_CRATE {
487493
let drop_impl_did = ccx.tcx.map.get_parent_did(drop_method_did.node);

src/librustc_typeck/diagnostics.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ register_diagnostics! {
181181
E0368, // binary operation `<op>=` cannot be applied to types
182182
E0369, // binary operation `<op>` cannot be applied to types
183183
E0371, // impl Trait for Trait is illegal
184-
E0372 // impl Trait for Trait where Trait is not object safe
184+
E0372, // impl Trait for Trait where Trait is not object safe
185+
E0373 // duplicate loop label in single block
185186
}
186187

187188
__build_diagnostic_array! { DIAGNOSTICS }

0 commit comments

Comments
 (0)