Skip to content

Commit 83ed227

Browse files
authored
Rollup merge of #94580 - xFrednet:55112-only-reason-in-lint-attr, r=lcnr
Emit `unused_attributes` if a level attr only has a reason Fixes a comment from `compiler/rustc_lint/src/levels.rs`. Lint level attributes that only contain a reason will also trigger the `unused_attribute` lint. The lint now also checks for the `expect` lint level. That's it, have a great rest of the day for everyone reasoning this 🙃 cc: #55112
2 parents aec535f + 700ec66 commit 83ed227

File tree

6 files changed

+133
-41
lines changed

6 files changed

+133
-41
lines changed

compiler/rustc_lint/src/levels.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ impl<'s> LintLevelsBuilder<'s> {
258258
};
259259

260260
if metas.is_empty() {
261-
// FIXME (#55112): issue unused-attributes lint for `#[level()]`
261+
// This emits the unused_attributes lint for `#[level()]`
262262
continue;
263263
}
264264

@@ -271,8 +271,6 @@ impl<'s> LintLevelsBuilder<'s> {
271271
ast::MetaItemKind::Word => {} // actual lint names handled later
272272
ast::MetaItemKind::NameValue(ref name_value) => {
273273
if item.path == sym::reason {
274-
// FIXME (#55112): issue unused-attributes lint if we thereby
275-
// don't have any lint names (`#[level(reason = "foo")]`)
276274
if let ast::LitKind::Str(rationale, _) = name_value.kind {
277275
if !self.sess.features_untracked().lint_reasons {
278276
feature_err(

compiler/rustc_passes/src/check_attr.rs

+51-29
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//! conflicts between multiple such attributes attached to the same
55
//! item.
66
7-
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
7+
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
88
use rustc_data_structures::fx::FxHashMap;
99
use rustc_errors::{pluralize, struct_span_err, Applicability};
1010
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@@ -178,34 +178,7 @@ impl CheckAttrVisitor<'_> {
178178
check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
179179
}
180180

181-
// Warn on useless empty attributes.
182-
if matches!(
183-
attr.name_or_empty(),
184-
sym::macro_use
185-
| sym::allow
186-
| sym::warn
187-
| sym::deny
188-
| sym::forbid
189-
| sym::feature
190-
| sym::repr
191-
| sym::target_feature
192-
) && attr.meta_item_list().map_or(false, |list| list.is_empty())
193-
{
194-
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
195-
lint.build("unused attribute")
196-
.span_suggestion(
197-
attr.span,
198-
"remove this attribute",
199-
String::new(),
200-
Applicability::MachineApplicable,
201-
)
202-
.note(&format!(
203-
"attribute `{}` with an empty list has no effect",
204-
attr.name_or_empty()
205-
))
206-
.emit();
207-
});
208-
}
181+
self.check_unused_attribute(hir_id, attr)
209182
}
210183

211184
if !is_valid {
@@ -1969,6 +1942,55 @@ impl CheckAttrVisitor<'_> {
19691942
});
19701943
}
19711944
}
1945+
1946+
fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
1947+
// Warn on useless empty attributes.
1948+
let note = if matches!(
1949+
attr.name_or_empty(),
1950+
sym::macro_use
1951+
| sym::allow
1952+
| sym::expect
1953+
| sym::warn
1954+
| sym::deny
1955+
| sym::forbid
1956+
| sym::feature
1957+
| sym::repr
1958+
| sym::target_feature
1959+
) && attr.meta_item_list().map_or(false, |list| list.is_empty())
1960+
{
1961+
format!(
1962+
"attribute `{}` with an empty list has no effect",
1963+
attr.name_or_empty()
1964+
)
1965+
} else if matches!(
1966+
attr.name_or_empty(),
1967+
sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
1968+
) && let Some(meta) = attr.meta_item_list()
1969+
&& meta.len() == 1
1970+
&& let Some(item) = meta[0].meta_item()
1971+
&& let MetaItemKind::NameValue(_) = &item.kind
1972+
&& item.path == sym::reason
1973+
{
1974+
format!(
1975+
"attribute `{}` without any lints has no effect",
1976+
attr.name_or_empty()
1977+
)
1978+
} else {
1979+
return;
1980+
};
1981+
1982+
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
1983+
lint.build("unused attribute")
1984+
.span_suggestion(
1985+
attr.span,
1986+
"remove this attribute",
1987+
String::new(),
1988+
Applicability::MachineApplicable,
1989+
)
1990+
.note(&note)
1991+
.emit();
1992+
});
1993+
}
19721994
}
19731995

