From 3738a18df7b2d1fefd111bc929625f82d3a95a23 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sun, 30 Apr 2023 21:45:46 +0100 Subject: [PATCH] Migrate `builtin_macros::asm` diagnostics to translatable diagnostics --- compiler/rustc_builtin_macros/messages.ftl | 35 ++++++ compiler/rustc_builtin_macros/src/asm.rs | 93 +++++---------- compiler/rustc_builtin_macros/src/errors.rs | 123 +++++++++++++++++++- 3 files changed, 179 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 74049406426..0d7cf7cdb26 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -169,5 +169,40 @@ builtin_macros_asm_pure_no_output = asm with the `pure` option must have at leas builtin_macros_asm_modifier_invalid = asm template modifier must be a single character +builtin_macros_asm_requires_template = requires at least a template string argument + +builtin_macros_asm_expected_comma = expected token: `,` + .label = expected `,` + +builtin_macros_asm_underscore_input = _ cannot be used for input operands + +builtin_macros_asm_sym_no_path = expected a path for argument to `sym` + +builtin_macros_asm_expected_other = expected operand, {$is_global_asm -> + [true] options + *[false] clobber_abi, options + }, or additional template string + +builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}` + .label = previously here + .arg = duplicate argument + +builtin_macros_asm_pos_after = positional arguments cannot follow named arguments or explicit register arguments + .pos = positional argument + .named = named argument + .explicit = explicit register argument + +builtin_macros_asm_noreturn = asm outputs are not allowed with the `noreturn` option + +builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!` + +builtin_macros_asm_clobber_no_reg = asm with `clobber_abi` must specify explicit registers for outputs +builtin_macros_asm_clobber_abi = clobber_abi +builtin_macros_asm_clobber_outputs = generic outputs + +builtin_macros_asm_opt_already_provided = the `{$symbol}` option was already provided + .label = this option was already provided + .suggestion = remove this option + builtin_macros_test_runner_invalid = `test_runner` argument must be a path builtin_macros_test_runner_nargs = `#![test_runner(..)]` accepts exactly 1 argument diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index bcdd58a0901..c066512b09e 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -3,7 +3,7 @@ use rustc_ast::token::{self, Delimiter}; use rustc_ast::tokenstream::TokenStream; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::PResult; use rustc_expand::base::{self, *}; use rustc_parse::parser::Parser; use rustc_parse_format as parse; @@ -49,7 +49,7 @@ pub fn parse_asm_args<'a>( let diag = &sess.span_diagnostic; if p.token == token::Eof { - return Err(diag.struct_span_err(sp, "requires at least a template string argument")); + return Err(diag.create_err(errors::AsmRequiresTemplate { span: sp })); } let first_template = p.parse_expr()?; @@ -68,8 +68,7 @@ pub fn parse_asm_args<'a>( if !p.eat(&token::Comma) { if allow_templates { // After a template string, we always expect *only* a comma... - let mut err = diag.struct_span_err(p.token.span, "expected token: `,`"); - err.span_label(p.token.span, "expected `,`"); + let mut err = diag.create_err(errors::AsmExpectedComma { span: p.token.span }); p.maybe_annotate_with_ascription(&mut err, false); return Err(err); } else { @@ -112,7 +111,7 @@ pub fn parse_asm_args<'a>( let op = if !is_global_asm && p.eat_keyword(kw::In) { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { - let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands"); + let err = diag.create_err(errors::AsmUnderscoreInput { span: p.token.span }); return Err(err); } let expr = p.parse_expr()?; @@ -128,7 +127,7 @@ pub fn parse_asm_args<'a>( } else if !is_global_asm && p.eat_keyword(sym::inout) { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { - let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands"); + let err = diag.create_err(errors::AsmUnderscoreInput { span: p.token.span }); return Err(err); } let expr = p.parse_expr()?; @@ -142,7 +141,7 @@ pub fn parse_asm_args<'a>( } else if !is_global_asm && p.eat_keyword(sym::inlateout) { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { - let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands"); + let err = diag.create_err(errors::AsmUnderscoreInput { span: p.token.span }); return Err(err); } let expr = p.parse_expr()?; @@ -160,7 +159,7 @@ pub fn parse_asm_args<'a>( let expr = p.parse_expr()?; let ast::ExprKind::Path(qself, path) = &expr.kind else { let err = diag - .struct_span_err(expr.span, "expected a path for argument to `sym`"); + .create_err(errors::AsmSymNoPath { span: expr.span }); return Err(err); }; let sym = ast::InlineAsmSym { @@ -181,13 +180,10 @@ pub fn parse_asm_args<'a>( ) => {} ast::ExprKind::MacCall(..) => {} _ => { - let errstr = if is_global_asm { - "expected operand, options, or additional template string" - } else { - "expected operand, clobber_abi, options, or additional template string" - }; - let mut err = diag.struct_span_err(template.span, errstr); - err.span_label(template.span, errstr); + let err = diag.create_err(errors::AsmExpectedOther { + span: template.span, + is_global_asm, + }); return Err(err); } } @@ -212,28 +208,16 @@ pub fn parse_asm_args<'a>( args.reg_args.insert(slot); } else if let Some(name) = name { if let Some(&prev) = args.named_args.get(&name) { - diag.struct_span_err(span, &format!("duplicate argument named `{}`", name)) - .span_label(args.operands[prev].1, "previously here") - .span_label(span, "duplicate argument") - .emit(); + diag.emit_err(errors::AsmDuplicateArg { span, name, prev: args.operands[prev].1 }); continue; } args.named_args.insert(name, slot); } else { if !args.named_args.is_empty() || !args.reg_args.is_empty() { - let mut err = diag.struct_span_err( - span, - "positional arguments cannot follow named arguments \ - or explicit register arguments", - ); - err.span_label(span, "positional argument"); - for pos in args.named_args.values() { - err.span_label(args.operands[*pos].1, "named argument"); - } - for pos in &args.reg_args { - err.span_label(args.operands[*pos].1, "explicit register argument"); - } - err.emit(); + let named = args.named_args.values().map(|p| args.operands[*p].1).collect(); + let explicit = args.reg_args.iter().map(|p| args.operands[*p].1).collect(); + + diag.emit_err(errors::AsmPositionalAfter { span, named, explicit }); } } } @@ -284,34 +268,25 @@ pub fn parse_asm_args<'a>( diag.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() }); } if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() { - let err = diag - .struct_span_err(outputs_sp, "asm outputs are not allowed with the `noreturn` option"); - + let err = diag.create_err(errors::AsmNoReturn { outputs_sp }); // Bail out now since this is likely to confuse MIR return Err(err); } if args.clobber_abis.len() > 0 { if is_global_asm { - let err = diag.struct_span_err( - args.clobber_abis.iter().map(|(_, span)| *span).collect::>(), - "`clobber_abi` cannot be used with `global_asm!`", - ); + let err = diag.create_err(errors::GlobalAsmClobberAbi { + spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(), + }); // Bail out now since this is likely to confuse later stages return Err(err); } if !regclass_outputs.is_empty() { - diag.struct_span_err( - regclass_outputs.clone(), - "asm with `clobber_abi` must specify explicit registers for outputs", - ) - .span_labels( - args.clobber_abis.iter().map(|(_, span)| *span).collect::>(), - "clobber_abi", - ) - .span_labels(regclass_outputs, "generic outputs") - .emit(); + diag.emit_err(errors::AsmClobberNoReg { + spans: regclass_outputs, + clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(), + }); } } @@ -323,25 +298,9 @@ pub fn parse_asm_args<'a>( /// This function must be called immediately after the option token is parsed. /// Otherwise, the suggestion will be incorrect. fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) { - let mut err = p - .sess - .span_diagnostic - .struct_span_err(span, &format!("the `{}` option was already provided", symbol)); - err.span_label(span, "this option was already provided"); - // Tool-only output - let mut full_span = span; - if p.token.kind == token::Comma { - full_span = full_span.to(p.token.span); - } - err.tool_only_span_suggestion( - full_span, - "remove this option", - "", - Applicability::MachineApplicable, - ); - - err.emit(); + let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span }; + p.sess.span_diagnostic.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); } /// Try to set the provided option in the provided `AsmArgs`. diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index b146988a3c2..d0d78646009 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,5 +1,6 @@ use rustc_errors::{ - AddToDiagnostic, EmissionGuarantee, IntoDiagnostic, MultiSpan, SingleLabelManySpans, + AddToDiagnostic, DiagnosticBuilder, EmissionGuarantee, Handler, IntoDiagnostic, MultiSpan, + SingleLabelManySpans, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -370,11 +371,12 @@ pub(crate) struct EnvNotDefined { // Hand-written implementation to support custom user messages impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefined { #[track_caller] - fn into_diagnostic( - self, - handler: &'a rustc_errors::Handler, - ) -> rustc_errors::DiagnosticBuilder<'a, G> { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> { let mut diag = if let Some(msg) = self.msg { + #[expect( + rustc::untranslatable_diagnostic, + reason = "cannot translate user-provided messages" + )] handler.struct_diagnostic(msg.as_str()) } else { handler.struct_diagnostic(crate::fluent_generated::builtin_macros_env_not_defined) @@ -606,6 +608,117 @@ pub(crate) struct AsmModifierInvalid { pub(crate) span: Span, } +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_requires_template)] +pub(crate) struct AsmRequiresTemplate { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_expected_comma)] +pub(crate) struct AsmExpectedComma { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_underscore_input)] +pub(crate) struct AsmUnderscoreInput { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_sym_no_path)] +pub(crate) struct AsmSymNoPath { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_expected_other)] +pub(crate) struct AsmExpectedOther { + #[primary_span] + #[label(builtin_macros_asm_expected_other)] + pub(crate) span: Span, + pub(crate) is_global_asm: bool, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_duplicate_arg)] +pub(crate) struct AsmDuplicateArg { + #[primary_span] + #[label(builtin_macros_arg)] + pub(crate) span: Span, + #[label] + pub(crate) prev: Span, + pub(crate) name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_pos_after)] +pub(crate) struct AsmPositionalAfter { + #[primary_span] + #[label(builtin_macros_pos)] + pub(crate) span: Span, + #[label(builtin_macros_named)] + pub(crate) named: Vec, + #[label(builtin_macros_explicit)] + pub(crate) explicit: Vec, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_noreturn)] +pub(crate) struct AsmNoReturn { + #[primary_span] + pub(crate) outputs_sp: Vec, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_global_asm_clobber_abi)] +pub(crate) struct GlobalAsmClobberAbi { + #[primary_span] + pub(crate) spans: Vec, +} + +pub(crate) struct AsmClobberNoReg { + pub(crate) spans: Vec, + pub(crate) clobbers: Vec, +} + +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> { + let mut diag = + handler.struct_diagnostic(crate::fluent_generated::builtin_macros_asm_clobber_no_reg); + diag.set_span(self.spans.clone()); + // eager translation as `span_labels` takes `AsRef` + let lbl1 = handler.eagerly_translate_to_string( + crate::fluent_generated::builtin_macros_asm_clobber_abi, + [].into_iter(), + ); + diag.span_labels(self.clobbers, &lbl1); + let lbl2 = handler.eagerly_translate_to_string( + crate::fluent_generated::builtin_macros_asm_clobber_outputs, + [].into_iter(), + ); + diag.span_labels(self.spans, &lbl2); + diag + } +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_opt_already_provided)] +pub(crate) struct AsmOptAlreadyprovided { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) symbol: Symbol, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub(crate) full_span: Span, +} + #[derive(Diagnostic)] #[diag(builtin_macros_test_runner_invalid)] pub(crate) struct TestRunnerInvalid {