From 12b87a7b4908e2719201bc41358430158e8e3197 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 4 Sep 2022 11:08:19 +0000 Subject: [PATCH 1/2] Migrate `rustc_builtin_macros::asm` to `SessionDiagnostic` --- compiler/rustc_builtin_macros/src/asm.rs | 198 +++++++--------- compiler/rustc_builtin_macros/src/errors.rs | 218 ++++++++++++++++++ compiler/rustc_builtin_macros/src/lib.rs | 1 + .../locales/en-US/builtin_macros.ftl | 88 +++++++ 4 files changed, 384 insertions(+), 121 deletions(-) create mode 100644 compiler/rustc_builtin_macros/src/errors.rs diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index a1051d990b14b..d6e344c311bd8 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -3,7 +3,7 @@ use rustc_ast::ptr::P; 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; @@ -15,6 +15,8 @@ use rustc_span::{InnerSpan, Span}; use rustc_target::asm::InlineAsmArch; use smallvec::smallvec; +use crate::errors::*; + pub struct AsmArgs { pub templates: Vec>, pub operands: Vec<(ast::InlineAsmOperand, Span)>, @@ -41,13 +43,11 @@ fn parse_args<'a>( pub fn parse_asm_args<'a>( p: &mut Parser<'a>, sess: &'a ParseSess, - sp: Span, + span: Span, is_global_asm: bool, ) -> PResult<'a, AsmArgs> { - 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(sess.create_err(AsmRequiresTemplateStringArg { span })); } let first_template = p.parse_expr()?; @@ -66,8 +66,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 = sess.create_err(AsmExpectedTokenComma { span: p.token.span }); p.maybe_annotate_with_ascription(&mut err, false); return Err(err); } else { @@ -110,8 +109,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"); - return Err(err); + return Err(sess.create_err(AsmUnderscoreForInputOperands { span: p.token.span })); } let expr = p.parse_expr()?; ast::InlineAsmOperand::In { reg, expr } @@ -126,8 +124,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"); - return Err(err); + return Err(sess.create_err(AsmUnderscoreForInputOperands { span: p.token.span })); } let expr = p.parse_expr()?; if p.eat(&token::FatArrow) { @@ -140,8 +137,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"); - return Err(err); + return Err(sess.create_err(AsmUnderscoreForInputOperands { span: p.token.span })); } let expr = p.parse_expr()?; if p.eat(&token::FatArrow) { @@ -157,9 +153,7 @@ pub fn parse_asm_args<'a>( } else if p.eat_keyword(sym::sym) { 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`"); - return Err(err); + return Err(sess.create_err(AsmExpectedPathArgToSym{span: expr.span})); }; let sym = ast::InlineAsmSym { id: ast::DUMMY_NODE_ID, @@ -175,13 +169,15 @@ pub fn parse_asm_args<'a>( ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {} ast::ExprKind::MacCall(..) => {} _ => { - let errstr = if is_global_asm { - "expected operand, options, or additional template string" + let err = if is_global_asm { + sess.create_err(AsmExpectedOperandOptionsOrTemplateString { + span: template.span, + }) } else { - "expected operand, clobber_abi, options, or additional template string" + sess.create_err(AsmExpectedOperandClobberAbiOptionsOrTemplateString { + span: template.span, + }) }; - let mut err = diag.struct_span_err(template.span, errstr); - err.span_label(template.span, errstr); return Err(err); } } @@ -200,56 +196,49 @@ pub fn parse_asm_args<'a>( // clobber_abi/options. We do this at the end once we have the full span // of the argument available. if !args.options_spans.is_empty() { - diag.struct_span_err(span, "arguments are not allowed after options") - .span_labels(args.options_spans.clone(), "previous options") - .span_label(span, "argument") - .emit(); + sess.create_err(AsmArgsAfterOptions { + span, + options_spans: args.options_spans.clone(), + }) + .emit(); } else if let Some((_, abi_span)) = args.clobber_abis.last() { - diag.struct_span_err(span, "arguments are not allowed after clobber_abi") - .span_label(*abi_span, "clobber_abi") - .span_label(span, "argument") - .emit(); + sess.create_err(AsmArgsAfterClobberAbi { span, abi_span: *abi_span }).emit(); } if explicit_reg { if name.is_some() { - diag.struct_span_err(span, "explicit register arguments cannot have names").emit(); + sess.create_err(AsmExplicitRegisterArgWithName { span }).emit(); } 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(); + sess.create_err(AsmDuplicateArgument { + name, + span, + prev_span: args.operands[prev].1, + }) + .emit(); continue; } if !args.reg_args.is_empty() { - let mut err = diag.struct_span_err( + sess.create_err(AsmArgsNamedAfterExplicitRegister { span, - "named arguments cannot follow explicit register arguments", - ); - err.span_label(span, "named argument"); - for pos in &args.reg_args { - err.span_label(args.operands[*pos].1, "explicit register argument"); - } - err.emit(); + register_spans: args.reg_args.iter().map(|pos| args.operands[*pos].1).collect(), + }) + .emit(); } 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( + sess.create_err(AsmArgsPositionalAfterNamedOrExplicitRegister { 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(); + named_spans: args + .named_args + .values() + .map(|pos| args.operands[*pos].1) + .collect(), + register_spans: args.reg_args.iter().map(|pos| args.operands[*pos].1).collect(), + }) + .emit(); } } } @@ -258,24 +247,26 @@ pub fn parse_asm_args<'a>( && args.options.contains(ast::InlineAsmOptions::READONLY) { let spans = args.options_spans.clone(); - diag.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive") + sess.create_err(AsmOptionsMutuallyExclusive { left: "nomem", right: "readonly", spans }) .emit(); } if args.options.contains(ast::InlineAsmOptions::PURE) && args.options.contains(ast::InlineAsmOptions::NORETURN) { let spans = args.options_spans.clone(); - diag.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive") + sess.create_err(AsmOptionsMutuallyExclusive { left: "pure", right: "noreturn", spans }) .emit(); } if args.options.contains(ast::InlineAsmOptions::PURE) && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY) { let spans = args.options_spans.clone(); - diag.struct_span_err( + sess.create_err(AsmOptionMustBeCombinedWithEither { + option: "pure", + left: "nomem", + right: "readonly", spans, - "the `pure` option must be combined with either `nomem` or `readonly`", - ) + }) .emit(); } @@ -303,15 +294,10 @@ pub fn parse_asm_args<'a>( } } if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output { - diag.struct_span_err( - args.options_spans.clone(), - "asm with the `pure` option must have at least one output", - ) - .emit(); + sess.create_err(AsmOptionPureNeedsOneOutput { spans: args.options_spans.clone() }).emit(); } 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 = sess.create_err(AsmOptionNoreturnWithOutputs { spans: outputs_sp }); // Bail out now since this is likely to confuse MIR return Err(err); @@ -319,24 +305,20 @@ pub fn parse_asm_args<'a>( 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 = sess.create_err(AsmCannotBeUsedWith { + left: "clobber_abi", + right: "global_asm!", + 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") + sess.create_err(AsmClobberAbiNeedsExplicitRegisters { + spans: regclass_outputs, + abi_spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(), + }) .emit(); } } @@ -349,25 +331,13 @@ 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<'a>(p: &mut Parser<'a>, 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(); + + p.sess.create_err(AsmDuplicateOption { symbol, span, full_span }).emit(); } /// Try to set the provided option in the provided `AsmArgs`. @@ -439,11 +409,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, p.expect(&token::OpenDelim(Delimiter::Parenthesis))?; if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { - let err = p.sess.span_diagnostic.struct_span_err( - p.token.span, - "at least one abi must be provided as an argument to `clobber_abi`", - ); - return Err(err); + return Err(p.sess.create_err(AsmClobberAbiNeedsAnAbi { span: p.token.span })); } let mut new_abis = Vec::new(); @@ -458,10 +424,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, break; } let span = opt_lit.map_or(p.token.span, |lit| lit.span); - let mut err = - p.sess.span_diagnostic.struct_span_err(span, "expected string literal"); - err.span_label(span, "not a string literal"); - return Err(err); + return Err(p.sess.create_err(AsmExpectedStringLiteral { span })); } }; @@ -475,12 +438,10 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, let full_span = span_start.to(p.prev_token.span); if !args.options_spans.is_empty() { - let mut err = p - .sess - .span_diagnostic - .struct_span_err(full_span, "clobber_abi is not allowed after options"); - err.span_labels(args.options_spans.clone(), "options"); - return Err(err); + return Err(p.sess.create_err(AsmClobberAbiAfterOptions { + span: full_span, + options_spans: args.options_spans.clone(), + })); } match &new_abis[..] { @@ -509,9 +470,9 @@ fn parse_reg<'a>( ast::InlineAsmRegOrRegClass::Reg(symbol) } _ => { - return Err( - p.struct_span_err(p.token.span, "expected register class or explicit register") - ); + return Err(p + .sess + .create_err(AsmExpectedRegisterClassOrExplicitRegister { span: p.token.span })); } }; p.bump(); @@ -706,13 +667,12 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option Some(idx), None => { - let msg = format!("there is no argument named `{}`", name); let span = arg.position_span; - ecx.struct_span_err( - template_span + ecx.create_err(AsmNoArgumentNamed { + name: name.to_owned(), + span: template_span .from_inner(InnerSpan::new(span.start, span.end)), - &msg, - ) + }) .emit(); None } @@ -728,11 +688,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_args_named_after_explicit_register)] +pub(crate) struct AsmArgsNamedAfterExplicitRegister { + #[primary_span] + #[label] + pub(crate) span: Span, + #[label(builtin_macros::register_label)] + pub(crate) register_spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_args_positional_after_named_or_explicit_register)] +pub(crate) struct AsmArgsPositionalAfterNamedOrExplicitRegister { + #[primary_span] + #[label] + pub(crate) span: Span, + #[label(builtin_macros::named_label)] + pub(crate) named_spans: Vec, + #[label(builtin_macros::register_label)] + pub(crate) register_spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_cannot_be_used_with)] +pub(crate) struct AsmCannotBeUsedWith { + pub(crate) left: &'static str, + pub(crate) right: &'static str, + #[primary_span] + pub(crate) spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_clobber_abi_after_options)] +pub(crate) struct AsmClobberAbiAfterOptions { + #[primary_span] + pub(crate) span: Span, + #[label(builtin_macros::options_label)] + pub(crate) options_spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_clobber_abi_needs_an_abi)] +pub(crate) struct AsmClobberAbiNeedsAnAbi { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_clobber_abi_needs_explicit_registers)] +pub(crate) struct AsmClobberAbiNeedsExplicitRegisters { + #[primary_span] + #[label] + pub(crate) spans: Vec, + #[label(builtin_macros::abi_label)] + pub(crate) abi_spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_duplicate_argument)] +pub(crate) struct AsmDuplicateArgument { + pub(crate) name: Symbol, + #[primary_span] + #[label] + pub(crate) span: Span, + #[label(builtin_macros::previously_label)] + pub(crate) prev_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_duplicate_option)] +pub(crate) struct AsmDuplicateOption { + pub(crate) symbol: Symbol, + #[primary_span] + #[label] + pub(crate) span: Span, + // TODO: This should be a `tool_only_span_suggestion` + #[suggestion(code = "", applicability = "machine-applicable")] + pub(crate) full_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_expected_operand_options_or_template_string)] +pub(crate) struct AsmExpectedOperandOptionsOrTemplateString { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_expected_operand_clobber_abi_options_or_template_string)] +pub(crate) struct AsmExpectedOperandClobberAbiOptionsOrTemplateString { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_expected_path_arg_to_sym)] +pub(crate) struct AsmExpectedPathArgToSym { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_expected_register_class_or_explicit_register)] +pub(crate) struct AsmExpectedRegisterClassOrExplicitRegister { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_expected_string_literal)] +pub(crate) struct AsmExpectedStringLiteral { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_expected_token_comma)] +pub(crate) struct AsmExpectedTokenComma { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_explicit_register_arg_with_name)] +pub(crate) struct AsmExplicitRegisterArgWithName { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_no_argument_named)] +pub(crate) struct AsmNoArgumentNamed { + pub(crate) name: String, + #[primary_span] + pub(crate) span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_option_must_be_combined_with_either)] +pub(crate) struct AsmOptionMustBeCombinedWithEither { + pub(crate) option: &'static str, + pub(crate) left: &'static str, + pub(crate) right: &'static str, + #[primary_span] + pub(crate) spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_option_noreturn_with_outputs)] +pub(crate) struct AsmOptionNoreturnWithOutputs { + #[primary_span] + pub(crate) spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_option_pure_needs_one_output)] +pub(crate) struct AsmOptionPureNeedsOneOutput { + #[primary_span] + pub(crate) spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_options_mutually_exclusive)] +pub(crate) struct AsmOptionsMutuallyExclusive { + pub(crate) left: &'static str, + pub(crate) right: &'static str, + #[primary_span] + pub(crate) spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_requires_template_string_arg)] +pub(crate) struct AsmRequiresTemplateStringArg { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_template_modifier_single_char)] +pub(crate) struct AsmTemplateModifierSingleChar { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::asm_underscore_for_input_operands)] +pub(crate) struct AsmUnderscoreForInputOperands { + #[primary_span] + pub(crate) span: Span, +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 280fa70451141..6401f1d56c601 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -37,6 +37,7 @@ mod derive; mod deriving; mod edition_panic; mod env; +mod errors; mod format; mod format_foreign; mod global_allocator; diff --git a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl index 4d088e27b364a..7f698dc4d2e8e 100644 --- a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl +++ b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl @@ -1,3 +1,91 @@ +builtin_macros_asm_args_after_clobber_abi = + arguments are not allowed after clobber_abi + .label = argument + .abi_label = clobber_abi + +builtin_macros_asm_args_after_options = + arguments are not allowed after options + .label = argument + .previous_options_label = previous options + +builtin_macros_asm_args_named_after_explicit_register = + named arguments cannot follow explicit register arguments + .label = named argument + .register_label = explicit register argument + +builtin_macros_asm_args_positional_after_named_or_explicit_register = + positional arguments cannot follow named arguments or explicit register arguments + .label = positional argument + .named_label = named argument + .register_label = explicit register argument + +builtin_macros_asm_cannot_be_used_with = `{$left}` cannot be used with `{$right}` + +builtin_macros_asm_clobber_abi_after_options = + clobber_abi is not allowed after options + .options_label = options + +builtin_macros_asm_clobber_abi_needs_an_abi = + at least one abi must be provided as an argument to `clobber_abi` + +builtin_macros_asm_clobber_abi_needs_explicit_registers = + asm with `clobber_abi` must specify explicit registers for outputs + .label = generic outputs + .abi_label = clobber_abi + +builtin_macros_asm_duplicate_argument = + duplicate argument named `{$name}` + .label = duplicate argument + .previously_label = previously here + +builtin_macros_asm_duplicate_option = + the `{$symbol}` option was already provided + .label = this option was already provided + .suggestion = remove this option + +builtin_macros_asm_expected_operand_options_or_template_string = + expected operand, options, or additional template string + .label = expected operand, options, or additional template string + +builtin_macros_asm_expected_operand_clobber_abi_options_or_template_string = + expected operand, clobber_abi, options, or additional template string + .label = expected operand, clobber_abi, options, or additional template string + +builtin_macros_asm_expected_path_arg_to_sym = expected a path for argument to `sym` + +builtin_macros_asm_expected_register_class_or_explicit_register = + expected register class or explicit register + +builtin_macros_asm_expected_string_literal = + expected string literal + .label = not a string literal + +builtin_macros_asm_expected_token_comma = + expected token: `,` + .label = expected `,` + +builtin_macros_asm_explicit_register_arg_with_name = explicit register arguments cannot have names + +builtin_macros_asm_no_argument_named = there is no argument named `{$name}` + +builtin_macros_asm_option_must_be_combined_with_either = + the `{$option}` option must be combined with either `{$left}` or `{$right}` + +builtin_macros_asm_option_noreturn_with_outputs = + asm outputs are not allowed with the `noreturn` option + +builtin_macros_asm_option_pure_needs_one_output = + asm with the `pure` option must have at least one output + +builtin_macros_asm_options_mutually_exclusive = + the `{$left}` and `${right}` options are mutually exclusive + +builtin_macros_asm_requires_template_string_arg = requires at least a template string argument + +builtin_macros_asm_template_modifier_single_char = asm template modifier must be a single character + +builtin_macros_asm_underscore_for_input_operands = _ cannot be used for input operands + builtin_macros_requires_cfg_pattern = macro requires a cfg-pattern as an argument .label = cfg-pattern required From dd32ec14fc32fb53b7264628fd7e6736d8860924 Mon Sep 17 00:00:00 2001 From: Wonchul Lee Date: Wed, 24 Aug 2022 06:39:47 +0900 Subject: [PATCH 2/2] Migrate rustc_builtin_macros to SessionDiagnostic --- compiler/rustc_builtin_macros/src/assert.rs | 33 +- .../src/cfg_accessible.rs | 21 +- .../rustc_builtin_macros/src/compile_error.rs | 4 +- compiler/rustc_builtin_macros/src/concat.rs | 8 +- .../rustc_builtin_macros/src/concat_bytes.rs | 90 ++-- .../rustc_builtin_macros/src/concat_idents.rs | 8 +- compiler/rustc_builtin_macros/src/derive.rs | 21 +- .../src/deriving/default.rs | 129 +++--- .../src/deriving/generic/mod.rs | 5 +- compiler/rustc_builtin_macros/src/env.rs | 8 +- compiler/rustc_builtin_macros/src/errors.rs | 408 +++++++++++++++++- compiler/rustc_builtin_macros/src/format.rs | 26 +- compiler/rustc_builtin_macros/src/lib.rs | 2 + .../locales/en-US/builtin_macros.ftl | 135 ++++++ 14 files changed, 698 insertions(+), 200 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 119724b50493e..9d514a3b65745 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -1,12 +1,13 @@ mod context; use crate::edition_panic::use_panic_2021; +use crate::errors::{self, ArgumentExpressionRequired}; use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{Expr, ExprKind, MacArgs, MacCall, MacDelimiter, Path, PathSegment, UnOp}; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::PResult; use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult}; use rustc_parse::parser::Parser; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -113,9 +114,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes let mut parser = cx.new_parser_from_tts(stream); if parser.token == token::Eof { - let mut err = cx.struct_span_err(sp, "macro requires a boolean expression as an argument"); - err.span_label(sp, "boolean expression required"); - return Err(err); + return Err(cx.create_err(errors::BooleanExpressionRequired { span: sp })); } let cond_expr = parser.parse_expr()?; @@ -128,14 +127,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes // // Emit an error about semicolon and suggest removing it. if parser.token == token::Semi { - let mut err = cx.struct_span_err(sp, "macro requires an expression as an argument"); - err.span_suggestion( - parser.token.span, - "try removing semicolon", - "", - Applicability::MaybeIncorrect, - ); - err.emit(); + cx.emit_err(ArgumentExpressionRequired { span: sp }); parser.bump(); } @@ -148,16 +140,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes // Emit an error and suggest inserting a comma. let custom_message = if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind { - let mut err = cx.struct_span_err(parser.token.span, "unexpected string literal"); - let comma_span = parser.prev_token.span.shrink_to_hi(); - err.span_suggestion_short( - comma_span, - "try adding a comma", - ", ", - Applicability::MaybeIncorrect, - ); - err.emit(); - + cx.sess.emit_err(errors::UnexpectedStringLiteral { span: parser.token.span }); parse_custom_message(&mut parser) } else if parser.eat(&token::Comma) { parse_custom_message(&mut parser) @@ -174,5 +157,9 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes fn parse_custom_message(parser: &mut Parser<'_>) -> Option { let ts = parser.parse_tokens(); - if !ts.is_empty() { Some(ts) } else { None } + if !ts.is_empty() { + Some(ts) + } else { + None + } } diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index cb5359dd1e27e..84484b13ec3c5 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -7,18 +7,29 @@ use rustc_parse::validate_attr; use rustc_span::symbol::sym; use rustc_span::Span; +use crate::errors::{ + MultiplePathsSpecified, NondeterministicAccess, NotSpecified, UnacceptedArguments, + UnallowedLiteralPath, +}; + pub(crate) struct Expander; fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> { match mi.meta_item_list() { None => {} - Some([]) => ecx.span_err(mi.span, "`cfg_accessible` path is not specified"), - Some([_, .., l]) => ecx.span_err(l.span(), "multiple `cfg_accessible` paths are specified"), + Some([]) => { + ecx.emit_err(NotSpecified { span: mi.span }); + } + Some([_, .., l]) => { + ecx.emit_err(MultiplePathsSpecified { span: l.span() }); + } Some([nmi]) => match nmi.meta_item() { - None => ecx.span_err(nmi.span(), "`cfg_accessible` path cannot be a literal"), + None => { + ecx.emit_err(UnallowedLiteralPath { span: nmi.span() }); + } Some(mi) => { if !mi.is_word() { - ecx.span_err(mi.span, "`cfg_accessible` path cannot accept arguments"); + ecx.emit_err(UnacceptedArguments { span: mi.span }); } return Some(&mi.path); } @@ -52,7 +63,7 @@ impl MultiItemModifier for Expander { Ok(true) => ExpandResult::Ready(vec![item]), Ok(false) => ExpandResult::Ready(Vec::new()), Err(Indeterminate) if ecx.force_mode => { - ecx.span_err(span, "cannot determine whether the path is accessible or not"); + ecx.emit_err(NondeterministicAccess { span }); ExpandResult::Ready(vec![item]) } Err(Indeterminate) => ExpandResult::Retry(item), diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index 72397aa2500f9..20ef85e81c677 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -4,6 +4,8 @@ use rustc_ast::tokenstream::TokenStream; use rustc_expand::base::{self, *}; use rustc_span::Span; +use crate::errors::CompileError; + pub fn expand_compile_error<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, @@ -13,7 +15,7 @@ pub fn expand_compile_error<'cx>( return DummyResult::any(sp); }; - cx.span_err(sp, var.as_str()); + cx.emit_err(CompileError { span: sp, msg: var.as_str().to_owned() }); DummyResult::any(sp) } diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index 41f4e8c234d5a..00a81622e557b 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -5,6 +5,8 @@ use rustc_span::symbol::Symbol; use std::string::String; +use crate::errors::{ByteStringLiteralConcatenate, MissingLiteral}; + pub fn expand_concat( cx: &mut base::ExtCtxt<'_>, sp: rustc_span::Span, @@ -37,7 +39,7 @@ pub fn expand_concat( accumulator.push_str(&b.to_string()); } ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..) => { - cx.span_err(e.span, "cannot concatenate a byte string literal"); + cx.emit_err(ByteStringLiteralConcatenate { span: e.span }); } ast::LitKind::Err => { has_errors = true; @@ -52,9 +54,7 @@ pub fn expand_concat( } } if !missing_literal.is_empty() { - let mut err = cx.struct_span_err(missing_literal, "expected a literal"); - err.note("only literals (like `\"foo\"`, `42` and `3.14`) can be passed to `concat!()`"); - err.emit(); + cx.emit_err(MissingLiteral { span: sp }); return DummyResult::any(sp); } else if has_errors { return DummyResult::any(sp); diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 66e86bf218267..f6acf305cd51f 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,8 +1,14 @@ use rustc_ast as ast; use rustc_ast::{ptr::P, tokenstream::TokenStream}; -use rustc_errors::Applicability; use rustc_expand::base::{self, DummyResult}; +use crate::errors::{ + BooleanLiteralsConcatenate, ByteLiteralExpected, CharacterLiteralsConcatenate, + DoublyNestedArrayConcatenate, FloatLiteralsConcatenate, InvalidNumericLiteral, + InvalidRepeatCount, NumericLiteralsConcatenate, OutOfBoundNumericLiteral, Snippet, + StringLiteralsConcatenate, +}; + /// Emits errors for literal expressions that are invalid inside and outside of an array. fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_nested: bool) { let ast::ExprKind::Lit(lit) = &expr.kind else { @@ -10,60 +16,49 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_ne }; match lit.kind { ast::LitKind::Char(_) => { - let mut err = cx.struct_span_err(expr.span, "cannot concatenate character literals"); - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { - err.span_suggestion( - expr.span, - "try using a byte character", - format!("b{}", snippet), - Applicability::MachineApplicable, - ) - .emit(); - } + let sub = cx + .sess + .source_map() + .span_to_snippet(expr.span) + .ok() + .map(|s| Snippet::ByteCharacter { span: expr.span, snippet: s }); + cx.emit_err(CharacterLiteralsConcatenate { span: expr.span, sub }); } ast::LitKind::Str(_, _) => { - let mut err = cx.struct_span_err(expr.span, "cannot concatenate string literals"); // suggestion would be invalid if we are nested - if !is_nested { - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { - err.span_suggestion( - expr.span, - "try using a byte string", - format!("b{}", snippet), - Applicability::MachineApplicable, - ); - } - } - err.emit(); + let sub = if !is_nested { + cx.sess + .source_map() + .span_to_snippet(expr.span) + .ok() + .map(|s| Snippet::ByteString { span: expr.span, snippet: s }) + } else { + None + }; + cx.emit_err(StringLiteralsConcatenate { span: expr.span, sub }); } ast::LitKind::Float(_, _) => { - cx.span_err(expr.span, "cannot concatenate float literals"); + cx.emit_err(FloatLiteralsConcatenate { span: expr.span }); } ast::LitKind::Bool(_) => { - cx.span_err(expr.span, "cannot concatenate boolean literals"); + cx.emit_err(BooleanLiteralsConcatenate { span: expr.span }); } ast::LitKind::Err => {} ast::LitKind::Int(_, _) if !is_nested => { - let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals"); - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { - err.span_suggestion( - expr.span, - "try wrapping the number in an array", - format!("[{}]", snippet), - Applicability::MachineApplicable, - ); - } - err.emit(); + let sub = cx.sess.source_map().span_to_snippet(expr.span).ok().map(|s| { + Snippet::WrappingNumberInArray { span: expr.span, snippet: format!("[{}]", s) } + }); + cx.emit_err(NumericLiteralsConcatenate { span: expr.span, sub }); } ast::LitKind::Int( val, ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), ) => { assert!(val > u8::MAX.into()); // must be an error - cx.span_err(expr.span, "numeric literal is out of bounds"); + cx.emit_err(OutOfBoundNumericLiteral { span: expr.span }); } ast::LitKind::Int(_, _) => { - cx.span_err(expr.span, "numeric literal is not a `u8`"); + cx.emit_err(InvalidNumericLiteral { span: expr.span }); } _ => unreachable!(), } @@ -78,7 +73,11 @@ fn handle_array_element( match expr.kind { ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => { if !*has_errors { - cx.span_err(expr.span, "cannot concatenate doubly nested array"); + cx.emit_err(DoublyNestedArrayConcatenate { + span: expr.span, + note: None, + help: None, + }); } *has_errors = true; None @@ -92,10 +91,11 @@ fn handle_array_element( ast::LitKind::Byte(val) => Some(val), ast::LitKind::ByteStr(_) => { if !*has_errors { - cx.struct_span_err(expr.span, "cannot concatenate doubly nested array") - .note("byte strings are treated as arrays of bytes") - .help("try flattening the array") - .emit(); + cx.emit_err(DoublyNestedArrayConcatenate { + span: expr.span, + note: Some(()), + help: Some(()), + }); } *has_errors = true; None @@ -150,7 +150,7 @@ pub fn expand_concat_bytes( } } } else { - cx.span_err(count.value.span, "repeat count is not a positive number"); + cx.emit_err(InvalidRepeatCount { span: count.value.span }); } } ast::ExprKind::Lit(ref lit) => match lit.kind { @@ -176,9 +176,7 @@ pub fn expand_concat_bytes( } } if !missing_literals.is_empty() { - let mut err = cx.struct_span_err(missing_literals.clone(), "expected a byte literal"); - err.note("only byte literals (like `b\"foo\"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`"); - err.emit(); + cx.emit_err(ByteLiteralExpected { spans: missing_literals.clone() }); return base::MacEager::expr(DummyResult::raw_expr(sp, true)); } else if has_errors { return base::MacEager::expr(DummyResult::raw_expr(sp, true)); diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 297c604e02043..86a37c9a4c0a8 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -6,13 +6,15 @@ use rustc_expand::base::{self, *}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; +use crate::errors::{CommaExpected, IdentArgsRequired, MissingArguments}; + pub fn expand_concat_idents<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, ) -> Box { if tts.is_empty() { - cx.span_err(sp, "concat_idents! takes 1 or more arguments"); + cx.emit_err(MissingArguments { span: sp }); return DummyResult::any(sp); } @@ -22,7 +24,7 @@ pub fn expand_concat_idents<'cx>( match e { TokenTree::Token(Token { kind: token::Comma, .. }, _) => {} _ => { - cx.span_err(sp, "concat_idents! expecting comma"); + cx.emit_err(CommaExpected { span: sp }); return DummyResult::any(sp); } } @@ -34,7 +36,7 @@ pub fn expand_concat_idents<'cx>( } } - cx.span_err(sp, "concat_idents! requires ident args"); + cx.emit_err(IdentArgsRequired { span: sp }); return DummyResult::any(sp); } } diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 467ac34ded942..e583c91e8f008 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,8 +1,8 @@ use crate::cfg_eval::cfg_eval; +use crate::errors::{NotApplicableDerive, PathRejected, TraitPathExpected}; use rustc_ast as ast; use rustc_ast::{attr, token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; -use rustc_errors::{struct_span_err, Applicability}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; use rustc_parse::validate_attr; @@ -112,15 +112,7 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool { let bad_target = !matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..))); if bad_target { - struct_span_err!( - sess, - span, - E0774, - "`derive` may only be applied to `struct`s, `enum`s and `union`s", - ) - .span_label(span, "not applicable here") - .span_label(item.span(), "not a `struct`, `enum` or `union`") - .emit(); + sess.emit_err(NotApplicableDerive { span, item_span: item.span() }); } bad_target } @@ -132,18 +124,13 @@ fn report_unexpected_literal(sess: &Session, lit: &ast::Lit) { } _ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(), }; - struct_span_err!(sess, lit.span, E0777, "expected path to a trait, found literal",) - .span_label(lit.span, "not a trait") - .help(&help_msg) - .emit(); + sess.emit_err(TraitPathExpected { span: lit.span, help_msg: &help_msg }); } fn report_path_args(sess: &Session, meta: &ast::MetaItem) { let report_error = |title, action| { let span = meta.span.with_lo(meta.path.span.hi()); - sess.struct_span_err(span, title) - .span_suggestion(span, action, "", Applicability::MachineApplicable) - .emit(); + sess.emit_err(PathRejected { span, title, action }); }; match meta.kind { MetaItemKind::Word => {} diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index a94c8a996e642..3c23bae908e7b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,8 +1,12 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; +use crate::errors::{ + DefaultNonExhaustive, DefaultNotAcceptValue, DefaultNotAllowed, MultipleDeclaredDefaults, + MultipleDeclaredDefaultsSuggestion, MultipleDefaultAttributes, + MultipleDefaultAttributesSuggestions, NoDefault, NoDefaultSuggestion, +}; use rustc_ast as ast; use rustc_ast::{walk_list, EnumDef, VariantData}; -use rustc_errors::Applicability; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::symbol::Ident; use rustc_span::symbol::{kw, sym}; @@ -119,68 +123,52 @@ fn extract_default_variant<'a>( .filter(|variant| matches!(variant.data, VariantData::Unit(..))) .filter(|variant| !cx.sess.contains_name(&variant.attrs, sym::non_exhaustive)); - let mut diag = cx.struct_span_err(trait_span, "no default declared"); - diag.help("make a unit variant default by placing `#[default]` above it"); - for variant in possible_defaults { - // Suggest making each unit variant default. - diag.tool_only_span_suggestion( - variant.span, - &format!("make `{}` default", variant.ident), - format!("#[default] {}", variant.ident), - Applicability::MaybeIncorrect, - ); - } - diag.emit(); - + cx.emit_err(NoDefault { + span: trait_span, + suggestions: possible_defaults + .map(|variant| NoDefaultSuggestion { span: variant.span, ident: variant.ident }) + .collect(), + }); return Err(()); } [first, rest @ ..] => { - let mut diag = cx.struct_span_err(trait_span, "multiple declared defaults"); - diag.span_label(first.span, "first default"); - diag.span_labels(rest.iter().map(|variant| variant.span), "additional default"); - diag.note("only one variant can be default"); - for variant in &default_variants { - // Suggest making each variant already tagged default. - let suggestion = default_variants - .iter() - .filter_map(|v| { - if v.ident == variant.ident { - None - } else { - Some((cx.sess.find_by_name(&v.attrs, kw::Default)?.span, String::new())) - } - }) - .collect(); - - diag.tool_only_multipart_suggestion( - &format!("make `{}` default", variant.ident), - suggestion, - Applicability::MaybeIncorrect, - ); - } - diag.emit(); + let suggestions = default_variants + .iter() + .map(|variant| { + let suggestion = default_variants + .iter() + .filter_map(|v| { + if v.ident == variant.ident { + None + } else { + Some(cx.sess.find_by_name(&v.attrs, kw::Default)?.span) + } + }) + .collect::>(); + MultipleDeclaredDefaultsSuggestion { span: suggestion } + }) + .collect(); + cx.emit_err(MultipleDeclaredDefaults { + span: trait_span, + first: first.span, + variants: rest.iter().map(|variant| variant.span).collect(), + suggestions, + }); return Err(()); } }; if !matches!(variant.data, VariantData::Unit(..)) { - cx.struct_span_err( - variant.ident.span, - "the `#[default]` attribute may only be used on unit enum variants", - ) - .help("consider a manual implementation of `Default`") - .emit(); - + cx.emit_err(DefaultNotAllowed { span: variant.ident.span, help: None }); return Err(()); } if let Some(non_exhaustive_attr) = cx.sess.find_by_name(&variant.attrs, sym::non_exhaustive) { - cx.struct_span_err(variant.ident.span, "default variant must be exhaustive") - .span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here") - .help("consider a manual implementation of `Default`") - .emit(); - + cx.emit_err(DefaultNonExhaustive { + span: variant.ident.span, + non_exhustive_attr: non_exhaustive_attr.span, + }); return Err(()); } @@ -203,33 +191,21 @@ fn validate_default_attribute( let suggestion_text = if rest.len() == 1 { "try removing this" } else { "try removing these" }; - cx.struct_span_err(default_variant.ident.span, "multiple `#[default]` attributes") - .note("only one `#[default]` attribute is needed") - .span_label(first.span, "`#[default]` used here") - .span_label(rest[0].span, "`#[default]` used again here") - .span_help(rest.iter().map(|attr| attr.span).collect::>(), suggestion_text) - // This would otherwise display the empty replacement, hence the otherwise - // repetitive `.span_help` call above. - .tool_only_multipart_suggestion( - suggestion_text, - rest.iter().map(|attr| (attr.span, String::new())).collect(), - Applicability::MachineApplicable, - ) - .emit(); - + cx.emit_err(MultipleDefaultAttributes { + span: default_variant.ident.span, + first: first.span, + rest: rest[0].span, + help: rest.iter().map(|attr| attr.span).collect::>(), + suggestion_text, + suggestions: MultipleDefaultAttributesSuggestions { + span: rest.iter().map(|attr| attr.span).collect(), + }, + }); return Err(()); } }; if !attr.is_word() { - cx.struct_span_err(attr.span, "`#[default]` attribute does not accept a value") - .span_suggestion_hidden( - attr.span, - "try using `#[default]`", - "#[default]", - Applicability::MaybeIncorrect, - ) - .emit(); - + cx.emit_err(DefaultNotAcceptValue { span: attr.span }); return Err(()); } Ok(()) @@ -242,12 +218,7 @@ struct DetectNonVariantDefaultAttr<'a, 'b> { impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> { fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) { if attr.has_name(kw::Default) { - self.cx - .struct_span_err( - attr.span, - "the `#[default]` attribute may only be used on unit enum variants", - ) - .emit(); + self.cx.emit_err(DefaultNotAllowed { span: attr.span, help: Some(()) }); } rustc_ast::visit::walk_attribute(self, attr); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 3cc160adb5397..c73cb266fd075 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -163,6 +163,7 @@ pub use StaticFields::*; pub use SubstructureFields::*; use crate::deriving; +use crate::errors::{CannotBeDerivedUnions, UnallowedDerive}; use rustc_ast::ptr::P; use rustc_ast::{ self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind, @@ -391,7 +392,7 @@ fn find_type_parameters( } fn visit_mac_call(&mut self, mac: &ast::MacCall) { - self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros"); + self.cx.emit_err(UnallowedDerive { span: mac.span() }); } } @@ -478,7 +479,7 @@ impl<'a> TraitDef<'a> { always_copy, ) } else { - cx.span_err(mitem.span, "this trait cannot be derived for unions"); + cx.emit_err(CannotBeDerivedUnions { span: mitem.span }); return; } } diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index b8828fa671a5d..64696a56cb489 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -11,6 +11,8 @@ use rustc_span::Span; use std::env; +use crate::errors::{EmptyArgument, EnvExpandError}; + pub fn expand_option_env<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, @@ -54,7 +56,7 @@ pub fn expand_env<'cx>( ) -> Box { let mut exprs = match get_exprs_from_tts(cx, sp, tts) { Some(ref exprs) if exprs.is_empty() => { - cx.span_err(sp, "env! takes 1 or 2 arguments"); + cx.emit_err(EmptyArgument { span: sp }); return DummyResult::any(sp); } None => return DummyResult::any(sp), @@ -73,7 +75,7 @@ pub fn expand_env<'cx>( }; if exprs.next().is_some() { - cx.span_err(sp, "env! takes 1 or 2 arguments"); + cx.emit_err(EmptyArgument { span: sp }); return DummyResult::any(sp); } @@ -82,7 +84,7 @@ pub fn expand_env<'cx>( cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { - cx.span_err(sp, msg.as_str()); + cx.emit_err(EnvExpandError { span: sp, msg: msg.as_str() }); return DummyResult::any(sp); } Some(value) => cx.expr_str(sp, value), diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 03446bc6ea4c5..481f06c3ed6db 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,5 +1,6 @@ -use rustc_macros::SessionDiagnostic; -use rustc_span::{Span, Symbol}; +use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic}; +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(SessionDiagnostic)] #[diag(builtin_macros::asm_args_after_clobber_abi)] @@ -97,7 +98,7 @@ pub(crate) struct AsmDuplicateOption { #[primary_span] #[label] pub(crate) span: Span, - // TODO: This should be a `tool_only_span_suggestion` + // FIXME: This should be a `tool_only_span_suggestion` #[suggestion(code = "", applicability = "machine-applicable")] pub(crate) full_span: Span, } @@ -216,3 +217,404 @@ pub(crate) struct AsmUnderscoreForInputOperands { #[primary_span] pub(crate) span: Span, } + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::boolean_expression_required)] +pub struct BooleanExpressionRequired { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::unexpected_string_literal)] +pub struct UnexpectedStringLiteral { + #[primary_span] + #[suggestion_short(code = ", ", applicability = "maybe-incorrect")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::argument_expression_required)] +pub struct ArgumentExpressionRequired { + #[primary_span] + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::not_specified)] +pub struct NotSpecified { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::multiple_paths_specified)] +pub struct MultiplePathsSpecified { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::unallowed_literal_path)] +pub struct UnallowedLiteralPath { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::unaccepted_arguments)] +pub struct UnacceptedArguments { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::nondeterministic_access)] +pub struct NondeterministicAccess { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::compile_error)] +pub struct CompileError { + #[primary_span] + pub span: Span, + pub msg: String, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::byte_string_literal_concatenate)] +pub struct ByteStringLiteralConcatenate { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::missing_literal)] +#[note] +pub struct MissingLiteral { + #[primary_span] + pub span: Span, +} + +pub enum Snippet { + ByteCharacter { span: Span, snippet: String }, + ByteString { span: Span, snippet: String }, + WrappingNumberInArray { span: Span, snippet: String }, +} + +impl AddSubdiagnostic for Snippet { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + match self { + Self::ByteCharacter { span, snippet } => { + diag.span_suggestion( + span, + fluent::builtin_macros::use_byte_character, + snippet, + Applicability::MachineApplicable, + ); + } + Self::ByteString { span, snippet } => { + diag.span_suggestion( + span, + fluent::builtin_macros::use_byte_string, + snippet, + Applicability::MachineApplicable, + ); + } + Self::WrappingNumberInArray { span, snippet } => { + diag.span_suggestion( + span, + fluent::builtin_macros::wrap_number_in_array, + snippet, + Applicability::MachineApplicable, + ); + } + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::character_literals_concatenate)] +pub struct CharacterLiteralsConcatenate { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: Option, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::string_literals_concatenate)] +pub struct StringLiteralsConcatenate { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: Option, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::float_literals_concatenate)] +pub struct FloatLiteralsConcatenate { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::boolean_literals_concatenate)] +pub struct BooleanLiteralsConcatenate { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::numeric_literals_concatenate)] +pub struct NumericLiteralsConcatenate { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: Option, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::out_of_bound_numeric_literal)] +pub struct OutOfBoundNumericLiteral { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::invalid_numeric_literal)] +pub struct InvalidNumericLiteral { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::doubly_nested_array_concatenate)] +pub struct DoublyNestedArrayConcatenate { + #[primary_span] + pub span: Span, + #[note] + pub note: Option<()>, + #[help] + pub help: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::invalid_repeat_count)] +pub struct InvalidRepeatCount { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[note] +#[diag(builtin_macros::byte_literal_expected)] +pub struct ByteLiteralExpected { + #[primary_span] + pub spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::missing_arguments)] +pub struct MissingArguments { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::comma_expected)] +pub struct CommaExpected { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::ident_args_required)] +pub struct IdentArgsRequired { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::not_applicable_derive, code = "E0774")] +pub struct NotApplicableDerive { + #[primary_span] + #[label] + pub span: Span, + #[label(builtin_macros::item_label)] + pub item_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::trait_path_expected, code = "E0777")] +pub struct TraitPathExpected<'a> { + #[primary_span] + #[label] + pub span: Span, + pub help_msg: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::path_rejected)] +pub struct PathRejected<'a> { + #[primary_span] + #[label] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, + pub title: &'a str, + pub action: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::no_default)] +pub struct NoDefault { + #[primary_span] + pub span: Span, + // FIXME: This should be a `tool_only_span_suggestion` + #[subdiagnostic] + pub suggestions: Vec, +} + +#[derive(SessionSubdiagnostic)] +#[suggestion( + builtin_macros::variant_suggestion, + code = "#[default] {ident}", + applicability = "maybe-incorrect" +)] +pub struct NoDefaultSuggestion { + #[primary_span] + pub span: Span, + pub ident: Ident, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::multiple_declared_defaults)] +pub struct MultipleDeclaredDefaults { + #[primary_span] + pub span: Span, + #[label(builtin_macros::multiple_declared_defaults_first)] + pub first: Span, + #[label(builtin_macros::multiple_declared_defaults_additional)] + pub variants: Vec, + // FIXME: This should be a `tool_only_multipart_suggestion` + #[subdiagnostic] + pub suggestions: Vec, +} + +#[derive(SessionSubdiagnostic)] +#[multipart_suggestion(builtin_macros::variant_suggestion, applicability = "maybe-incorrect")] +pub struct MultipleDeclaredDefaultsSuggestion { + #[suggestion_part(code = "")] + pub span: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::default_not_allowed)] +pub struct DefaultNotAllowed { + #[primary_span] + pub span: Span, + #[help] + pub help: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::default_non_exhaustive)] +pub struct DefaultNonExhaustive { + #[primary_span] + pub span: Span, + #[label(builtin_macros::default_non_exhaustive_instruction)] + pub non_exhustive_attr: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::multiple_default_attributes)] +pub struct MultipleDefaultAttributes<'a> { + #[primary_span] + pub span: Span, + #[label(builtin_macros::multiple_default_attributes_first)] + pub first: Span, + #[label(builtin_macros::multiple_default_attributes_rest)] + pub rest: Span, + #[help(builtin_macros::multiple_default_attributes_suggestion_text)] + pub help: Vec, + pub suggestion_text: &'a str, + // FIXME: This should be a `tool_only_multipart_suggestion` + #[subdiagnostic] + pub suggestions: MultipleDefaultAttributesSuggestions, +} + +#[derive(SessionSubdiagnostic)] +#[multipart_suggestion( + builtin_macros::multiple_default_attributes_suggestion_text, + applicability = "machine-applicable" +)] +pub struct MultipleDefaultAttributesSuggestions { + #[suggestion_part(code = "")] + pub span: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::default_not_accept_value)] +pub struct DefaultNotAcceptValue { + #[primary_span] + #[suggestion_hidden(code = "#[default]", applicability = "maybe-incorrect")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::unallowed_derive)] +pub struct UnallowedDerive { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::cannot_be_derived_unions)] +pub struct CannotBeDerivedUnions { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::empty_argument)] +pub struct EmptyArgument { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::env_expand_error)] +pub struct EnvExpandError<'a> { + #[primary_span] + pub span: Span, + pub msg: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::format_string_argument_required)] +pub struct FormatStringArgumentRequired { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::duplicated_argument)] +pub struct DuplicatedArgument { + #[primary_span] + pub span: Span, + #[label(builtin_macros::multiple_default_attributes_first)] + pub prev_span: Span, + pub ident: Ident, +} + +#[derive(SessionDiagnostic)] +#[diag(builtin_macros::invalid_positional_arguments)] +pub struct InvalidPositionalArguments { + #[primary_span] + pub span: Span, + #[label(builtin_macros::invalid_positional_arguments_names)] + pub names: Vec, +} diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 2100487107517..ecbf1f8487612 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -20,6 +20,8 @@ use rustc_parse_format::Count; use std::borrow::Cow; use std::collections::hash_map::Entry; +use crate::errors::{DuplicatedArgument, FormatStringArgumentRequired, InvalidPositionalArguments}; + #[derive(PartialEq)] enum ArgumentType { Placeholder(&'static str), @@ -287,7 +289,7 @@ fn parse_args<'a>( let mut p = ecx.new_parser_from_tts(tts); if p.token == token::Eof { - return Err(ecx.struct_span_err(sp, "requires at least a format string argument")); + return Err(ecx.create_err(FormatStringArgumentRequired { span: sp })); } let first_token = &p.token; @@ -348,10 +350,11 @@ fn parse_args<'a>( p.expect(&token::Eq)?; let e = p.parse_expr()?; if let Some(&prev) = names.get(&ident.name) { - ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident)) - .span_label(args[prev].expr.span, "previously here") - .span_label(e.span, "duplicate argument") - .emit(); + ecx.emit_err(DuplicatedArgument { + span: e.span, + prev_span: args[prev].expr.span, + ident, + }); continue; } @@ -366,15 +369,10 @@ fn parse_args<'a>( _ => { let e = p.parse_expr()?; if named { - let mut err = ecx.struct_span_err( - e.span, - "positional arguments cannot follow named arguments", - ); - err.span_label(e.span, "positional arguments must be before named arguments"); - for &pos in names.values() { - err.span_label(args[pos].expr.span, "named argument"); - } - err.emit(); + ecx.emit_err(InvalidPositionalArguments { + span: e.span, + names: names.values().map(|&pos| args[pos].expr.span).collect(), + }); } args.push(FormatArg { expr: e, name: None }); } diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 6401f1d56c601..3bcfe61cb486f 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -13,6 +13,8 @@ #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] extern crate proc_macro; diff --git a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl index 7f698dc4d2e8e..485368e712071 100644 --- a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl +++ b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl @@ -91,3 +91,138 @@ builtin_macros_requires_cfg_pattern = .label = cfg-pattern required builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern + +builtin_macros_boolean_expression_required = + macro requires a boolean expression as an argument + .label = boolean expression required + +builtin_macros_unexpected_string_literal = unexpected string literal + .suggestion = try adding a comma + +builtin_macros_argument_expression_required = + macro requires an expression as an argument + .suggestion = try removing semicolon + +builtin_macros_not_specified = + `cfg_accessible` path is not specified + +builtin_macros_multiple_paths_specified = + multiple `cfg_accessible` paths are specified + +builtin_macros_unallowed_literal_path = + `cfg_accessible` path cannot be a literal + +builtin_macros_unaccepted_arguments = + `cfg_accessible` path cannot accept arguments + +builtin_macros_nondeterministic_access = + cannot determine whether the path is accessible or not + +builtin_macros_compile_error = {$msg} + +builtin_macros_byte_string_literal_concatenate = + cannot concatenate a byte string literal + +builtin_macros_missing_literal = expected a literal + .note = only literals (like `\"foo\"`, `42` and `3.14`) can be passed to `concat!()` + +builtin_macros_character_literals_concatenate = cannot concatenate character literals + +builtin_macros_string_literals_concatenate = cannot concatenate string literals + +builtin_macros_use_byte_character = try using a byte character + +builtin_macros_use_byte_string = try using a byte string + +builtin_macros_float_literals_concatenate = cannot concatenate float literals + +builtin_macros_boolean_literals_concatenate = cannot concatenate boolean literals + +builtin_macros_wrap_number_in_array = try wrapping the number in an array + +builtin_macros_numeric_literals_concatenate = cannot concatenate numeric literals + +builtin_macros_out_of_bound_numeric_literal = numeric literal is out of bounds + +builtin_macros_invalid_numeric_literal = numeric literal is not a `u8` + +builtin_macros_doubly_nested_array_concatenate = cannot concatenate doubly nested array + .note = byte strings are treated as arrays of bytes + .help = try flattening the array + +builtin_macros_invalid_repeat_count = repeat count is not a positive number + +builtin_macros_byte_literal_expected = expected a byte literal + .note = only byte literals (like `b\"foo\"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + +builtin_macros_missing_arguments = concat_idents! takes 1 or more arguments + +builtin_macros_comma_expected = concat_idents! expecting comma + +builtin_macros_ident_args_required = concat_idents! requires ident args + +builtin_macros_not_applicable_derive = + `derive` may only be applied to `struct`s, `enum`s and `union`s + .label = not applicable here + .item_label = not a `struct`, `enum` or `union` + +builtin_macros_trait_path_expected = + expected path to a trait, found literal + .label = not a trait + .help = {$help_msg} + +builtin_macros_path_rejected = {$title} + .suggestion = {$action} + +builtin_macros_no_default = no default declared + .help = make a unit variant default by placing `#[default]` above it + +builtin_macros_variant_suggestion = make `{$ident}` default + +builtin_macros_multiple_declared_defaults_first = = first default + +builtin_macros_multiple_declared_defaults_additional = additional default + +builtin_macros_multiple_declared_defaults = multiple declared defaults + .note = only one variant can be default + +builtin_macros_default_not_allowed = + the `#[default]` attribute may only be used on unit enum variants + .help = consider a manual implementation of `Default` + +builtin_macros_default_non_exhaustive = default variant must be exhaustive + .help = consider a manual implementation of `Default` + +builtin_macros_default_non_exhaustive_instruction = declared `#[non_exhaustive]` here + +builtin_macros_multiple_default_attributes_first = `#[default]` used here + +builtin_macros_multiple_default_attributes_rest = `#[default]` used again here + +builtin_macros_multiple_default_attributes_suggestion_text = {$suggestion_text} + +builtin_macros_multiple_default_attributes = multiple `#[default]` attributes + .note = only one `#[default]` attribute is needed + +builtin_macros_default_not_accept_value = `#[default]` attribute does not accept a value + .suggestion = try using `#[default]` + +builtin_macros_unallowed_derive = `derive` cannot be used on items with type macros + +builtin_macros_cannot_be_derived_unions = this trait cannot be derived for unions + +builtin_macros_empty_argument = env! takes 1 or 2 arguments + +builtin_macros_env_expand_error = {$msg} + +builtin_macros_format_string_argument_required = requires at least a format string argument + +builtin_macros_duplicated_argument = duplicate argument named `{$ident}` + .label = duplicate argument + +builtin_macros_duplicated_argument_prev = previously here + +builtin_macros_invalid_positional_arguments = positional arguments cannot follow named arguments + .label = positional arguments must be before named arguments + +builtin_macros_invalid_positional_arguments_names = named argument