Skip to content

Commit 74815d2

Browse files
authored
Unrolled build for #154794
Rollup merge of #154794 - chenyukang:yukang-fix-152494-incomplete-macro-args, r=mejrs Add on_unmatch_args Fixes #152494 r? @estebank
2 parents f676c20 + 8d75f0c commit 74815d2

45 files changed

Lines changed: 576 additions & 11 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub(crate) mod on_const;
2525
pub(crate) mod on_move;
2626
pub(crate) mod on_unimplemented;
2727
pub(crate) mod on_unknown;
28+
pub(crate) mod on_unmatch_args;
2829

2930
#[derive(Copy, Clone)]
3031
pub(crate) enum Mode {
@@ -38,6 +39,8 @@ pub(crate) enum Mode {
3839
DiagnosticOnMove,
3940
/// `#[diagnostic::on_unknown]`
4041
DiagnosticOnUnknown,
42+
/// `#[diagnostic::on_unmatch_args]`
43+
DiagnosticOnUnmatchArgs,
4144
}
4245

4346
impl Mode {
@@ -48,6 +51,7 @@ impl Mode {
4851
Self::DiagnosticOnConst => "diagnostic::on_const",
4952
Self::DiagnosticOnMove => "diagnostic::on_move",
5053
Self::DiagnosticOnUnknown => "diagnostic::on_unknown",
54+
Self::DiagnosticOnUnmatchArgs => "diagnostic::on_unmatch_args",
5155
}
5256
}
5357

@@ -62,6 +66,7 @@ impl Mode {
6266
Self::DiagnosticOnConst => DEFAULT,
6367
Self::DiagnosticOnMove => DEFAULT,
6468
Self::DiagnosticOnUnknown => DEFAULT,
69+
Self::DiagnosticOnUnmatchArgs => DEFAULT,
6570
}
6671
}
6772

