diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 11459e18190..6dd2161e0f9 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -571,46 +571,37 @@ impl DiagnosticDeriveBuilder { let mut span_idx = None; let mut applicability_idx = None; + fn type_err(span: &Span) -> Result { + span_err(span.unwrap(), "wrong types for suggestion") + .help( + "`#[suggestion(...)]` on a tuple field must be applied to fields \ + of type `(Span, Applicability)`", + ) + .emit(); + Err(DiagnosticDeriveError::ErrorHandled) + } + for (idx, elem) in tup.elems.iter().enumerate() { if type_matches_path(elem, &["rustc_span", "Span"]) { - if span_idx.is_none() { - span_idx = Some(syn::Index::from(idx)); - } else { - throw_span_err!( - info.span.unwrap(), - "type of field annotated with `#[suggestion(...)]` contains more \ - than one `Span`" - ); - } + span_idx.set_once((syn::Index::from(idx), elem.span().unwrap())); } else if type_matches_path(elem, &["rustc_errors", "Applicability"]) { - if applicability_idx.is_none() { - applicability_idx = Some(syn::Index::from(idx)); - } else { - throw_span_err!( - info.span.unwrap(), - "type of field annotated with `#[suggestion(...)]` contains more \ - than one Applicability" - ); - } + applicability_idx.set_once((syn::Index::from(idx), elem.span().unwrap())); + } else { + type_err(&elem.span())?; } } - if let Some(span_idx) = span_idx { - let binding = &info.binding.binding; - let span = quote!(#binding.#span_idx); - let applicability = applicability_idx - .map(|applicability_idx| quote!(#binding.#applicability_idx)) - .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified)); + let Some((span_idx, _)) = span_idx else { + type_err(&tup.span())?; + }; + let Some((applicability_idx, _applicability_span)) = applicability_idx else { + type_err(&tup.span())?; + }; + let binding = &info.binding.binding; + let span = quote!(#binding.#span_idx); + let applicability = quote!(#binding.#applicability_idx); - return Ok((span, Some(applicability))); - } - - throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| { - diag.help( - "`#[suggestion(...)]` on a tuple field must be applied to fields of type \ - `(Span, Applicability)`", - ) - }); + Ok((span, Some(applicability))) } // If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error. _ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| { diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index a113f2a034a..c774484d8bf 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -269,16 +269,16 @@ struct SuggestWithSpanOnly { #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] struct SuggestWithDuplicateSpanAndApplicability { #[suggestion(typeck::suggestion, code = "This is suggested code")] - //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span` suggestion: (Span, Span, Applicability), + //~^ ERROR specified multiple times } #[derive(Diagnostic)] #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] struct SuggestWithDuplicateApplicabilityAndSpan { #[suggestion(typeck::suggestion, code = "This is suggested code")] - //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one suggestion: (Applicability, Applicability, Span), + //~^ ERROR specified multiple times } #[derive(Diagnostic)] @@ -589,3 +589,19 @@ struct DuplicatedSuggestionCode { //~^ ERROR specified multiple times suggestion: Span, } + +#[derive(Diagnostic)] +#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] +struct InvalidTypeInSuggestionTuple { + #[suggestion(typeck::suggestion, code = "...")] + suggestion: (Span, usize), + //~^ ERROR wrong types for suggestion +} + +#[derive(Diagnostic)] +#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] +struct MissingApplicabilityInSuggestionTuple { + #[suggestion(typeck::suggestion, code = "...")] + suggestion: (Span,), + //~^ ERROR wrong types for suggestion +} diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index aa768e28334..084a021ac20 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -263,21 +263,29 @@ LL | | suggestion: Applicability, | = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)` -error: type of field annotated with `#[suggestion(...)]` contains more than one `Span` - --> $DIR/diagnostic-derive.rs:271:5 +error: specified multiple times + --> $DIR/diagnostic-derive.rs:272:24 | -LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")] -LL | | -LL | | suggestion: (Span, Span, Applicability), - | |___________________________________________^ +LL | suggestion: (Span, Span, Applicability), + | ^^^^ + | +note: previously specified here + --> $DIR/diagnostic-derive.rs:272:18 + | +LL | suggestion: (Span, Span, Applicability), + | ^^^^ -error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability - --> $DIR/diagnostic-derive.rs:279:5 +error: specified multiple times + --> $DIR/diagnostic-derive.rs:280:33 | -LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")] -LL | | -LL | | suggestion: (Applicability, Applicability, Span), - | |____________________________________________________^ +LL | suggestion: (Applicability, Applicability, Span), + | ^^^^^^^^^^^^^ + | +note: previously specified here + --> $DIR/diagnostic-derive.rs:280:18 + | +LL | suggestion: (Applicability, Applicability, Span), + | ^^^^^^^^^^^^^ error: `#[label = ...]` is not a valid attribute --> $DIR/diagnostic-derive.rs:287:5 @@ -415,6 +423,22 @@ note: previously specified here LL | #[suggestion(typeck::suggestion, code = "...", code = ",,,")] | ^^^^^^^^^^^^ +error: wrong types for suggestion + --> $DIR/diagnostic-derive.rs:597:24 + | +LL | suggestion: (Span, usize), + | ^^^^^ + | + = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` + +error: wrong types for suggestion + --> $DIR/diagnostic-derive.rs:605:17 + | +LL | suggestion: (Span,), + | ^^^^^^^ + | + = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` + error: cannot find attribute `nonsense` in this scope --> $DIR/diagnostic-derive.rs:53:3 | @@ -471,7 +495,7 @@ LL | arg: impl IntoDiagnosticArg, | ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg` = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 56 previous errors +error: aborting due to 58 previous errors Some errors have detailed explanations: E0277, E0425. For more information about an error, try `rustc --explain E0277`.