Skip to content

Commit 3dcb288

Browse files
committed
Auto merge of #38806 - comex:lint-attr-fix, r=nrc
Fix lint attributes on non-item nodes. Currently, late lint checking uses two HIR visitors: LateContext and IdVisitor. IdVisitor only overrides visit_id, and for each node searches for builtin lints previously added to the session; LateContext overrides a number of methods, and runs late lints. When LateContext encounters an item, it first has IdVisitor walk everything in it except nested items (OnlyBodies), then recurses into it itself - i.e. there are two separate walks. Aside from apparently being unnecessary, this separation prevents lint attributes (allow/deny/warn) on non-item HIR nodes from working properly. Test case: ```rust // generates warning without this change fn main() { #[allow(unreachable_code)] loop { break; break; } } ``` LateContext contains logic to merge attributes seen into the current lint settings while walking (with_lint_attrs), but IdVisitor does not. So such attributes will affect late lints (because they are called from LateContext), and if the node contains any items within it, they will affect builtin lints within those items (because that IdVisitor is run while LateContext is within the attributed node), but otherwise the attributes will be ignored for builtin lints. This change simply removes IdVisitor and moves its visit_id into LateContext itself. Hopefully this doesn't break anything... Also added walk calls to visit_lifetime and visit_lifetime_def respectively, so visit_lifetime_def will recurse into the lifetime and visit_lifetime will recurse into the name. In principle this could confuse lint plugins. This is "necessary" because walk_lifetime calls visit_id on the lifetime; of course, an alternative would be directly calling visit_id (which would require manually iterating over the lifetimes in visit_lifetime_def), but that seems less clean.
2 parents ff591b6 + 9cfb8b7 commit 3dcb288

File tree

3 files changed

+43
-59
lines changed

3 files changed

+43
-59
lines changed

src/librustc/lint/context.rs

+12-47
Original file line numberDiff line numberDiff line change
@@ -705,17 +705,6 @@ impl<'a> EarlyContext<'a> {
705705
}
706706
}
707707

708-
impl<'a, 'tcx> LateContext<'a, 'tcx> {
709-
fn visit_ids<'b, F: 'b>(&'b mut self, f: F)
710-
where F: FnOnce(&mut IdVisitor<'b, 'a, 'tcx>)
711-
{
712-
let mut v = IdVisitor::<'b, 'a, 'tcx> {
713-
cx: self
714-
};
715-
f(&mut v);
716-
}
717-
}
718-
719708
impl<'a, 'tcx> LintContext<'tcx> for LateContext<'a, 'tcx> {
720709
/// Get the overall compiler `Session` object.
721710
fn sess(&self) -> &Session {
@@ -782,6 +771,16 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
782771
hir_visit::NestedVisitorMap::All(&self.tcx.map)
783772
}
784773

774+
// Output any lints that were previously added to the session.
775+
fn visit_id(&mut self, id: ast::NodeId) {
776+
if let Some(lints) = self.sess().lints.borrow_mut().remove(&id) {
777+
debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);
778+
for early_lint in lints {
779+
self.early_lint(early_lint);
780+
}
781+
}
782+
}
783+
785784
fn visit_nested_body(&mut self, body: hir::BodyId) {
786785
let old_tables = self.tables;
787786
self.tables = self.tcx.body_tables(body);
@@ -793,7 +792,6 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
793792
fn visit_item(&mut self, it: &'tcx hir::Item) {
794793
self.with_lint_attrs(&it.attrs, |cx| {
795794
run_lints!(cx, check_item, late_passes, it);
796-
cx.visit_ids(|v| v.visit_item(it));
797795
hir_visit::walk_item(cx, it);
798796
run_lints!(cx, check_item_post, late_passes, it);
799797
})
@@ -918,7 +916,6 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
918916
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
919917
self.with_lint_attrs(&trait_item.attrs, |cx| {
920918
run_lints!(cx, check_trait_item, late_passes, trait_item);
921-
cx.visit_ids(|v| hir_visit::walk_trait_item(v, trait_item));
922919
hir_visit::walk_trait_item(cx, trait_item);
923920
run_lints!(cx, check_trait_item_post, late_passes, trait_item);
924921
});
@@ -927,18 +924,19 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
927924
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
928925
self.with_lint_attrs(&impl_item.attrs, |cx| {
929926
run_lints!(cx, check_impl_item, late_passes, impl_item);
930-
cx.visit_ids(|v| hir_visit::walk_impl_item(v, impl_item));
931927
hir_visit::walk_impl_item(cx, impl_item);
932928
run_lints!(cx, check_impl_item_post, late_passes, impl_item);
933929
});
934930
}
935931

936932
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
937933
run_lints!(self, check_lifetime, late_passes, lt);
934+
hir_visit::walk_lifetime(self, lt);
938935
}
939936

