Skip to content

Commit 6c7cb2b

Browse files
committed
Honor lint level attributes in more places.
This extends the LintLevelBuilder to handle lint level attributes on struct expression fields and pattern fields. This also updates the early lints to honor lint levels on generic parameters.
1 parent b651c1c commit 6c7cb2b

File tree

6 files changed

+1312
-6
lines changed

6 files changed

+1312
-6
lines changed

compiler/rustc_lint/src/early.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,10 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
219219
}
220220

221221
fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
222-
run_early_pass!(self, check_generic_param, param);
223-
self.check_id(param.id);
224-
ast_visit::walk_generic_param(self, param);
222+
self.with_lint_attrs(param.id, &param.attrs, |cx| {
223+
run_early_pass!(cx, check_generic_param, param);
224+
ast_visit::walk_generic_param(cx, param);
225+
});
225226
}
226227

227228
fn visit_generics(&mut self, g: &'a ast::Generics) {

compiler/rustc_lint/src/levels.rs

+42-3
Original file line numberDiff line numberDiff line change
@@ -761,9 +761,26 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
761761
}
762762

763763
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
764-
self.with_lint_attrs(e.hir_id, |builder| {
765-
intravisit::walk_expr(builder, e);
766-
})
764+
match e.kind {
765+
hir::ExprKind::Struct(qpath, fields, base_expr) => {
766+
self.with_lint_attrs(e.hir_id, |builder| {
767+
builder.visit_qpath(qpath, e.hir_id, e.span);
768+
for field in fields {
769+
builder.with_lint_attrs(field.hir_id, |field_builder| {
770+
field_builder.visit_id(field.hir_id);
771+
field_builder.visit_ident(field.ident);
772+
field_builder.visit_expr(field.expr);
773+
});
774+
}
775+
if let Some(base_expr) = base_expr {
776+
builder.visit_expr(base_expr);
777+
}
778+
});
779+
}
780+
_ => self.with_lint_attrs(e.hir_id, |builder| {
781+
intravisit::walk_expr(builder, e);
782+
}),
783+
}
767784
}
768785

769786
fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
@@ -801,6 +818,28 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
801818
intravisit::walk_impl_item(builder, impl_item);
802819
});
803820
}
821+
822+
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
823+
match &p.kind {
824+
hir::PatKind::Struct(qpath, fields, _) => {
825+
self.visit_qpath(&qpath, p.hir_id, p.span);
826+
for field in *fields {
827+
self.with_lint_attrs(field.hir_id, |builder| {
828+
builder.visit_id(field.hir_id);
829+
builder.visit_ident(field.ident);
830+
builder.visit_pat(field.pat);
831+
})
832+
}
833+
}
834+
_ => intravisit::walk_pat(self, p),
835+
}
836+
}
837+
838+
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
839+
self.with_lint_attrs(p.hir_id, |builder| {
840+
intravisit::walk_generic_param(builder, p);
841+
});
842+
}
804843
}
805844

