Skip to content

Commit ec85a1b

Browse files
committed
Ensure #[suggestion] is only applied to correct tuple types
1 parent 2e72387 commit ec85a1b

File tree

3 files changed

+79
-48
lines changed

3 files changed

+79
-48
lines changed

compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -571,46 +571,37 @@ impl DiagnosticDeriveBuilder {
571571
let mut span_idx = None;
572572
let mut applicability_idx = None;
573573

574+
fn type_err(span: &Span) -> Result<!, DiagnosticDeriveError> {
575+
span_err(span.unwrap(), "wrong types for suggestion")
576+
.help(
577+
"`#[suggestion(...)]` on a tuple field must be applied to fields \
578+
of type `(Span, Applicability)`",
579+
)
580+
.emit();
581+
Err(DiagnosticDeriveError::ErrorHandled)
582+
}
583+
574584
for (idx, elem) in tup.elems.iter().enumerate() {
575585
if type_matches_path(elem, &["rustc_span", "Span"]) {
576-
if span_idx.is_none() {
577-
span_idx = Some(syn::Index::from(idx));
578-
} else {
579-
throw_span_err!(
580-
info.span.unwrap(),
581-
"type of field annotated with `#[suggestion(...)]` contains more \
582-
than one `Span`"
583-
);
584-
}
586+
span_idx.set_once((syn::Index::from(idx), elem.span().unwrap()));
585587
} else if type_matches_path(elem, &["rustc_errors", "Applicability"]) {
586-
if applicability_idx.is_none() {
587-
applicability_idx = Some(syn::Index::from(idx));
588-
} else {
589-
throw_span_err!(
590-
info.span.unwrap(),
591-
"type of field annotated with `#[suggestion(...)]` contains more \
592-
than one Applicability"
593-
);
594-
}
588+
applicability_idx.set_once((syn::Index::from(idx), elem.span().unwrap()));
589+
} else {
590+
type_err(&elem.span())?;
595591
}
596592
}
597593

598-
if let Some(span_idx) = span_idx {
599-
let binding = &info.binding.binding;
600-
let span = quote!(#binding.#span_idx);
601-
let applicability = applicability_idx
602-
.map(|applicability_idx| quote!(#binding.#applicability_idx))
603-
.unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
604-
605-
return Ok((span, Some(applicability)));
606-
}
594+
let Some((span_idx, _)) = span_idx else {
595+
type_err(&tup.span())?;
596+
};
597+
let Some((applicability_idx, _applicability_span)) = applicability_idx else {
598+
type_err(&tup.span())?;
599+
};
600+
let binding = &info.binding.binding;
601+
let span = quote!(#binding.#span_idx);
602+
let applicability = quote!(#binding.#applicability_idx);
607603

608-
throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| {
609-
diag.help(
610-
"`#[suggestion(...)]` on a tuple field must be applied to fields of type \
611-
`(Span, Applicability)`",
612-
)
613-
});
604+
Ok((span, Some(applicability)))
614605
}
615606
// If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error.
616607
_ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| {

src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,16 +269,16 @@ struct SuggestWithSpanOnly {
269269
#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
270270
struct SuggestWithDuplicateSpanAndApplicability {
271271
#[suggestion(typeck::suggestion, code = "This is suggested code")]
272-
//~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span`
273272
suggestion: (Span, Span, Applicability),
273+
//~^ ERROR specified multiple times
274274
}
275275

276276
#[derive(Diagnostic)]
277277
#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
278278
struct SuggestWithDuplicateApplicabilityAndSpan {
279279
#[suggestion(typeck::suggestion, code = "This is suggested code")]
280-
//~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one
281280
suggestion: (Applicability, Applicability, Span),
281+
//~^ ERROR specified multiple times
282282
}
283283

284284
#[derive(Diagnostic)]
@@ -589,3 +589,19 @@ struct DuplicatedSuggestionCode {
589589
//~^ ERROR specified multiple times
590590
suggestion: Span,
591591
}
592+
593+
#[derive(Diagnostic)]
594+
#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
595+
struct InvalidTypeInSuggestionTuple {
596+
#[suggestion(typeck::suggestion, code = "...")]
597+
suggestion: (Span, usize),
598+
//~^ ERROR wrong types for suggestion
599+
}
600+
601+
#[derive(Diagnostic)]
602+
#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
603+
struct MissingApplicabilityInSuggestionTuple {
604+
#[suggestion(typeck::suggestion, code = "...")]
605+
suggestion: (Span,),
606+
//~^ ERROR wrong types for suggestion
607+
}

src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -263,21 +263,29 @@ LL | | suggestion: Applicability,
263263
|
264264
= help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
265265

266-
error: type of field annotated with `#[suggestion(...)]` contains more than one `Span`
267-
--> $DIR/diagnostic-derive.rs:271:5
266+
error: specified multiple times
267+
--> $DIR/diagnostic-derive.rs:272:24
268268
|
269-
LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")]
270-
LL | |
271-
LL | | suggestion: (Span, Span, Applicability),
272-
| |___________________________________________^
269+
LL | suggestion: (Span, Span, Applicability),
270+
| ^^^^
271+
|
272+
note: previously specified here
273+
--> $DIR/diagnostic-derive.rs:272:18
274+
|
275+
LL | suggestion: (Span, Span, Applicability),
276+
| ^^^^
273277

274-
error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
275-
--> $DIR/diagnostic-derive.rs:279:5
278+
error: specified multiple times
279+
--> $DIR/diagnostic-derive.rs:280:33
276280
|
277-
LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")]
278-
LL | |
279-
LL | | suggestion: (Applicability, Applicability, Span),
280-
| |____________________________________________________^
281+
LL | suggestion: (Applicability, Applicability, Span),
282+
| ^^^^^^^^^^^^^
283+
|
284+
note: previously specified here
285+
--> $DIR/diagnostic-derive.rs:280:18
286+
|
287+
LL | suggestion: (Applicability, Applicability, Span),
288+
| ^^^^^^^^^^^^^
281289

282290
error: `#[label = ...]` is not a valid attribute
283291
--> $DIR/diagnostic-derive.rs:287:5
@@ -415,6 +423,22 @@ note: previously specified here
415423
LL | #[suggestion(typeck::suggestion, code = "...", code = ",,,")]
416424
| ^^^^^^^^^^^^
417425

426+
error: wrong types for suggestion
427+
--> $DIR/diagnostic-derive.rs:597:24
428+
|
429+
LL | suggestion: (Span, usize),
430+
| ^^^^^
431+
|
432+
= help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
433+
434+
error: wrong types for suggestion
435+
--> $DIR/diagnostic-derive.rs:605:17
436+
|
437+
LL | suggestion: (Span,),
438+
| ^^^^^^^
439+
|
440+
= help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
441+
418442
error: cannot find attribute `nonsense` in this scope
419443
--> $DIR/diagnostic-derive.rs:53:3
420444
|
@@ -471,7 +495,7 @@ LL | arg: impl IntoDiagnosticArg,
471495
| ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
472496
= note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
473497

474-
error: aborting due to 56 previous errors
498+
error: aborting due to 58 previous errors
475499

476500
Some errors have detailed explanations: E0277, E0425.
477501
For more information about an error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)