rustc_attr_parsing/attributes/diagnostic/
on_unknown.rs1use rustc_errors::Diagnostic;
2use rustc_hir::attrs::diagnostic::Directive;
3use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
4
5use crate::ShouldEmit;
6use crate::attributes::diagnostic::*;
7use crate::attributes::prelude::*;
8use crate::errors::DiagnosticOnUnknownOnlyForImports;
9
10#[derive(#[automatically_derived]
impl ::core::default::Default for OnUnknownParser {
#[inline]
fn default() -> OnUnknownParser {
OnUnknownParser {
span: ::core::default::Default::default(),
directive: ::core::default::Default::default(),
}
}
}Default)]
11pub(crate) struct OnUnknownParser {
12 span: Option<Span>,
13 directive: Option<(Span, Directive)>,
14}
15
16impl OnUnknownParser {
17 fn parse<'sess, S: Stage>(
18 &mut self,
19 cx: &mut AcceptContext<'_, 'sess, S>,
20 args: &ArgParser,
21 mode: Mode,
22 ) {
23 if let Some(features) = cx.features
24 && !features.diagnostic_on_unknown()
25 {
26 return;
28 }
29 let span = cx.attr_span;
30 self.span = Some(span);
31
32 let early = #[allow(non_exhaustive_omitted_patterns)] match cx.stage.should_emit() {
ShouldEmit::Nothing => true,
_ => false,
}matches!(cx.stage.should_emit(), ShouldEmit::Nothing);
35
36 if !early && !#[allow(non_exhaustive_omitted_patterns)] match cx.target {
Target::Use => true,
_ => false,
}matches!(cx.target, Target::Use) {
37 let target_span = cx.target_span;
38 cx.emit_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
48 let Some(items) = parse_list(cx, args, mode) else { return };
49
50 if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
51 merge_directives(cx, &mut self.directive, (span, directive));
52 };
53 }
54}
55
56impl<S: Stage> AttributeParser<S> for OnUnknownParser {
57 const ATTRIBUTES: AcceptMapping<Self, S> = &[(
58 &[sym::diagnostic, sym::on_unknown],
59 ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
60 |this, cx, args| {
61 this.parse(cx, args, Mode::DiagnosticOnUnknown);
62 },
63 )];
64 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
66
67 fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
68 if let Some(span) = self.span {
69 Some(AttributeKind::OnUnknown {
70 span,
71 directive: self.directive.map(|d| Box::new(d.1)),
72 })
73 } else {
74 None
75 }
76 }
77}