Skip to content
/ rust Public
forked from rust-lang/rust

Commit cdb923d

Browse files
authored
Rollup merge of rust-lang#155572 - mejrs:move_target_checks, r=JonathanBrouwer,GuillaumeGomez
Move diagnostic attribute target checks from check_attr Move diagnostic attribute target checks into their targets. Part of rust-lang#131229 (comment) This is much easier with `emit_dyn_lint` :) (thanks @GuillaumeGomez !) I think there might be some opportunity to simplify all these `check_diagnostic_*` methods in `check_attr`. However there are some diagnostic attribute prs in flight and I'd like to wait for those to land first and then think about it. So that PR is not for today. r? @JonathanBrouwer (or @GuillaumeGomez if you want)
2 parents 5a97343 + 3990dda commit cdb923d

15 files changed

Lines changed: 238 additions & 172 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
1+
use rustc_errors::Diagnostic;
12
use rustc_feature::{AttributeTemplate, template};
3+
use rustc_hir::Target;
24
use rustc_hir::attrs::AttributeKind;
35
use rustc_hir::lints::AttributeLintKind;
4-
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
6+
use rustc_session::lint::builtin::{
7+
MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES,
8+
};
59
use rustc_span::{Symbol, sym};
610

711
use crate::attributes::{OnDuplicate, SingleAttributeParser};
812
use crate::context::{AcceptContext, Stage};
13+
use crate::errors::IncorrectDoNotRecommendLocation;
914
use crate::parser::ArgParser;
1015
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
1116

1217
pub(crate) struct DoNotRecommendParser;
1318
impl<S: Stage> SingleAttributeParser<S> for DoNotRecommendParser {
1419
const PATH: &[Symbol] = &[sym::diagnostic, sym::do_not_recommend];
1520
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
16-
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Checked in check_attr.
21+
// "Allowed" on any target, noop on all but trait impls
22+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
1723
const TEMPLATE: AttributeTemplate = template!(Word /*doesn't matter */);
1824

1925
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
@@ -25,6 +31,19 @@ impl<S: Stage> SingleAttributeParser<S> for DoNotRecommendParser {
2531
attr_span,
2632
);
2733
}
34+
35+
if !matches!(cx.target, Target::Impl { of_trait: true }) {
36+
let target_span = cx.target_span;
37+
cx.emit_dyn_lint(
38+
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
39+
move |dcx, level| {
40+
IncorrectDoNotRecommendLocation { target_span }.into_diag(dcx, level)
41+
},
42+
attr_span,
43+
);
44+
return None;
45+
}
46+
2847
Some(AttributeKind::DoNotRecommend { attr_span })
2948
}
3049
}

compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use rustc_errors::Diagnostic;
12
use rustc_hir::attrs::diagnostic::Directive;
3+
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
24

35
use crate::attributes::diagnostic::*;
46
use crate::attributes::prelude::*;
5-
7+
use crate::errors::DiagnosticOnConstOnlyForTraitImpls;
68
#[derive(Default)]
79
pub(crate) struct OnConstParser {
810
span: Option<Span>,
@@ -21,6 +23,21 @@ impl<S: Stage> AttributeParser<S> for OnConstParser {
2123

2224
let span = cx.attr_span;
2325
this.span = Some(span);
26+
27+
// FIXME(mejrs) no constness field on `Target`,
28+
// so non-constness is still checked in check_attr.rs
29+
if !matches!(cx.target, Target::Impl { of_trait: true }) {
30+
let target_span = cx.target_span;
31+
cx.emit_dyn_lint(
32+
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
33+
move |dcx, level| {
34+
DiagnosticOnConstOnlyForTraitImpls { target_span }.into_diag(dcx, level)
35+
},
36+
span,
37+
);
38+
return;
39+
}
40+
2441
let mode = Mode::DiagnosticOnConst;
2542

2643
let Some(items) = parse_list(cx, args, mode) else { return };
@@ -32,7 +49,8 @@ impl<S: Stage> AttributeParser<S> for OnConstParser {
3249
},
3350
)];
3451

35-
//FIXME Still checked in `check_attr.rs`
52+
// "Allowed" on all targets; noop on anything but non-const trait impls;
53+
// this linted on in parser.
3654
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
3755

3856
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {

compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
use rustc_errors::Diagnostic;
12
use rustc_feature::template;
23
use rustc_hir::attrs::AttributeKind;
4+
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
35
use rustc_span::sym;
46

57
use crate::attributes::diagnostic::*;
68
use crate::attributes::prelude::*;
79
use crate::context::{AcceptContext, Stage};
10+
use crate::errors::DiagnosticOnMoveOnlyForAdt;
811
use crate::parser::ArgParser;
912
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
1013

@@ -29,6 +32,15 @@ impl OnMoveParser {
2932
let span = cx.attr_span;
3033
self.span = Some(span);
3134

35+
if !matches!(cx.target, Target::Enum | Target::Struct | Target::Union) {
36+
cx.emit_dyn_lint(
37+
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
38+
move |dcx, level| DiagnosticOnMoveOnlyForAdt.into_diag(dcx, level),
39+
span,
40+
);
41+
return;
42+
}
43+
3244
let Some(items) = parse_list(cx, args, mode) else { return };
3345

3446
if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
@@ -44,6 +56,8 @@ impl<S: Stage> AttributeParser<S> for OnMoveParser {
4456
this.parse(cx, args, Mode::DiagnosticOnMove);
4557
},
4658
)];
59+
60+
// "Allowed" for all targets but noop if used on not-adt.
4761
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
4862