@@ -75,6 +80,7 @@ impl Mode {
7580
Self::DiagnosticOnConst => DEFAULT,
7681
Self::DiagnosticOnMove => DEFAULT,
7782
Self::DiagnosticOnUnknown => DEFAULT,
83+
Self::DiagnosticOnUnmatchArgs => DEFAULT,
7884
}
7985
}
8086
}
@@ -398,7 +404,9 @@ fn parse_arg(
398404
Position::ArgumentNamed(name) => match (mode, Symbol::intern(name)) {
399405
// Only `#[rustc_on_unimplemented]` can use these
400406
(Mode::RustcOnUnimplemented { .. }, sym::ItemContext) => FormatArg::ItemContext,
401-
(Mode::RustcOnUnimplemented { .. }, sym::This) => FormatArg::This,
407+
(Mode::RustcOnUnimplemented { .. } | Mode::DiagnosticOnUnmatchArgs, sym::This) => {
408+
FormatArg::This
409+
}
402410
(Mode::RustcOnUnimplemented { .. }, sym::Trait) => FormatArg::Trait,
403411
// Any attribute can use these
404412
(_, kw::SelfUpper) => FormatArg::SelfUpper,
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use rustc_errors::Diagnostic;
2+
use rustc_hir::attrs::diagnostic::Directive;
3+
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
4+
5+
use crate::attributes::diagnostic::*;
6+
use crate::attributes::prelude::*;
7+
use crate::errors::DiagnosticOnUnmatchArgsOnlyForMacros;
8+
9+
#[derive(Default)]
10+
pub(crate) struct OnUnmatchArgsParser {
11+
span: Option<Span>,
12+
directive: Option<(Span, Directive)>,
13+
}
14+
15+
impl<S: Stage> AttributeParser<S> for OnUnmatchArgsParser {
16+
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
17+
&[sym::diagnostic, sym::on_unmatch_args],
18+
template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
19+
|this, cx, args| {
20+
if !cx.features().diagnostic_on_unmatch_args() {
21+
return;
22+
}
23+
24+
let span = cx.attr_span;
25+
this.span = Some(span);
26+
27+
if !matches!(cx.target, Target::MacroDef) {
28+
cx.emit_dyn_lint(
29+
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
30+
move |dcx, level| DiagnosticOnUnmatchArgsOnlyForMacros.into_diag(dcx, level),
31+
span,
32+
);
33+
return;
34+
}
35+
36+
let mode = Mode::DiagnosticOnUnmatchArgs;
37+
let Some(items) = parse_list(cx, args, mode) else { return };
38+
39+
let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) else {
40+
return;
41+
};
42+
merge_directives(cx, &mut this.directive, (span, directive));
43+
},
44+
)];
45+
46+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
47+
48+
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
49+
if let Some(span) = self.span {
50+
Some(AttributeKind::OnUnmatchArgs {
51+
span,
52+
directive: self.directive.map(|d| Box::new(d.1)),
53+
})
54+
} else {
55+
None
56+
}
57+
}
58+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use crate::attributes::diagnostic::on_const::*;
3333
use crate::attributes::diagnostic::on_move::*;
3434
use crate::attributes::diagnostic::on_unimplemented::*;
3535
use crate::attributes::diagnostic::on_unknown::*;
36+
use crate::attributes::diagnostic::on_unmatch_args::*;
3637
use crate::attributes::doc::*;
3738
use crate::attributes::dummy::*;
3839
use crate::attributes::inline::*;
@@ -159,6 +160,7 @@ attribute_parsers!(
159160
OnMoveParser,
160161
OnUnimplementedParser,
161162
OnUnknownParser,
163+
OnUnmatchArgsParser,
162164
RustcAlignParser,
163165
RustcAlignStaticParser,
164166
RustcCguTestAttributeParser,

compiler/rustc_attr_parsing/src/errors.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ pub(crate) struct DiagnosticOnUnknownOnlyForImports {
315315
pub target_span: Span,
316316
}
317317

318+
#[derive(Diagnostic)]
319+
#[diag("`#[diagnostic::on_unmatch_args]` can only be applied to macro definitions")]
320+
pub(crate) struct DiagnosticOnUnmatchArgsOnlyForMacros;
321+
318322
#[derive(Diagnostic)]
319323
#[diag("`#[diagnostic::do_not_recommend]` can only be placed on trait implementations")]
320324
pub(crate) struct IncorrectDoNotRecommendLocation {

compiler/rustc_expand/src/mbe/diagnostics.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::borrow::Cow;
33
use rustc_ast::token::{self, Token};
44
use rustc_ast::tokenstream::TokenStream;
55
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
6+
use rustc_hir::attrs::diagnostic::{CustomDiagnostic, Directive, FormatArgs};
67
use rustc_macros::Subdiagnostic;
78
use rustc_parse::parser::{Parser, Recovery, token_descr};
89
use rustc_session::parse::ParseSess;
@@ -32,6 +33,7 @@ pub(super) fn failed_to_match_macro(
3233
args: FailedMacro<'_>,
3334
body: &TokenStream,
3435
rules: &[MacroRule],
36+
on_unmatch_args: Option<&Directive>,
3537
) -> (Span, ErrorGuaranteed) {
3638
debug!("failed to match macro");
3739
let def_head_span = if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) {
@@ -72,9 +74,30 @@ pub(super) fn failed_to_match_macro(
7274
};
7375

7476
let span = token.span.substitute_dummy(sp);
77+
let CustomDiagnostic {
78+
message: custom_message, label: custom_label, notes: custom_notes, ..
79+
} = {
80+
let macro_name = name.to_string();
81+
on_unmatch_args
82+
.map(|directive| {
83+
directive.eval(
84+
None,
85+
&FormatArgs {
86+
this: macro_name.clone(),
87+
this_sugared: macro_name,
88+
item_context: "macro invocation",
89+
generic_args: Vec::new(),
90+
},
91+
)
92+
})
93+
.unwrap_or_default()
94+
};
7595

76-
let mut err = psess.dcx().struct_span_err(span, parse_failure_msg(&token, None));
77-
err.span_label(span, label);
96+
let mut err = match custom_message {
97+
Some(message) => psess.dcx().struct_span_err(span, message),
98+
None => psess.dcx().struct_span_err(span, parse_failure_msg(&token, None)),
99+
};
100+
err.span_label(span, custom_label.unwrap_or_else(|| label.to_string()));
78101
if !def_head_span.is_dummy() {
79102
err.span_label(def_head_span, "when calling this macro");
80103
}
@@ -86,6 +109,9 @@ pub(super) fn failed_to_match_macro(
86109
} else {
87110
err.note(format!("while trying to match {remaining_matcher}"));
88111
}
112+
for note in custom_notes {
113+
err.note(note);
114+
}
89115

90116
if let MatcherLoc::Token { token: expected_token } = &remaining_matcher
91117
&& (matches!(expected_token.kind, token::OpenInvisible(_))

compiler/rustc_expand/src/mbe/macro_rules.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
1414
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
1515
use rustc_feature::Features;
1616
use rustc_hir as hir;
17+
use rustc_hir::attrs::diagnostic::Directive;
1718
use rustc_hir::def::MacroKinds;
1819
use rustc_hir::find_attr;
1920
use rustc_lint_defs::builtin::{
@@ -164,6 +165,7 @@ pub struct MacroRulesMacroExpander {
164165
node_id: NodeId,
165166
name: Ident,
166167
span: Span,
168+
on_unmatch_args: Option<Directive>,
167169
transparency: Transparency,
168170
kinds: MacroKinds,
169171
rules: Vec<MacroRule>,
@@ -194,7 +196,8 @@ impl MacroRulesMacroExpander {
194196
) -> Result<TokenStream, ErrorGuaranteed> {
195197
// This is similar to `expand_macro`, but they have very different signatures, and will
196198
// diverge further once derives support arguments.
197-
let Self { name, ref rules, node_id, .. } = *self;
199+
let name = self.name;
200+
let rules = &self.rules;
198201
let psess = &cx.sess.psess;
199202

200203
if cx.trace_macros() {
@@ -220,8 +223,8 @@ impl MacroRulesMacroExpander {
220223
trace_macros_note(&mut cx.expansions, sp, msg);
221224
}
222225

223-
if is_defined_in_current_crate(node_id) {
224-
cx.resolver.record_macro_rule_usage(node_id, rule_index);
226+
if is_defined_in_current_crate(self.node_id) {
227+
cx.resolver.record_macro_rule_usage(self.node_id, rule_index);
225228
}
226229

227230
Ok(tts)
@@ -236,6 +239,7 @@ impl MacroRulesMacroExpander {
236239
FailedMacro::Derive,
237240
body,
238241
rules,
242+
self.on_unmatch_args.as_ref(),
239243
);
240244
cx.macro_error_and_trace_macros_diag();
241245
Err(guar)
@@ -260,6 +264,7 @@ impl TTMacroExpander for MacroRulesMacroExpander {
260264
self.transparency,
261265
input,
262266
&self.rules,
267+
self.on_unmatch_args.as_ref(),
263268
))
264269
}
265270
}
@@ -294,6 +299,7 @@ impl AttrProcMacro for MacroRulesMacroExpander {
294299
args,
295300
body,
296301
&self.rules,
302+
self.on_unmatch_args.as_ref(),
297303
)
298304
}
299305
}
@@ -355,7 +361,7 @@ impl<'matcher> Tracker<'matcher> for NoopTracker {
355361
}
356362

357363
/// Expands the rules based macro defined by `rules` for a given input `arg`.
358-
#[instrument(skip(cx, transparency, arg, rules))]
364+
#[instrument(skip(cx, transparency, arg, rules, on_unmatch_args))]
359365
fn expand_macro<'cx, 'a: 'cx>(
360366
cx: &'cx mut ExtCtxt<'_>,
361367
sp: Span,
@@ -365,6 +371,7 @@ fn expand_macro<'cx, 'a: 'cx>(
365371
transparency: Transparency,
366372
arg: TokenStream,
367373
rules: &'a [MacroRule],
374+
on_unmatch_args: Option<&Directive>,
368375
) -> Box<dyn MacResult + 'cx> {
369376
let psess = &cx.sess.psess;
370377

@@ -423,6 +430,7 @@ fn expand_macro<'cx, 'a: 'cx>(
423430
FailedMacro::Func,
424431
&arg,
425432
rules,
433+
on_unmatch_args,
426434
);
427435
cx.macro_error_and_trace_macros_diag();
428436
DummyResult::any(span, guar)
@@ -431,7 +439,7 @@ fn expand_macro<'cx, 'a: 'cx>(
431439
}
432440

433441
/// Expands the rules based macro defined by `rules` for a given attribute `args` and `body`.
434-
#[instrument(skip(cx, transparency, args, body, rules))]
442+
#[instrument(skip(cx, transparency, args, body, rules, on_unmatch_args))]
435443
fn expand_macro_attr(
436444
cx: &mut ExtCtxt<'_>,
437445
sp: Span,
@@ -443,6 +451,7 @@ fn expand_macro_attr(
443451
args: TokenStream,
444452
body: TokenStream,
445453
rules: &[MacroRule],
454+
on_unmatch_args: Option<&Directive>,
446455
) -> Result<TokenStream, ErrorGuaranteed> {
447456
let psess = &cx.sess.psess;
448457
// Macros defined in the current crate have a real node id,
@@ -507,6 +516,7 @@ fn expand_macro_attr(
507516
FailedMacro::Attr(&args),
508517
&body,
509518
rules,
519+
on_unmatch_args,
510520
);
511521
cx.trace_macros_diag();
512522
Err(guar)
@@ -849,7 +859,22 @@ pub fn compile_declarative_macro(
849859
// Return the number of rules for unused rule linting, if this is a local macro.
850860
let nrules = if is_defined_in_current_crate(node_id) { rules.len() } else { 0 };
851861

852-
let exp = MacroRulesMacroExpander { name: ident, kinds, span, node_id, transparency, rules };
862+
let on_unmatch_args = find_attr!(
863+
attrs,
864+
OnUnmatchArgs { directive, .. } => directive.clone()
865+
)
866+
.flatten()
867+
.map(|directive| *directive);
868+
869+
let exp = MacroRulesMacroExpander {
870+
name: ident,
871+
kinds,
872+
span,
873+
node_id,
874+
on_unmatch_args,
875+
transparency,
876+
rules,
877+
};
853878
(mk_syn_ext(SyntaxExtensionKind::MacroRules(Arc::new(exp))), nrules)
854879
}
855880

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,8 @@ declare_features! (
480480
(unstable, diagnostic_on_move, "1.96.0", Some(154181)),
481481
/// Allows giving unresolved imports a custom diagnostic message
482482
(unstable, diagnostic_on_unknown, "1.96.0", Some(152900)),
483+
/// Allows macros to customize macro argument matcher diagnostics.
484+
(unstable, diagnostic_on_unmatch_args, "CURRENT_RUSTC_VERSION", Some(155642)),
483485
/// Allows `#[doc(cfg(...))]`.
484486
(unstable, doc_cfg, "1.21.0", Some(43781)),
485487
/// Allows `#[doc(masked)]`.

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,6 +1208,13 @@ pub enum AttributeKind {
12081208
directive: Option<Box<Directive>>,
12091209
},
12101210

1211+
/// Represents `#[diagnostic::on_unmatch_args]`.
1212+
OnUnmatchArgs {
1213+
span: Span,
1214+
/// None if the directive was malformed in some way.
1215+
directive: Option<Box<Directive>>,
1216+
},
1217+
12111218
/// Represents `#[optimize(size|speed)]`
12121219
Optimize(OptimizeAttr, Span),
12131220

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ impl AttributeKind {
8080
OnMove { .. } => Yes,
8181
OnUnimplemented { .. } => Yes,
8282
OnUnknown { .. } => Yes,
83+
OnUnmatchArgs { .. } => Yes,
8384
Optimize(..) => No,
8485
PanicRuntime => No,
8586
PatchableFunctionEntry { .. } => Yes,

compiler/rustc_lint/src/early/diagnostics.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> {
5252
lints::MalFormedDiagnosticAttributeLint { attribute, options, span }
5353
.into_diag(dcx, level)
5454
}
55-
5655
AttributeLintKind::MalformedDiagnosticFormat { warning } => match warning {
5756
FormatWarning::PositionalArgument { .. } => {
5857
lints::DisallowedPositionalArgument.into_diag(dcx, level)

0 commit comments

Comments
 (0)