19741996
impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {

src/test/ui/empty/empty-attributes.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
#![feature(lint_reasons)]
2+
13
#![deny(unused_attributes)]
24
#![allow()] //~ ERROR unused attribute
5+
#![expect()] //~ ERROR unused attribute
36
#![warn()] //~ ERROR unused attribute
47
#![deny()] //~ ERROR unused attribute
58
#![forbid()] //~ ERROR unused attribute
+17-9
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,71 @@
11
error: unused attribute
2-
--> $DIR/empty-attributes.rs:8:1
2+
--> $DIR/empty-attributes.rs:11:1
33
|
44
LL | #[repr()]
55
| ^^^^^^^^^ help: remove this attribute
66
|
77
note: the lint level is defined here
8-
--> $DIR/empty-attributes.rs:1:9
8+
--> $DIR/empty-attributes.rs:3:9
99
|
1010
LL | #![deny(unused_attributes)]
1111
| ^^^^^^^^^^^^^^^^^
1212
= note: attribute `repr` with an empty list has no effect
1313

1414
error: unused attribute
15-
--> $DIR/empty-attributes.rs:11:1
15+
--> $DIR/empty-attributes.rs:14:1
1616
|
1717
LL | #[target_feature()]
1818
| ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
1919
|
2020
= note: attribute `target_feature` with an empty list has no effect
2121

2222
error: unused attribute
23-
--> $DIR/empty-attributes.rs:2:1
23+
--> $DIR/empty-attributes.rs:4:1
2424
|
2525
LL | #![allow()]
2626
| ^^^^^^^^^^^ help: remove this attribute
2727
|
2828
= note: attribute `allow` with an empty list has no effect
2929

3030
error: unused attribute
31-
--> $DIR/empty-attributes.rs:3:1
31+
--> $DIR/empty-attributes.rs:5:1
32+
|
33+
LL | #![expect()]
34+
| ^^^^^^^^^^^^ help: remove this attribute
35+
|
36+
= note: attribute `expect` with an empty list has no effect
37+
38+
error: unused attribute
39+
--> $DIR/empty-attributes.rs:6:1
3240
|
3341
LL | #![warn()]
3442
| ^^^^^^^^^^ help: remove this attribute
3543
|
3644
= note: attribute `warn` with an empty list has no effect
3745

3846
error: unused attribute
39-
--> $DIR/empty-attributes.rs:4:1
47+
--> $DIR/empty-attributes.rs:7:1
4048
|
4149
LL | #![deny()]
4250
| ^^^^^^^^^^ help: remove this attribute
4351
|
4452
= note: attribute `deny` with an empty list has no effect
4553

4654
error: unused attribute
47-
--> $DIR/empty-attributes.rs:5:1
55+
--> $DIR/empty-attributes.rs:8:1
4856
|
4957
LL | #![forbid()]
5058
| ^^^^^^^^^^^^ help: remove this attribute
5159
|
5260
= note: attribute `forbid` with an empty list has no effect
5361

5462
error: unused attribute
55-
--> $DIR/empty-attributes.rs:6:1
63+
--> $DIR/empty-attributes.rs:9:1
5664
|
5765
LL | #![feature()]
5866
| ^^^^^^^^^^^^^ help: remove this attribute
5967
|
6068
= note: attribute `feature` with an empty list has no effect
6169

62-
error: aborting due to 7 previous errors
70+
error: aborting due to 8 previous errors
6371

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(lint_reasons)]
2+
3+
#![deny(unused_attributes)]
4+
5+
#[allow(reason = "I want to allow something")]//~ ERROR unused attribute
6+
#[expect(reason = "I don't know what I'm waiting for")]//~ ERROR unused attribute
7+
#[warn(reason = "This should be warn by default")]//~ ERROR unused attribute
8+
#[deny(reason = "All listed lints are denied")]//~ ERROR unused attribute
9+
#[forbid(reason = "Just some reason")]//~ ERROR unused attribute
10+
11+
#[allow(clippy::box_collection, reason = "This is still valid")]
12+
#[warn(dead_code, reason = "This is also reasonable")]
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error: unused attribute
2+
--> $DIR/lint-attribute-only-with-reason.rs:5:1
3+
|
4+
LL | #[allow(reason = "I want to allow something")]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/lint-attribute-only-with-reason.rs:3:9
9+
|
10+
LL | #![deny(unused_attributes)]
11+
| ^^^^^^^^^^^^^^^^^
12+
= note: attribute `allow` without any lints has no effect
13+
14+
error: unused attribute
15+
--> $DIR/lint-attribute-only-with-reason.rs:6:1
16+
|
17+
LL | #[expect(reason = "I don't know what I'm waiting for")]
18+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
19+
|
20+
= note: attribute `expect` without any lints has no effect
21+
22+
error: unused attribute
23+
--> $DIR/lint-attribute-only-with-reason.rs:7:1
24+
|
25+
LL | #[warn(reason = "This should be warn by default")]
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
27+
|
28+
= note: attribute `warn` without any lints has no effect
29+
30+
error: unused attribute
31+
--> $DIR/lint-attribute-only-with-reason.rs:8:1
32+
|
33+
LL | #[deny(reason = "All listed lints are denied")]
34+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
35+
|
36+
= note: attribute `deny` without any lints has no effect
37+
38+
error: unused attribute
39+
--> $DIR/lint-attribute-only-with-reason.rs:9:1
40+
|
41+
LL | #[forbid(reason = "Just some reason")]
42+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
43+
|
44+
= note: attribute `forbid` without any lints has no effect
45+
46+
error: aborting due to 5 previous errors
47+

0 commit comments

Comments
 (0)