4963
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {

compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
use rustc_errors::Diagnostic;
12
use rustc_hir::attrs::diagnostic::Directive;
3+
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
24

35
use crate::attributes::diagnostic::*;
46
use crate::attributes::prelude::*;
7+
use crate::errors::DiagnosticOnUnimplementedOnlyForTraits;
58

69
#[derive(Default)]
710
pub(crate) struct OnUnimplementedParser {
@@ -19,11 +22,12 @@ impl OnUnimplementedParser {
1922
let span = cx.attr_span;
2023
self.span = Some(span);
2124

22-
// If target is not a trait, returning early will make `finalize` emit a
23-
// `AttributeKind::OnUnimplemented {span, directive: None }`, to prevent it being
24-
// accidentally used on non-trait items like trait aliases.
2525
if !matches!(cx.target, Target::Trait) {
26-
// Lint later emitted in check_attr
26+
cx.emit_dyn_lint(
27+
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
28+
move |dcx, level| DiagnosticOnUnimplementedOnlyForTraits.into_diag(dcx, level),
29+
span,
30+
);
2731
return;
2832
}
2933

compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
use rustc_errors::Diagnostic;
12
use rustc_hir::attrs::diagnostic::Directive;
3+
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
24

5+
use crate::ShouldEmit;
36
use crate::attributes::diagnostic::*;
47
use crate::attributes::prelude::*;
8+
use crate::errors::DiagnosticOnUnknownOnlyForImports;
59

610
#[derive(Default)]
711
pub(crate) struct OnUnknownParser {
@@ -25,6 +29,22 @@ impl OnUnknownParser {
2529
let span = cx.attr_span;
2630
self.span = Some(span);
2731

32+
// At early parsing we get passed `Target::Crate` regardless of the item we're on.
33+
// Only do target checking if we're late.
34+
let early = matches!(cx.stage.should_emit(), ShouldEmit::Nothing);
35+
36+
if !early && !matches!(cx.target, Target::Use) {
37+
let target_span = cx.target_span;
38+
cx.emit_dyn_lint(
39+
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
40+
move |dcx, level| {
41+
DiagnosticOnUnknownOnlyForImports { target_span }.into_diag(dcx, level)
42+
},
43+
span,
44+
);
45+
return;
46+
}
47+
2848
let Some(items) = parse_list(cx, args, mode) else { return };
2949

3050
if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
@@ -41,7 +61,7 @@ impl<S: Stage> AttributeParser<S> for OnUnknownParser {
4161
this.parse(cx, args, Mode::DiagnosticOnUnknown);
4262
},
4363
)];
44-
//FIXME attribute is not parsed for non-use statements but diagnostics are issued in `check_attr.rs`
64+
// "Allowed" for all targets, but noop for all but use statements.
4565
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
4666

4767
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {

compiler/rustc_attr_parsing/src/errors.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,3 +252,32 @@ pub(crate) struct DocUnknownAny {
252252
#[derive(Diagnostic)]
253253
#[diag("expected boolean for `#[doc(auto_cfg = ...)]`")]
254254
pub(crate) struct DocAutoCfgWrongLiteral;
255+
256+
#[derive(Diagnostic)]
257+
#[diag("`#[diagnostic::on_const]` can only be applied to non-const trait implementations")]
258+
pub(crate) struct DiagnosticOnConstOnlyForTraitImpls {
259+
#[label("not a trait implementation")]
260+
pub target_span: Span,
261+
}
262+
263+
#[derive(Diagnostic)]
264+
#[diag("`#[diagnostic::on_move]` can only be applied to enums, structs or unions")]
265+
pub(crate) struct DiagnosticOnMoveOnlyForAdt;
266+
267+
#[derive(Diagnostic)]
268+
#[diag("`#[diagnostic::on_unimplemented]` can only be applied to trait definitions")]
269+
pub(crate) struct DiagnosticOnUnimplementedOnlyForTraits;
270+
271+
#[derive(Diagnostic)]
272+
#[diag("`#[diagnostic::on_unknown]` can only be applied to `use` statements")]
273+
pub(crate) struct DiagnosticOnUnknownOnlyForImports {
274+
#[label("not an import")]
275+
pub target_span: Span,
276+
}
277+
278+
#[derive(Diagnostic)]
279+
#[diag("`#[diagnostic::do_not_recommend]` can only be placed on trait implementations")]
280+
pub(crate) struct IncorrectDoNotRecommendLocation {
281+
#[label("not a trait implementation")]
282+
pub target_span: Span,
283+
}

0 commit comments

Comments
 (0)