diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 4d088e27b36..83dc1ac50e5 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -3,3 +3,149 @@ builtin_macros_requires_cfg_pattern = .label = cfg-pattern required builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern + +builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function + +builtin_macros_assert_requires_boolean = macro requires a boolean expression as an argument + .label = boolean expression required + +builtin_macros_assert_requires_expression = macro requires an expression as an argument + .suggestion = try removing semicolon + +builtin_macros_assert_missing_comma = unexpected string literal + .suggestion = try adding a comma + +builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified +builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified +builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a literal +builtin_macros_cfg_accessible_has_args = `cfg_accessible` path cannot accept arguments + +builtin_macros_cfg_accessible_indeterminate = cannot determine whether the path is accessible or not + +builtin_macros_concat_bytestr = cannot concatenate a byte string literal + +builtin_macros_concat_missing_literal = expected a literal + .note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()` + +builtin_macros_concat_bytes_missing_literal = 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_concat_bytes_invalid = cannot concatenate {$lit_kind} literals + .byte_char = try using a byte character + .byte_str = try using a byte string + .number_array = try wrapping the number in an array + +builtin_macros_concat_bytes_oob = numeric literal is out of bounds + +builtin_macros_concat_bytes_non_u8 = numeric literal is not a `u8` + +builtin_macros_concat_bytes_array = cannot concatenate doubly nested array + .note = byte strings are treated as arrays of bytes + .help = try flattening the array + +builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number + +builtin_macros_concat_idents_missing_args = `concat_idents!()` takes 1 or more arguments +builtin_macros_concat_idents_missing_comma = `concat_idents!()` expecting comma +builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args + +builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s + .label = not applicable here + .label2 = not a `struct`, `enum` or `union` + +builtin_macros_unexpected_lit = expected path to a trait, found literal + .label = not a trait + .str_lit = try using `#[derive({$sym})]` + .other = for example, write `#[derive(Debug)]` for `Debug` + +builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept arguments + .suggestion = remove the arguments + +builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values + .suggestion = remove the value + +builtin_macros_derive_macro_call = `derive` cannot be used on items with type macros + +builtin_macros_cannot_derive_union = this trait cannot be derived for unions + +builtin_macros_no_default_variant = no default declared + .help = make a unit variant default by placing `#[default]` above it + .suggestion = make `{$ident}` default + +builtin_macros_multiple_defaults = multiple declared defaults + .label = first default + .additional = additional default + .note = only one variant can be default + .suggestion = make `{$ident}` default + +builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants + .help = consider a manual implementation of `Default` + +builtin_macros_non_exhaustive_default = default variant must be exhaustive + .label = declared `#[non_exhaustive]` here + .help = consider a manual implementation of `Default` + +builtin_macros_multiple_default_attrs = multiple `#[default]` attributes + .note = only one `#[default]` attribute is needed + .label = `#[default]` used here + .label_again = `#[default]` used again here + .help = try removing {$only_one -> + [true] this + *[false] these + } + +builtin_macros_default_arg = `#[default]` attribute does not accept a value + .suggestion = try using `#[default]` + +builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments + +builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time + .cargo = Cargo sets build script variables at run time. Use `std::env::var("{$var}")` instead + .other = use `std::env::var("{$var}")` to read the variable at run time + +builtin_macros_format_requires_string = requires at least a format string argument + +builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}` + .label1 = previously here + .label2 = duplicate argument + +builtin_macros_format_positional_after_named = positional arguments cannot follow named arguments + .label = positional arguments must be before named arguments + .named_args = named argument + +builtin_macros_format_string_invalid = invalid format string: {$desc} + .label = {$label1} in format string + .note = {$note} + .second_label = {$label} + +builtin_macros_sugg = consider using a positional formatting argument instead + +builtin_macros_format_no_arg_named = there is no argument named `{$name}` + .note = did you intend to capture a variable `{$name}` from the surrounding scope? + .note2 = to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro + +builtin_macros_format_unknown_trait = unknown format trait `{$ty}` + .note = the only appropriate formatting traits are: + - ``, which uses the `Display` trait + - `?`, which uses the `Debug` trait + - `e`, which uses the `LowerExp` trait + - `E`, which uses the `UpperExp` trait + - `o`, which uses the `Octal` trait + - `p`, which uses the `Pointer` trait + - `b`, which uses the `Binary` trait + - `x`, which uses the `LowerHex` trait + - `X`, which uses the `UpperHex` trait + .suggestion = use the `{$trait_name}` trait + +builtin_macros_format_unused_arg = {$named -> + [true] named argument + *[false] argument + } never used + +builtin_macros_format_unused_args = multiple unused formatting arguments + .label = multiple missing formatting specifiers + +builtin_macros_format_pos_mismatch = {$n} positional {$n -> + [one] argument + *[more] arguments + } in format string, but {$desc} diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index ac6697232cb..82bae9157e7 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -1,3 +1,4 @@ +use crate::errors; use crate::util::check_builtin_macro_attribute; use rustc_ast::ptr::P; @@ -31,7 +32,7 @@ pub fn expand( { (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) } else { - ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "alloc_error_handler must be a function"); + ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocErrorMustBeFn {span: item.span() }); return vec![orig_item]; }; diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 75af5e2b1fa..0de424be2f1 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; use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{DelimArgs, Expr, ExprKind, 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}; @@ -114,9 +115,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::AssertRequiresBoolean { span: sp })); } let cond_expr = parser.parse_expr()?; @@ -129,15 +128,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(errors::AssertRequiresExpression { span: sp, token: parser.token.span }); parser.bump(); } @@ -149,15 +140,8 @@ 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(); + let comma = parser.prev_token.span.shrink_to_hi(); + cx.emit_err(errors::AssertMissingComma { span: parser.token.span, comma }); parse_custom_message(&mut parser) } else if parser.eat(&token::Comma) { diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 5638c2f6180..1397cee7af8 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -2,13 +2,13 @@ //! a literal `true` or `false` based on whether the given cfg matches the //! current compilation environment. +use crate::errors; use rustc_ast as ast; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_attr as attr; use rustc_errors::PResult; use rustc_expand::base::{self, *}; -use rustc_macros::Diagnostic; use rustc_span::Span; pub fn expand_cfg( @@ -35,26 +35,11 @@ pub fn expand_cfg( } } -#[derive(Diagnostic)] -#[diag(builtin_macros_requires_cfg_pattern)] -struct RequiresCfgPattern { - #[primary_span] - #[label] - span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_expected_one_cfg_pattern)] -struct OneCfgPattern { - #[primary_span] - span: Span, -} - fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { - return Err(cx.create_err(RequiresCfgPattern { span })); + return Err(cx.create_err(errors::RequiresCfgPattern { span })); } let cfg = p.parse_meta_item()?; @@ -62,7 +47,7 @@ fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult< let _ = p.eat(&token::Comma); if !p.eat(&token::Eof) { - return Err(cx.create_err(OneCfgPattern { span })); + return Err(cx.create_err(errors::OneCfgPattern { span })); } Ok(cfg) diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index 4e4cafc7182..37ac09ccdff 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -1,5 +1,6 @@ //! Implementation of the `#[cfg_accessible(path)]` attribute macro. +use crate::errors; use rustc_ast as ast; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; @@ -10,15 +11,22 @@ use rustc_span::Span; pub(crate) struct Expander; fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> { + use errors::CfgAccessibleInvalid::*; 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(UnspecifiedPath(mi.span)); + } + Some([_, .., l]) => { + ecx.emit_err(MultiplePaths(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(LiteralPath(nmi.span())); + } Some(mi) => { if !mi.is_word() { - ecx.span_err(mi.span, "`cfg_accessible` path cannot accept arguments"); + ecx.emit_err(HasArguments(mi.span)); } return Some(&mi.path); } @@ -53,7 +61,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(errors::CfgAccessibleIndeterminate { 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 72397aa2500..aeb3bb80045 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -13,6 +13,11 @@ pub fn expand_compile_error<'cx>( return DummyResult::any(sp); }; + #[expect( + rustc::diagnostic_outside_of_impl, + reason = "diagnostic message is specified by user" + )] + #[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")] cx.span_err(sp, var.as_str()); DummyResult::any(sp) diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index 36682bbe070..b92964d03e9 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -4,6 +4,8 @@ use rustc_expand::base::{self, DummyResult}; use rustc_session::errors::report_lit_error; use rustc_span::symbol::Symbol; +use crate::errors; + pub fn expand_concat( cx: &mut base::ExtCtxt<'_>, sp: rustc_span::Span, @@ -31,7 +33,7 @@ pub fn expand_concat( accumulator.push_str(&b.to_string()); } Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => { - cx.span_err(e.span, "cannot concatenate a byte string literal"); + cx.emit_err(errors::ConcatBytestr { span: e.span }); has_errors = true; } Ok(ast::LitKind::Err) => { @@ -55,7 +57,7 @@ pub fn expand_concat( } } ast::ExprKind::IncludedBytes(..) => { - cx.span_err(e.span, "cannot concatenate a byte string literal") + cx.emit_err(errors::ConcatBytestr { span: e.span }); } ast::ExprKind::Err => { has_errors = true; @@ -67,9 +69,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(errors::ConcatMissingLiteral { spans: missing_literal }); 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 4f1a7d709ff..ba639c0a9fe 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,10 +1,11 @@ use rustc_ast as ast; use rustc_ast::{ptr::P, tokenstream::TokenStream}; -use rustc_errors::Applicability; use rustc_expand::base::{self, DummyResult}; use rustc_session::errors::report_lit_error; use rustc_span::Span; +use crate::errors; + /// Emits errors for literal expressions that are invalid inside and outside of an array. fn invalid_type_err( cx: &mut base::ExtCtxt<'_>, @@ -12,62 +13,46 @@ fn invalid_type_err( span: Span, is_nested: bool, ) { + use errors::{ + ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob, + }; + let snippet = cx.sess.source_map().span_to_snippet(span).ok(); match ast::LitKind::from_token_lit(token_lit) { Ok(ast::LitKind::Char(_)) => { - let mut err = cx.struct_span_err(span, "cannot concatenate character literals"); - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, - "try using a byte character", - format!("b{}", snippet), - Applicability::MachineApplicable, - ) - .emit(); - } + let sugg = + snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet }); + cx.sess.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }); } Ok(ast::LitKind::Str(_, _)) => { - let mut err = cx.struct_span_err(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(span) { - err.span_suggestion( - span, - "try using a byte string", - format!("b{}", snippet), - Applicability::MachineApplicable, - ); - } - } - err.emit(); + let sugg = if !is_nested { + snippet.map(|snippet| ConcatBytesInvalidSuggestion::StrLit { span, snippet }) + } else { + None + }; + cx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }); } Ok(ast::LitKind::Float(_, _)) => { - cx.span_err(span, "cannot concatenate float literals"); + cx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }); } Ok(ast::LitKind::Bool(_)) => { - cx.span_err(span, "cannot concatenate boolean literals"); + cx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }); } Ok(ast::LitKind::Err) => {} Ok(ast::LitKind::Int(_, _)) if !is_nested => { - let mut err = cx.struct_span_err(span, "cannot concatenate numeric literals"); - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, - "try wrapping the number in an array", - format!("[{}]", snippet), - Applicability::MachineApplicable, - ); - } - err.emit(); + let sugg = + snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet }); + cx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }); } Ok(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(span, "numeric literal is out of bounds"); + cx.emit_err(ConcatBytesOob { span }); } Ok(ast::LitKind::Int(_, _)) => { - cx.span_err(span, "numeric literal is not a `u8`"); + cx.emit_err(ConcatBytesNonU8 { span }); } Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(), Err(err) => { @@ -85,7 +70,7 @@ 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(errors::ConcatBytesArray { span: expr.span, bytestr: false }); } *has_errors = true; None @@ -99,10 +84,7 @@ fn handle_array_element( Ok(ast::LitKind::Byte(val)) => Some(val), Ok(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(errors::ConcatBytesArray { span: expr.span, bytestr: true }); } *has_errors = true; None @@ -117,10 +99,7 @@ fn handle_array_element( }, ast::ExprKind::IncludedBytes(..) => { 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(errors::ConcatBytesArray { span: expr.span, bytestr: false }); } *has_errors = true; None @@ -167,7 +146,7 @@ pub fn expand_concat_bytes( } } } else { - cx.span_err(count.value.span, "repeat count is not a positive number"); + cx.emit_err(errors::ConcatBytesBadRepeat {span: count.value.span }); } } &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { @@ -196,9 +175,7 @@ pub fn expand_concat_bytes( } } if !missing_literals.is_empty() { - let mut err = cx.struct_span_err(missing_literals, "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(errors::ConcatBytesMissingLiteral { spans: missing_literals }); 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 297c604e020..8c737f04323 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; + 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(errors::ConcatIdentsMissingArgs { 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(errors::ConcatIdentsMissingComma { 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(errors::ConcatIdentsIdentArgs { 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 2a8dc02849e..fe4483104ee 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; use rustc_ast as ast; use rustc_ast::{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; @@ -116,49 +116,33 @@ 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(errors::BadDeriveTarget { span, item: item.span() }); } bad_target } fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) { - let help_msg = match lit.kind { + let help = match lit.kind { ast::LitKind::Str(_, ast::StrStyle::Cooked) if rustc_lexer::is_ident(lit.symbol.as_str()) => { - format!("try using `#[derive({})]`", lit.symbol) + errors::BadDeriveLitHelp::StrLit { sym: lit.symbol } } - _ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(), + _ => errors::BadDeriveLitHelp::Other, }; - 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(errors::BadDeriveLit { span: lit.span, help }); } 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(); - }; + let span = meta.span.with_lo(meta.path.span.hi()); + match meta.kind { MetaItemKind::Word => {} - MetaItemKind::List(..) => report_error( - "traits in `#[derive(...)]` don't accept arguments", - "remove the arguments", - ), + MetaItemKind::List(..) => { + sess.emit_err(errors::DerivePathArgsList { span }); + } MetaItemKind::NameValue(..) => { - report_error("traits in `#[derive(...)]` don't accept values", "remove the value") + sess.emit_err(errors::DerivePathArgsValue { span }); } } } diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index cc32739d083..33fe98b40e1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,8 +1,8 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; +use crate::errors; use rustc_ast as ast; use rustc_ast::{attr, 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}; @@ -118,67 +118,50 @@ fn extract_default_variant<'a>( .filter(|variant| matches!(variant.data, VariantData::Unit(..))) .filter(|variant| !attr::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(); + let suggs = possible_defaults + .map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident }) + .collect(); + cx.emit_err(errors::NoDefaultVariant { span: trait_span, suggs }); 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.span == variant.span { - None - } else { - Some((attr::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 suggs = default_variants + .iter() + .map(|variant| { + let spans = default_variants + .iter() + .filter_map(|v| { + if v.span == variant.span { + None + } else { + Some(attr::find_by_name(&v.attrs, kw::Default)?.span) + } + }) + .collect(); + errors::MultipleDefaultsSugg { spans, ident: variant.ident } + }) + .collect(); + cx.emit_err(errors::MultipleDefaults { + span: trait_span, + first: first.span, + additional: rest.iter().map(|v| v.span).collect(), + suggs, + }); 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(errors::NonUnitDefault { span: variant.ident.span }); return Err(()); } if let Some(non_exhaustive_attr) = attr::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(errors::NonExhaustiveDefault { + span: variant.ident.span, + non_exhaustive: non_exhaustive_attr.span, + }); return Err(()); } @@ -199,35 +182,23 @@ fn validate_default_attribute( "this method must only be called with a variant that has a `#[default]` attribute", ), [first, rest @ ..] => { - 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(); + let sugg = errors::MultipleDefaultAttrsSugg { + spans: rest.iter().map(|attr| attr.span).collect(), + }; + cx.emit_err(errors::MultipleDefaultAttrs { + span: default_variant.ident.span, + first: first.span, + first_rest: rest[0].span, + rest: rest.iter().map(|attr| attr.span).collect::>().into(), + only_one: rest.len() == 1, + sugg, + }); 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(errors::DefaultHasArg { span: attr.span }); return Err(()); } @@ -241,12 +212,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(errors::NonUnitDefault { span: attr.span }); } 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 6b3053fdfac..e5a00331588 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -162,7 +162,7 @@ pub use StaticFields::*; pub use SubstructureFields::*; -use crate::deriving; +use crate::{deriving, errors}; use rustc_ast::ptr::P; use rustc_ast::{ self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, @@ -415,7 +415,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(errors::DeriveMacroCall { span: mac.span() }); } } @@ -488,7 +488,7 @@ impl<'a> TraitDef<'a> { is_packed, ) } else { - cx.span_err(mitem.span, "this trait cannot be derived for unions"); + cx.emit_err(errors::DeriveUnion { span: mitem.span }); return; } } diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index f011cb754cb..58c972738c4 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 thin_vec::thin_vec; +use crate::errors; + 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, tts) { Some(exprs) if exprs.is_empty() || exprs.len() > 2 => { - cx.span_err(sp, "env! takes 1 or 2 arguments"); + cx.emit_err(errors::EnvTakesArgs { span: sp }); return DummyResult::any(sp); } None => return DummyResult::any(sp), @@ -78,18 +80,12 @@ pub fn expand_env<'cx>( cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { - let (msg, help) = match custom_msg { - None => ( - format!("environment variable `{var}` not defined at compile time"), - Some(help_for_missing_env_var(var.as_str())), - ), - Some(s) => (s.to_string(), None), - }; - let mut diag = cx.struct_span_err(sp, &msg); - if let Some(help) = help { - diag.help(help); - } - diag.emit(); + cx.emit_err(errors::EnvNotDefined { + span: sp, + msg: custom_msg, + var, + help: custom_msg.is_none().then(|| help_for_missing_env_var(var.as_str())), + }); return DummyResult::any(sp); } Some(value) => cx.expr_str(sp, value), @@ -97,15 +93,13 @@ pub fn expand_env<'cx>( MacEager::expr(e) } -fn help_for_missing_env_var(var: &str) -> String { +fn help_for_missing_env_var(var: &str) -> errors::EnvNotDefinedHelp { if var.starts_with("CARGO_") || var.starts_with("DEP_") || matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET") { - format!( - "Cargo sets build script variables at run time. Use `std::env::var(\"{var}\")` instead" - ) + errors::EnvNotDefinedHelp::CargoVar } else { - format!("Use `std::env::var(\"{var}\")` to read the variable at run time") + errors::EnvNotDefinedHelp::Other } } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs new file mode 100644 index 00000000000..630f9b87bc3 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -0,0 +1,553 @@ +use rustc_errors::{ + AddToDiagnostic, EmissionGuarantee, IntoDiagnostic, MultiSpan, SingleLabelManySpans, +}; +use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_span::{symbol::Ident, Span, Symbol}; + +#[derive(Diagnostic)] +#[diag(builtin_macros_requires_cfg_pattern)] +pub(crate) struct RequiresCfgPattern { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_expected_one_cfg_pattern)] +pub(crate) struct OneCfgPattern { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_alloc_error_must_be_fn)] +pub(crate) struct AllocErrorMustBeFn { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_assert_requires_boolean)] +pub(crate) struct AssertRequiresBoolean { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_assert_requires_expression)] +pub(crate) struct AssertRequiresExpression { + #[primary_span] + pub(crate) span: Span, + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub(crate) token: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_assert_missing_comma)] +pub(crate) struct AssertMissingComma { + #[primary_span] + pub(crate) span: Span, + #[suggestion(code = ", ", applicability = "maybe-incorrect", style = "short")] + pub(crate) comma: Span, +} + +#[derive(Diagnostic)] +pub(crate) enum CfgAccessibleInvalid { + #[diag(builtin_macros_cfg_accessible_unspecified_path)] + UnspecifiedPath(#[primary_span] Span), + #[diag(builtin_macros_cfg_accessible_multiple_paths)] + MultiplePaths(#[primary_span] Span), + #[diag(builtin_macros_cfg_accessible_literal_path)] + LiteralPath(#[primary_span] Span), + #[diag(builtin_macros_cfg_accessible_has_args)] + HasArguments(#[primary_span] Span), +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_cfg_accessible_indeterminate)] +pub(crate) struct CfgAccessibleIndeterminate { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_missing_literal)] +#[note] +pub(crate) struct ConcatMissingLiteral { + #[primary_span] + pub(crate) spans: Vec, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytestr)] +pub(crate) struct ConcatBytestr { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytes_invalid)] +pub(crate) struct ConcatBytesInvalid { + #[primary_span] + pub(crate) span: Span, + pub(crate) lit_kind: &'static str, + #[subdiagnostic] + pub(crate) sugg: Option, +} + +#[derive(Subdiagnostic)] +pub(crate) enum ConcatBytesInvalidSuggestion { + #[suggestion( + builtin_macros_byte_char, + code = "b{snippet}", + applicability = "machine-applicable" + )] + CharLit { + #[primary_span] + span: Span, + snippet: String, + }, + #[suggestion( + builtin_macros_byte_str, + code = "b{snippet}", + applicability = "machine-applicable" + )] + StrLit { + #[primary_span] + span: Span, + snippet: String, + }, + #[suggestion( + builtin_macros_number_array, + code = "[{snippet}]", + applicability = "machine-applicable" + )] + IntLit { + #[primary_span] + span: Span, + snippet: String, + }, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytes_oob)] +pub(crate) struct ConcatBytesOob { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytes_non_u8)] +pub(crate) struct ConcatBytesNonU8 { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytes_missing_literal)] +#[note] +pub(crate) struct ConcatBytesMissingLiteral { + #[primary_span] + pub(crate) spans: Vec, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytes_array)] +pub(crate) struct ConcatBytesArray { + #[primary_span] + pub(crate) span: Span, + #[note] + #[help] + pub(crate) bytestr: bool, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_bytes_bad_repeat)] +pub(crate) struct ConcatBytesBadRepeat { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_idents_missing_args)] +pub(crate) struct ConcatIdentsMissingArgs { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_idents_missing_comma)] +pub(crate) struct ConcatIdentsMissingComma { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_concat_idents_ident_args)] +pub(crate) struct ConcatIdentsIdentArgs { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_bad_derive_target, code = "E0774")] +pub(crate) struct BadDeriveTarget { + #[primary_span] + #[label] + pub(crate) span: Span, + #[label(builtin_macros_label2)] + pub(crate) item: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_unexpected_lit, code = "E0777")] +pub(crate) struct BadDeriveLit { + #[primary_span] + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub help: BadDeriveLitHelp, +} + +#[derive(Subdiagnostic)] +pub(crate) enum BadDeriveLitHelp { + #[help(builtin_macros_str_lit)] + StrLit { sym: Symbol }, + #[help(builtin_macros_other)] + Other, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_derive_path_args_list)] +pub(crate) struct DerivePathArgsList { + #[suggestion(code = "", applicability = "machine-applicable")] + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_derive_path_args_value)] +pub(crate) struct DerivePathArgsValue { + #[suggestion(code = "", applicability = "machine-applicable")] + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_no_default_variant)] +#[help] +pub(crate) struct NoDefaultVariant { + #[primary_span] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) suggs: Vec, +} + +#[derive(Subdiagnostic)] +#[suggestion( + builtin_macros_suggestion, + code = "#[default] {ident}", + applicability = "maybe-incorrect", + style = "tool-only" +)] +pub(crate) struct NoDefaultVariantSugg { + #[primary_span] + pub(crate) span: Span, + pub(crate) ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_multiple_defaults)] +#[note] +pub(crate) struct MultipleDefaults { + #[primary_span] + pub(crate) span: Span, + #[label] + pub(crate) first: Span, + #[label(builtin_macros_additional)] + pub additional: Vec, + #[subdiagnostic] + pub suggs: Vec, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + builtin_macros_suggestion, + applicability = "maybe-incorrect", + style = "tool-only" +)] +pub(crate) struct MultipleDefaultsSugg { + #[suggestion_part(code = "")] + pub(crate) spans: Vec, + pub(crate) ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_non_unit_default)] +#[help] +pub(crate) struct NonUnitDefault { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_non_exhaustive_default)] +#[help] +pub(crate) struct NonExhaustiveDefault { + #[primary_span] + pub(crate) span: Span, + #[label] + pub(crate) non_exhaustive: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_multiple_default_attrs)] +#[note] +pub(crate) struct MultipleDefaultAttrs { + #[primary_span] + pub(crate) span: Span, + #[label] + pub(crate) first: Span, + #[label(builtin_macros_label_again)] + pub(crate) first_rest: Span, + #[help] + pub(crate) rest: MultiSpan, + pub(crate) only_one: bool, + #[subdiagnostic] + pub(crate) sugg: MultipleDefaultAttrsSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + builtin_macros_help, + applicability = "machine-applicable", + style = "tool-only" +)] +pub(crate) struct MultipleDefaultAttrsSugg { + #[suggestion_part(code = "")] + pub(crate) spans: Vec, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_default_arg)] +pub(crate) struct DefaultHasArg { + #[primary_span] + #[suggestion(code = "#[default]", style = "hidden", applicability = "maybe-incorrect")] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_derive_macro_call)] +pub(crate) struct DeriveMacroCall { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_cannot_derive_union)] +pub(crate) struct DeriveUnion { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_env_takes_args)] +pub(crate) struct EnvTakesArgs { + #[primary_span] + pub(crate) span: Span, +} + +//#[derive(Diagnostic)] +//#[diag(builtin_macros_env_not_defined)] +pub(crate) struct EnvNotDefined { + pub(crate) span: Span, + pub(crate) msg: Option, + pub(crate) var: Symbol, + pub(crate) help: Option, +} + +// 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> { + let mut diag = if let Some(msg) = self.msg { + handler.struct_diagnostic(msg.as_str()) + } else { + handler.struct_diagnostic(crate::fluent_generated::builtin_macros_env_not_defined) + }; + diag.set_arg("var", self.var); + diag.set_span(self.span); + if let Some(help) = self.help { + diag.subdiagnostic(help); + } + diag + } +} + +#[derive(Subdiagnostic)] +pub(crate) enum EnvNotDefinedHelp { + #[help(builtin_macros_cargo)] + CargoVar, + #[help(builtin_macros_other)] + Other, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_requires_string)] +pub(crate) struct FormatRequiresString { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_duplicate_arg)] +pub(crate) struct FormatDuplicateArg { + #[primary_span] + pub(crate) span: Span, + #[label(builtin_macros_label1)] + pub(crate) prev: Span, + #[label(builtin_macros_label2)] + pub(crate) duplicate: Span, + pub(crate) ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_positional_after_named)] +pub(crate) struct PositionalAfterNamed { + #[primary_span] + #[label] + pub(crate) span: Span, + #[label(builtin_macros_named_args)] + pub(crate) args: Vec, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_string_invalid)] +pub(crate) struct InvalidFormatString { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) desc: String, + pub(crate) label1: String, + #[subdiagnostic] + pub(crate) note_: Option, + #[subdiagnostic] + pub(crate) label_: Option, + #[subdiagnostic] + pub(crate) sugg_: Option, +} + +#[derive(Subdiagnostic)] +#[note(builtin_macros_note)] +pub(crate) struct InvalidFormatStringNote { + pub(crate) note: String, +} + +#[derive(Subdiagnostic)] +#[label(builtin_macros_second_label)] +pub(crate) struct InvalidFormatStringLabel { + #[primary_span] + pub(crate) span: Span, + pub(crate) label: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + builtin_macros_sugg, + style = "verbose", + applicability = "machine-applicable" +)] +pub(crate) struct InvalidFormatStringSuggestion { + #[suggestion_part(code = "{len}")] + pub(crate) captured: Span, + pub(crate) len: String, + #[suggestion_part(code = ", {arg}")] + pub(crate) span: Span, + pub(crate) arg: String, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_no_arg_named)] +#[note] +#[note(builtin_macros_note2)] +pub(crate) struct FormatNoArgNamed { + #[primary_span] + pub(crate) span: Span, + pub(crate) name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_unknown_trait)] +#[note] +pub(crate) struct FormatUnknownTrait<'a> { + #[primary_span] + pub(crate) span: Span, + pub(crate) ty: &'a str, + #[subdiagnostic] + pub(crate) suggs: Vec, +} + +#[derive(Subdiagnostic)] +#[suggestion( + builtin_macros_suggestion, + code = "{fmt}", + style = "tool-only", + applicability = "maybe-incorrect" +)] +pub struct FormatUnknownTraitSugg { + #[primary_span] + pub span: Span, + pub fmt: &'static str, + pub trait_name: &'static str, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_unused_arg)] +pub(crate) struct FormatUnusedArg { + #[primary_span] + #[label(builtin_macros_format_unused_arg)] + pub(crate) span: Span, + pub(crate) named: bool, +} + +// Allow the singular form to be a subdiagnostic of the multiple-unused +// form of diagnostic. +impl AddToDiagnostic for FormatUnusedArg { + fn add_to_diagnostic_with(self, diag: &mut rustc_errors::Diagnostic, f: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + diag.set_arg("named", self.named); + let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into()); + diag.span_label(self.span, msg); + } +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_unused_args)] +pub(crate) struct FormatUnusedArgs { + #[primary_span] + pub(crate) unused: Vec, + #[label] + pub(crate) fmt: Span, + #[subdiagnostic] + pub(crate) unused_labels: Vec, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_format_pos_mismatch)] +pub(crate) struct FormatPositionalMismatch { + #[primary_span] + pub(crate) span: MultiSpan, + pub(crate) n: usize, + pub(crate) desc: String, + #[subdiagnostic] + pub(crate) highlight: SingleLabelManySpans, +} diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index db2ef7fba4b..435a07d8ce7 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -7,7 +7,7 @@ use rustc_ast::{ FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, }; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{pluralize, Applicability, MultiSpan, PResult}; +use rustc_errors::{Applicability, MultiSpan, PResult, SingleLabelManySpans}; use rustc_expand::base::{self, *}; use rustc_parse_format as parse; use rustc_span::symbol::{Ident, Symbol}; @@ -36,6 +36,8 @@ enum PositionUsedAs { } use PositionUsedAs::*; +use crate::errors; + struct MacroInput { fmtstr: P, args: FormatArguments, @@ -66,7 +68,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< 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(errors::FormatRequiresString { span: sp })); } let first_token = &p.token; @@ -121,13 +123,12 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< p.expect(&token::Eq)?; let expr = p.parse_expr()?; if let Some((_, prev)) = args.by_name(ident.name) { - ecx.struct_span_err( - ident.span, - &format!("duplicate argument named `{}`", ident), - ) - .span_label(prev.kind.ident().unwrap().span, "previously here") - .span_label(ident.span, "duplicate argument") - .emit(); + ecx.emit_err(errors::FormatDuplicateArg { + span: ident.span, + prev: prev.kind.ident().unwrap().span, + duplicate: ident.span, + ident, + }); continue; } args.add(FormatArgument { kind: FormatArgumentKind::Named(ident), expr }); @@ -135,20 +136,21 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< _ => { let expr = p.parse_expr()?; if !args.named_args().is_empty() { - let mut err = ecx.struct_span_err( - expr.span, - "positional arguments cannot follow named arguments", - ); - err.span_label( - expr.span, - "positional arguments must be before named arguments", - ); - for arg in args.named_args() { - if let Some(name) = arg.kind.ident() { - err.span_label(name.span.to(arg.expr.span), "named argument"); - } - } - err.emit(); + ecx.emit_err(errors::PositionalAfterNamed { + span: expr.span, + args: args + .named_args() + .iter() + .filter_map(|a| { + if let Some(ident) = a.kind.ident() { + Some((a, ident)) + } else { + None + } + }) + .map(|(arg, n)| n.span.to(arg.expr.span)) + .collect(), + }); } args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr }); } @@ -234,13 +236,19 @@ fn make_format_args( // argument span here. fmt_span }; - let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", err.description)); - e.span_label(sp, err.label + " in format string"); + let mut e = errors::InvalidFormatString { + span: sp, + note_: None, + label_: None, + sugg_: None, + desc: err.description, + label1: err.label, + }; if let Some(note) = err.note { - e.note(¬e); + e.note_ = Some(errors::InvalidFormatStringNote { note }); } if let Some((label, span)) = err.secondary_label && is_source_literal { - e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label); + e.label_ = Some(errors::InvalidFormatStringLabel { span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label } ); } if err.should_be_replaced_with_positional_argument { let captured_arg_span = @@ -250,17 +258,15 @@ fn make_format_args( Some(arg) => arg.expr.span, None => fmt_span, }; - e.multipart_suggestion_verbose( - "consider using a positional formatting argument instead", - vec![ - (captured_arg_span, args.unnamed_args().len().to_string()), - (span.shrink_to_hi(), format!(", {}", arg)), - ], - Applicability::MachineApplicable, - ); + e.sugg_ = Some(errors::InvalidFormatStringSuggestion { + captured: captured_arg_span, + len: args.unnamed_args().len().to_string(), + span: span.shrink_to_hi(), + arg, + }); } } - e.emit(); + ecx.emit_err(e); return Err(()); } @@ -318,10 +324,7 @@ fn make_format_args( } else { // For the moment capturing variables from format strings expanded from macros is // disabled (see RFC #2795) - ecx.struct_span_err(span, &format!("there is no argument named `{name}`")) - .note(format!("did you intend to capture a variable `{name}` from the surrounding scope?")) - .note("to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro") - .emit(); + ecx.emit_err(errors::FormatNoArgNamed { span, name }); DummyResult::raw_expr(span, true) }; Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr })) @@ -475,12 +478,8 @@ fn make_format_args( .enumerate() .filter(|&(_, used)| !used) .map(|(i, _)| { - let msg = if let FormatArgumentKind::Named(_) = args.explicit_args()[i].kind { - "named argument never used" - } else { - "argument never used" - }; - (args.explicit_args()[i].expr.span, msg) + let named = matches!(args.explicit_args()[i].kind, FormatArgumentKind::Named(_)); + (args.explicit_args()[i].expr.span, named) }) .collect::>(); @@ -531,22 +530,8 @@ fn invalid_placeholder_type_error( fmt_span: Span, ) { let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end))); - let mut err = - ecx.struct_span_err(sp.unwrap_or(fmt_span), &format!("unknown format trait `{}`", ty)); - err.note( - "the only appropriate formatting traits are:\n\ - - ``, which uses the `Display` trait\n\ - - `?`, which uses the `Debug` trait\n\ - - `e`, which uses the `LowerExp` trait\n\ - - `E`, which uses the `UpperExp` trait\n\ - - `o`, which uses the `Octal` trait\n\ - - `p`, which uses the `Pointer` trait\n\ - - `b`, which uses the `Binary` trait\n\ - - `x`, which uses the `LowerHex` trait\n\ - - `X`, which uses the `UpperHex` trait", - ); - if let Some(sp) = sp { - for (fmt, name) in &[ + let suggs = if let Some(sp) = sp { + [ ("", "Display"), ("?", "Debug"), ("e", "LowerExp"), @@ -556,40 +541,38 @@ fn invalid_placeholder_type_error( ("b", "Binary"), ("x", "LowerHex"), ("X", "UpperHex"), - ] { - err.tool_only_span_suggestion( - sp, - &format!("use the `{}` trait", name), - *fmt, - Applicability::MaybeIncorrect, - ); - } - } - err.emit(); + ] + .into_iter() + .map(|(fmt, trait_name)| errors::FormatUnknownTraitSugg { span: sp, fmt, trait_name }) + .collect() + } else { + vec![] + }; + ecx.emit_err(errors::FormatUnknownTrait { span: sp.unwrap_or(fmt_span), ty, suggs }); } fn report_missing_placeholders( ecx: &mut ExtCtxt<'_>, - unused: Vec<(Span, &str)>, + unused: Vec<(Span, bool)>, detect_foreign_fmt: bool, str_style: Option, fmt_str: &str, fmt_span: Span, ) { - let mut diag = if let &[(span, msg)] = &unused[..] { - let mut diag = ecx.struct_span_err(span, msg); - diag.span_label(span, msg); - diag + let mut diag = if let &[(span, named)] = &unused[..] { + //let mut diag = ecx.struct_span_err(span, msg); + //diag.span_label(span, msg); + //diag + ecx.create_err(errors::FormatUnusedArg { span, named }) } else { - let mut diag = ecx.struct_span_err( - unused.iter().map(|&(sp, _)| sp).collect::>(), - "multiple unused formatting arguments", - ); - diag.span_label(fmt_span, "multiple missing formatting specifiers"); - for &(span, msg) in &unused { - diag.span_label(span, msg); - } - diag + let unused_labels = + unused.iter().map(|&(span, named)| errors::FormatUnusedArg { span, named }).collect(); + let unused_spans = unused.iter().map(|&(span, _)| span).collect(); + ecx.create_err(errors::FormatUnusedArgs { + fmt: fmt_span, + unused: unused_spans, + unused_labels, + }) }; // Used to ensure we only report translations for *one* kind of foreign format. @@ -768,18 +751,16 @@ fn report_invalid_references( } else { MultiSpan::from_spans(spans) }; - e = ecx.struct_span_err( + e = ecx.create_err(errors::FormatPositionalMismatch { span, - &format!( - "{} positional argument{} in format string, but {}", - num_placeholders, - pluralize!(num_placeholders), - num_args_desc, - ), - ); - for arg in args.explicit_args() { - e.span_label(arg.expr.span, ""); - } + n: num_placeholders, + desc: num_args_desc, + highlight: SingleLabelManySpans { + spans: args.explicit_args().iter().map(|arg| arg.expr.span).collect(), + label: "", + kind: rustc_errors::LabelKind::Label, + }, + }); // Point out `{:.*}` placeholders: those take an extra argument. let mut has_precision_star = false; for piece in template { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 7697b592e33..37fbd03a6a2 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -9,6 +9,7 @@ #![feature(if_let_guard)] #![feature(is_sorted)] #![feature(let_chains)] +#![feature(lint_reasons)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![recursion_limit = "256"] @@ -39,6 +40,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_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index e09ef34b93d..29c692128bc 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -880,6 +880,7 @@ impl Diagnostic { /// /// This is intended to be used for suggestions that are *very* obvious in what the changes /// need to be from the message, but we still want other tools to be able to apply them. + #[rustc_lint_diagnostics] pub fn tool_only_span_suggestion( &mut self, sp: Span, diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index e82bad67b21..65f8a61a30a 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -1,4 +1,4 @@ -use crate::fluent_generated as fluent; +use crate::{fluent_generated as fluent, AddToDiagnostic}; use crate::{DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg}; use rustc_ast as ast; use rustc_ast_pretty::pprust; @@ -6,6 +6,7 @@ use rustc_hir as hir; use rustc_lint_defs::Level; use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; +use rustc_span::Span; use rustc_target::abi::TargetDataLayoutErrors; use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; use rustc_type_ir as type_ir; @@ -276,3 +277,26 @@ impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> { } } } + +/// Utility struct used to apply a single label while highlighting multiple spans +pub struct SingleLabelManySpans { + pub spans: Vec, + pub label: &'static str, + pub kind: LabelKind, +} +impl AddToDiagnostic for SingleLabelManySpans { + fn add_to_diagnostic_with(self, diag: &mut crate::Diagnostic, _: F) { + match self.kind { + LabelKind::Note => diag.span_note(self.spans, self.label), + LabelKind::Label => diag.span_labels(self.spans, self.label), + LabelKind::Help => diag.span_help(self.spans, self.label), + }; + } +} + +/// The kind of label to attach when using [`SingleLabelManySpans`] +pub enum LabelKind { + Note, + Label, + Help, +} diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 9866a9bffe0..5b0d8096207 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -383,7 +383,9 @@ pub use diagnostic::{ DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, }; pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted}; -pub use diagnostic_impls::{DiagnosticArgFromDisplay, DiagnosticSymbolList}; +pub use diagnostic_impls::{ + DiagnosticArgFromDisplay, DiagnosticSymbolList, LabelKind, SingleLabelManySpans, +}; use std::backtrace::Backtrace; /// A handler deals with errors and other compiler output. diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 4540ded0f41..427c82c410b 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -392,14 +392,16 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { } SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => { let inner = info.ty.inner_type(); - if type_matches_path(inner, &["rustc_span", "Span"]) { + if type_matches_path(inner, &["rustc_span", "Span"]) + || type_matches_path(inner, &["rustc_span", "MultiSpan"]) + { Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug)) } else if type_is_unit(inner) || (matches!(info.ty, FieldInnerTy::Plain(_)) && type_is_bool(inner)) { Ok(self.add_subdiagnostic(&fn_ident, slug)) } else { - report_type_error(attr, "`Span`, `bool` or `()`")? + report_type_error(attr, "`Span`, `MultiSpan`, `bool` or `()`")? } } SubdiagnosticKind::Suggestion { diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index 61724c11745..6cc7bab3726 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -518,7 +518,7 @@ struct BoolField { #[help] foo: bool, #[help(no_crate_help)] - //~^ ERROR the `#[help(...)]` attribute can only be applied to fields of type `Span`, `bool` or `()` + //~^ ERROR the `#[help(...)]` attribute can only be applied to fields of type // only allow plain 'bool' fields bar: Option, } diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index cd14c7496b3..a2f3bb5277b 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -323,7 +323,7 @@ error: invalid applicability LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")] | ^^^^^^^^ -error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `bool` or `()` +error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()` --> $DIR/diagnostic-derive.rs:520:5 | LL | #[help(no_crate_help)] diff --git a/tests/ui/extenv/extenv-no-args.rs b/tests/ui/extenv/extenv-no-args.rs index 9f221ed10d7..2ff6d242b27 100644 --- a/tests/ui/extenv/extenv-no-args.rs +++ b/tests/ui/extenv/extenv-no-args.rs @@ -1 +1 @@ -fn main() { env!(); } //~ ERROR: env! takes 1 or 2 arguments +fn main() { env!(); } //~ ERROR: `env!()` takes 1 or 2 arguments diff --git a/tests/ui/extenv/extenv-no-args.stderr b/tests/ui/extenv/extenv-no-args.stderr index 318ed635be0..70b85932c23 100644 --- a/tests/ui/extenv/extenv-no-args.stderr +++ b/tests/ui/extenv/extenv-no-args.stderr @@ -1,4 +1,4 @@ -error: env! takes 1 or 2 arguments +error: `env!()` takes 1 or 2 arguments --> $DIR/extenv-no-args.rs:1:13 | LL | fn main() { env!(); } diff --git a/tests/ui/extenv/extenv-too-many-args.rs b/tests/ui/extenv/extenv-too-many-args.rs index 1adbee583db..ffad1c51303 100644 --- a/tests/ui/extenv/extenv-too-many-args.rs +++ b/tests/ui/extenv/extenv-too-many-args.rs @@ -1 +1 @@ -fn main() { env!("one", "two", "three"); } //~ ERROR: env! takes 1 or 2 arguments +fn main() { env!("one", "two", "three"); } //~ ERROR: `env!()` takes 1 or 2 arguments diff --git a/tests/ui/extenv/extenv-too-many-args.stderr b/tests/ui/extenv/extenv-too-many-args.stderr index 54150a3328f..47cf810b70d 100644 --- a/tests/ui/extenv/extenv-too-many-args.stderr +++ b/tests/ui/extenv/extenv-too-many-args.stderr @@ -1,4 +1,4 @@ -error: env! takes 1 or 2 arguments +error: `env!()` takes 1 or 2 arguments --> $DIR/extenv-too-many-args.rs:1:13 | LL | fn main() { env!("one", "two", "three"); } diff --git a/tests/ui/extenv/issue-55897.stderr b/tests/ui/extenv/issue-55897.stderr index 5752a965e35..401db827813 100644 --- a/tests/ui/extenv/issue-55897.stderr +++ b/tests/ui/extenv/issue-55897.stderr @@ -4,7 +4,7 @@ error: environment variable `NON_EXISTENT` not defined at compile time LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs")); | ^^^^^^^^^^^^^^^^^^^^ | - = help: Use `std::env::var("NON_EXISTENT")` to read the variable at run time + = help: use `std::env::var("NON_EXISTENT")` to read the variable at run time = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) error: suffixes on string literals are invalid diff --git a/tests/ui/issues/issue-50403.rs b/tests/ui/issues/issue-50403.rs index 012057fc280..ab22aff26d9 100644 --- a/tests/ui/issues/issue-50403.rs +++ b/tests/ui/issues/issue-50403.rs @@ -1,5 +1,5 @@ #![feature(concat_idents)] fn main() { - let x = concat_idents!(); //~ ERROR concat_idents! takes 1 or more arguments + let x = concat_idents!(); //~ ERROR `concat_idents!()` takes 1 or more arguments } diff --git a/tests/ui/issues/issue-50403.stderr b/tests/ui/issues/issue-50403.stderr index a3a2ed044db..d50befa5e32 100644 --- a/tests/ui/issues/issue-50403.stderr +++ b/tests/ui/issues/issue-50403.stderr @@ -1,4 +1,4 @@ -error: concat_idents! takes 1 or more arguments +error: `concat_idents!()` takes 1 or more arguments --> $DIR/issue-50403.rs:4:13 | LL | let x = concat_idents!(); diff --git a/tests/ui/macros/concat-bytes-error.stderr b/tests/ui/macros/concat-bytes-error.stderr index d6cd1a3d178..3f2c64922e3 100644 --- a/tests/ui/macros/concat-bytes-error.stderr +++ b/tests/ui/macros/concat-bytes-error.stderr @@ -4,7 +4,7 @@ error: expected a byte literal LL | concat_bytes!(pie); | ^^^ | - = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: expected a byte literal --> $DIR/concat-bytes-error.rs:5:19 @@ -12,7 +12,7 @@ error: expected a byte literal LL | concat_bytes!(pie, pie); | ^^^ ^^^ | - = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate string literals --> $DIR/concat-bytes-error.rs:6:19 @@ -98,7 +98,7 @@ error: expected a byte literal LL | -33, | ^^^ | - = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate doubly nested array --> $DIR/concat-bytes-error.rs:35:9 @@ -151,7 +151,7 @@ error: expected a byte literal LL | concat_bytes!([pie; 2]); | ^^^ | - = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate float literals --> $DIR/concat-bytes-error.rs:46:20 diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr index 93fbc9c8a44..ca373ea6cd9 100644 --- a/tests/ui/macros/macros-nonfatal-errors.stderr +++ b/tests/ui/macros/macros-nonfatal-errors.stderr @@ -3,36 +3,48 @@ error: the `#[default]` attribute may only be used on unit enum variants | LL | #[default] | ^^^^^^^^^^ + | + = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants --> $DIR/macros-nonfatal-errors.rs:18:36 | LL | struct DefaultInnerAttrTupleStruct(#[default] ()); | ^^^^^^^^^^ + | + = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants --> $DIR/macros-nonfatal-errors.rs:22:1 | LL | #[default] | ^^^^^^^^^^ + | + = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants --> $DIR/macros-nonfatal-errors.rs:26:1 | LL | #[default] | ^^^^^^^^^^ + | + = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants --> $DIR/macros-nonfatal-errors.rs:36:11 | LL | Foo = #[default] 0, | ^^^^^^^^^^ + | + = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants --> $DIR/macros-nonfatal-errors.rs:37:14 | LL | Bar([u8; #[default] 1]), | ^^^^^^^^^^ + | + = help: consider a manual implementation of `Default` error: no default declared --> $DIR/macros-nonfatal-errors.rs:42:10 @@ -132,7 +144,7 @@ error: asm template must be a string literal LL | asm!(invalid); | ^^^^^^^ -error: concat_idents! requires ident args +error: `concat_idents!()` requires ident args --> $DIR/macros-nonfatal-errors.rs:101:5 | LL | concat_idents!("not", "idents"); @@ -150,7 +162,7 @@ error: expected string literal LL | env!(invalid); | ^^^^^^^ -error: env! takes 1 or 2 arguments +error: `env!()` takes 1 or 2 arguments --> $DIR/macros-nonfatal-errors.rs:105:5 | LL | env!(foo, abr, baz); @@ -162,7 +174,7 @@ error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined at co LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: Use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time + = help: use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) error: format argument must be a string literal