806845
pub fn provide(providers: &mut Providers) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
// Tests that lint levels can be set for early lints.
2+
#![allow(non_camel_case_types, unsafe_code, while_true, unused_parens)]
3+
4+
// The following is a check of the lints used here to verify they do not warn
5+
// when allowed.
6+
fn verify_no_warnings() {
7+
type non_camel_type = i32; // non_camel_case_types
8+
struct NON_CAMEL_IS_ALLOWED; // non_camel_case_types
9+
unsafe {} // unsafe_code
10+
enum Enum {
11+
VARIANT_CAMEL // non_camel_case_types
12+
}
13+
fn generics<foo>() {} // non_camel_case_types
14+
while true {} // while_true
15+
type T = (i32); // unused_parens
16+
}
17+
18+
19+
// ################## Types
20+
21+
#[deny(non_camel_case_types)]
22+
type type_outer = i32; //~ ERROR type `type_outer` should have an upper camel case name
23+
24+
type BareFnPtr = fn(#[deny(unused_parens)](i32)); //~ ERROR unnecessary parentheses around type
25+
// There aren't any early lints that currently apply to the variadic spot.
26+
// type BareFnPtrVariadic = extern "C" fn(i32, #[deny()]...);
27+
28+
// ################## Items
29+
#[deny(non_camel_case_types)]
30+
struct ITEM_OUTER; //~ ERROR type `ITEM_OUTER` should have an upper camel case name
31+
32+
mod module_inner {
33+
#![deny(unsafe_code)]
34+
fn f() {
35+
unsafe {} //~ ERROR usage of an `unsafe` block
36+
}
37+
}
38+
39+
struct Associated;
40+
impl Associated {
41+
#![deny(unsafe_code)]
42+
43+
fn inherent_denied_from_inner() { unsafe {} } //~ usage of an `unsafe` block
44+
45+
#[deny(while_true)]
46+
fn inherent_fn() { while true {} } //~ ERROR denote infinite loops with
47+
48+
#[deny(while_true)]
49+
const INHERENT_CONST: i32 = {while true {} 1}; //~ ERROR denote infinite loops with
50+
}
51+
52+
trait trait_inner { //~ ERROR trait `trait_inner` should have an upper camel case name
53+
#![deny(non_camel_case_types)]
54+
}
55+
56+
trait AssociatedTrait {
57+
#![deny(unsafe_code)]
58+
59+
fn denied_from_inner() { unsafe {} } //~ ERROR usage of an `unsafe` block
60+
61+
#[deny(while_true)]
62+
fn assoc_fn() { while true {} } //~ ERROR denote infinite loops with
63+
64+
#[deny(while_true)]
65+
const ASSOC_CONST: i32 = {while true {} 1}; //~ ERROR denote infinite loops with
66+
67+
#[deny(non_camel_case_types)]
68+
type assoc_type; //~ ERROR associated type `assoc_type` should have an upper camel case name
69+
}
70+
71+
impl AssociatedTrait for Associated {
72+
#![deny(unsafe_code)]
73+
74+
fn denied_from_inner() { unsafe {} } //~ ERROR usage of an `unsafe` block
75+
76+
#[deny(while_true)]
77+
fn assoc_fn() { while true {} } //~ ERROR denote infinite loops with
78+
79+
#[deny(while_true)]
80+
const ASSOC_CONST: i32 = {while true {} 1}; //~ ERROR denote infinite loops with
81+
82+
#[deny(unused_parens)]
83+
type assoc_type = (i32); //~ ERROR unnecessary parentheses around type
84+
}
85+
86+
struct StructFields {
87+
#[deny(unused_parens)]f1: (i32), //~ ERROR unnecessary parentheses around type
88+
}
89+
struct StructTuple(#[deny(unused_parens)](i32)); //~ ERROR unnecessary parentheses around type
90+
91+
enum Enum {
92+
#[deny(non_camel_case_types)]
93+
VARIANT_CAMEL, //~ ERROR variant `VARIANT_CAMEL` should have an upper camel case name
94+
}
95+
96+
extern "C" {
97+
#![deny(unused_parens)]
98+
99+
fn foreign_denied_from_inner(x: (i32)); //~ ERROR unnecessary parentheses around type
100+
}
101+
102+
extern "C" {
103+
#[deny(unused_parens)]
104+
fn foreign_denied_from_outer(x: (i32)); //~ ERROR unnecessary parentheses around type
105+
}
106+
107+
fn function(#[deny(unused_parens)] param: (i32)) {} //~ ERROR unnecessary parentheses around type
108+
109+
fn generics<#[deny(non_camel_case_types)]foo>() {} //~ ERROR type parameter `foo` should have an upper camel case name
110+
111+
112+
// ################## Statements
113+
fn statements() {
114+
#[deny(unused_parens)]
115+
let x = (1); //~ ERROR unnecessary parentheses around assigned value
116+
}
117+
118+
119+
// ################## Expressions
120+
fn expressions() {
121+
let closure = |#[deny(unused_parens)] param: (i32)| {}; //~ ERROR unnecessary parentheses around type
122+
123+
struct Match{f1: i32}
124+
// Strangely unused_parens doesn't fire with {f1: (123)}
125+
let f = Match{#[deny(unused_parens)]f1: {(123)}}; //~ ERROR unnecessary parentheses around block return value
126+
127+
match f {
128+
#![deny(unsafe_code)]
129+
130+
#[deny(while_true)]
131+
Match{f1} => {
132+
unsafe {} //~ ERROR usage of an `unsafe` block
133+
while true {} //~ ERROR denote infinite loops with
134+
}
135+
}
136+
137+
// Statement Block
138+
{
139+
#![deny(unsafe_code)]
140+
unsafe {} //~ ERROR usage of an `unsafe` block
141+
}
142+
let block_tail = {
143+
#[deny(unsafe_code)]
144+
unsafe {} //~ ERROR usage of an `unsafe` block
145+
};
146+
147+
// Before expression as a statement.
148+
#[deny(unsafe_code)]
149+
unsafe {}; //~ ERROR usage of an `unsafe` block
150+
151+
[#[deny(unsafe_code)] unsafe {123}]; //~ ERROR usage of an `unsafe` block
152+
(#[deny(unsafe_code)] unsafe {123},); //~ ERROR usage of an `unsafe` block
153+
fn call(p: i32) {}
154+
call(#[deny(unsafe_code)] unsafe {123}); //~ ERROR usage of an `unsafe` block
155+
struct TupleStruct(i32);
156+
TupleStruct(#[deny(unsafe_code)] unsafe {123}); //~ ERROR usage of an `unsafe` block
157+
}
158+
159+
160+
// ################## Patterns
161+
fn patterns() {
162+
// There aren't any early lints that I can find that apply to pattern fields.
163+
//
164+
// struct PatField{f1: i32, f2: i32};
165+
// let f = PatField{f1: 1, f2: 2};
166+
// let PatField{#[deny()]f1, #[deny()]..} = f;
167+
}
168+
169+
fn main() {}

0 commit comments

Comments
 (0)