940937
fn visit_lifetime_def(&mut self, lt: &'tcx hir::LifetimeDef) {
941938
run_lints!(self, check_lifetime_def, late_passes, lt);
939+
hir_visit::walk_lifetime_def(self, lt);
942940
}
943941

944942
fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) {
@@ -1100,35 +1098,6 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
11001098
}
11011099
}
11021100

1103-
struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> {
1104-
cx: &'a mut LateContext<'b, 'tcx>
1105-
}
1106-
1107-
// Output any lints that were previously added to the session.
1108-
impl<'a, 'b, 'tcx> hir_visit::Visitor<'tcx> for IdVisitor<'a, 'b, 'tcx> {
1109-
fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> {
1110-
hir_visit::NestedVisitorMap::OnlyBodies(&self.cx.tcx.map)
1111-
}
1112-
1113-
fn visit_id(&mut self, id: ast::NodeId) {
1114-
if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) {
1115-
debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);
1116-
for early_lint in lints {
1117-
self.cx.early_lint(early_lint);
1118-
}
1119-
}
1120-
}
1121-
1122-
fn visit_trait_item(&mut self, _ti: &'tcx hir::TraitItem) {
1123-
// Do not recurse into trait or impl items automatically. These are
1124-
// processed separately by calling hir_visit::walk_trait_item()
1125-
}
1126-
1127-
fn visit_impl_item(&mut self, _ii: &'tcx hir::ImplItem) {
1128-
// See visit_trait_item()
1129-
}
1130-
}
1131-
11321101
enum CheckLintNameResult {
11331102
Ok,
11341103
// Lint doesn't exist
@@ -1252,10 +1221,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
12521221

12531222
// Visit the whole crate.
12541223
cx.with_lint_attrs(&krate.attrs, |cx| {
1255-
cx.visit_ids(|v| {
1256-
hir_visit::walk_crate(v, krate);
1257-
});
1258-
12591224
// since the root module isn't visited as an item (because it isn't an
12601225
// item), warn for it here.
12611226
run_lints!(cx, check_crate, late_passes, krate);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2016 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+
// Checks that lint attributes work on non-item AST nodes
12+
13+
fn main() {
14+
#[deny(unreachable_code)]
15+
loop {
16+
break;
17+
"unreachable"; //~ ERROR unreachable statement
18+
}
19+
}

src/test/ui/span/issue-24690.stderr

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,3 @@
1-
error: unused variable: `theOtherTwo`
2-
--> $DIR/issue-24690.rs:20:9
3-
|
4-
20 | let theOtherTwo = 2;
5-
| ^^^^^^^^^^^
6-
|
7-
note: lint level defined here
8-
--> $DIR/issue-24690.rs:16:9
9-
|
10-
16 | #![deny(warnings)]
11-
| ^^^^^^^^
12-
131
error: variable `theTwo` should have a snake case name such as `the_two`
142
--> $DIR/issue-24690.rs:19:9
153
|
@@ -28,5 +16,17 @@ error: variable `theOtherTwo` should have a snake case name such as `the_other_t
2816
20 | let theOtherTwo = 2;
2917
| ^^^^^^^^^^^
3018

19+
error: unused variable: `theOtherTwo`
20+
--> $DIR/issue-24690.rs:20:9
21+
|
22+
20 | let theOtherTwo = 2;
23+
| ^^^^^^^^^^^
24+
|
25+
note: lint level defined here
26+
--> $DIR/issue-24690.rs:16:9
27+
|
28+
16 | #![deny(warnings)]
29+
| ^^^^^^^^
30+
3131
error: aborting due to 3 previous errors
3232

0 commit comments

Comments
 (0)