From 7d4e34d0bcf06b357fd09a059a02687acf335132 Mon Sep 17 00:00:00 2001 From: V3n3RiX Date: Wed, 21 Jun 2023 01:17:50 +0100 Subject: gentoo auto-resync : 21:06:2023 - 01:17:50 --- dev-lang/rust/files/1.67.1-rustc_expand.patch | 1427 +++++++++++++++++++++++++ 1 file changed, 1427 insertions(+) create mode 100644 dev-lang/rust/files/1.67.1-rustc_expand.patch (limited to 'dev-lang/rust/files/1.67.1-rustc_expand.patch') diff --git a/dev-lang/rust/files/1.67.1-rustc_expand.patch b/dev-lang/rust/files/1.67.1-rustc_expand.patch new file mode 100644 index 000000000000..af778d45c76f --- /dev/null +++ b/dev-lang/rust/files/1.67.1-rustc_expand.patch @@ -0,0 +1,1427 @@ +From 2f9f097cb8b6c27a7e0d7a916e6911fc1f5ecd81 Mon Sep 17 00:00:00 2001 +From: nils <48135649+Nilstrieb@users.noreply.github.com> +Date: Tue, 15 Nov 2022 14:24:33 +0100 +Subject: [PATCH] Migrate parts of `rustc_expand` to session diagnostics + +This migrates everything but the `mbe` and `proc_macro` modules. It also +contains a few cleanups and drive-by/accidental diagnostic improvements +which can be seen in the diff for the UI tests. +--- + compiler/rustc_builtin_macros/src/concat.rs | 2 +- + .../rustc_builtin_macros/src/concat_bytes.rs | 2 +- + compiler/rustc_builtin_macros/src/env.rs | 2 +- + .../locales/en-US/expand.ftl | 107 ++++++ + compiler/rustc_errors/src/diagnostic_impls.rs | 6 + + compiler/rustc_expand/src/base.rs | 90 +++-- + compiler/rustc_expand/src/config.rs | 106 +++--- + compiler/rustc_expand/src/errors.rs | 326 +++++++++++++++++- + compiler/rustc_expand/src/expand.rs | 86 ++--- + compiler/rustc_expand/src/lib.rs | 6 + + compiler/rustc_expand/src/module.rs | 80 ++--- + compiler/rustc_expand/src/tests.rs | 1 + + src/test/rustdoc-ui/doc-cfg.stderr | 4 +- + .../cfg-attr-syntax-validation.stderr | 2 +- + .../macros/macro-in-expression-context.stderr | 8 +- + .../ui/proc-macro/attr-invalid-exprs.stderr | 16 +- + src/test/ui/proc-macro/attribute.rs | 8 +- + src/test/ui/proc-macro/attribute.stderr | 8 +- + src/test/ui/proc-macro/expand-expr.stderr | 16 +- + 19 files changed, 640 insertions(+), 236 deletions(-) + +diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs +index e2d71825d556f..9ae65c641fd62 100644 +--- a/compiler/rustc_builtin_macros/src/concat.rs ++++ b/compiler/rustc_builtin_macros/src/concat.rs +@@ -11,7 +11,7 @@ pub fn expand_concat( + sp: rustc_span::Span, + tts: TokenStream, + ) -> Box { +- let Some(es) = base::get_exprs_from_tts(cx, sp, tts) else { ++ let Some(es) = base::get_exprs_from_tts(cx, tts) else { + return DummyResult::any(sp); + }; + let mut accumulator = String::new(); +diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs +index d1124145dcbbb..70ce5a6c41929 100644 +--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs ++++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs +@@ -137,7 +137,7 @@ pub fn expand_concat_bytes( + sp: rustc_span::Span, + tts: TokenStream, + ) -> Box { +- let Some(es) = base::get_exprs_from_tts(cx, sp, tts) else { ++ let Some(es) = base::get_exprs_from_tts(cx, tts) else { + return DummyResult::any(sp); + }; + let mut accumulator = Vec::new(); +diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs +index 0b4e545f7a3d0..a7283ea601b19 100644 +--- a/compiler/rustc_builtin_macros/src/env.rs ++++ b/compiler/rustc_builtin_macros/src/env.rs +@@ -52,7 +52,7 @@ pub fn expand_env<'cx>( + sp: Span, + tts: TokenStream, + ) -> Box { +- let mut exprs = match get_exprs_from_tts(cx, sp, tts) { ++ let mut exprs = match get_exprs_from_tts(cx, tts) { + Some(exprs) if exprs.is_empty() => { + cx.span_err(sp, "env! takes 1 or 2 arguments"); + return DummyResult::any(sp); +diff --git a/compiler/rustc_error_messages/locales/en-US/expand.ftl b/compiler/rustc_error_messages/locales/en-US/expand.ftl +index 5720591154f99..df0e8ae5dd8f5 100644 +--- a/compiler/rustc_error_messages/locales/en-US/expand.ftl ++++ b/compiler/rustc_error_messages/locales/en-US/expand.ftl +@@ -20,3 +20,110 @@ expand_var_still_repeating = + variable '{$ident}' is still repeating at this depth + + expand_meta_var_dif_seq_matchers = {$msg} ++ ++expand_macro_const_stability = ++ macros cannot have const stability attributes ++ .label = invalid const stability attribute ++ .label2 = const stability attribute affects this macro ++ ++expand_macro_body_stability = ++ macros cannot have body stability attributes ++ .label = invalid body stability attribute ++ .label2 = body stability attribute affects this macro ++ ++expand_resolve_relative_path = ++ cannot resolve relative path in non-file source `{$path}` ++ ++expand_attr_no_arguments = ++ attribute must have either one or two arguments ++ ++expand_not_a_meta_item = ++ not a meta item ++ ++expand_only_one_word = ++ must only be one word ++ ++expand_cannot_be_name_of_macro = ++ `{$trait_ident}` cannot be a name of {$macro_type} macro ++ ++expand_arg_not_attributes = ++ second argument must be `attributes` ++ ++expand_attributes_wrong_form = ++ attribute must be of form: `attributes(foo, bar)` ++ ++expand_attribute_meta_item = ++ attribute must be a meta item, not a literal ++ ++expand_attribute_single_word = ++ attribute must only be a single word ++ ++expand_helper_attribute_name_invalid = ++ `{$name}` cannot be a name of derive helper attribute ++ ++expand_expected_comma_in_list = ++ expected token: `,` ++ ++expand_only_one_argument = ++ {$name} takes 1 argument ++ ++expand_takes_no_arguments = ++ {$name} takes no arguments ++ ++expand_feature_included_in_edition = ++ the feature `{$feature}` is included in the Rust {$edition} edition ++ ++expand_feature_removed = ++ feature has been removed ++ .label = feature has been removed ++ .reason = {$reason} ++ ++expand_feature_not_allowed = ++ the feature `{$name}` is not in the list of allowed features ++ ++expand_recursion_limit_reached = ++ recursion limit reached while expanding `{$descr}` ++ .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) ++ ++expand_malformed_feature_attribute = ++ malformed `feature` attribute input ++ .expected = expected just one word ++ ++expand_remove_expr_not_supported = ++ removing an expression is not supported in this position ++ ++expand_invalid_cfg_no_parens = `cfg` is not followed by parentheses ++expand_invalid_cfg_no_predicate = `cfg` predicate is not specified ++expand_invalid_cfg_multiple_predicates = multiple `cfg` predicates are specified ++expand_invalid_cfg_predicate_literal = `cfg` predicate key cannot be a literal ++expand_invalid_cfg_expected_syntax = expected syntax is ++ ++expand_wrong_fragment_kind = ++ non-{$kind} macro in {$kind} position: {$name} ++ ++expand_unsupported_key_value = ++ key-value macro attributes are not supported ++ ++expand_incomplete_parse = ++ macro expansion ignores token `{$token}` and any following ++ .label = caused by the macro expansion here ++ .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context ++ .suggestion_add_semi = you might be missing a semicolon here ++ ++expand_remove_node_not_supported = ++ removing {$descr} is not supported in this position ++ ++expand_module_circular = ++ circular modules: {$modules} ++ ++expand_module_in_block = ++ cannot declare a non-inline module inside a block unless it has a path attribute ++ .note = maybe `use` the module `{$name}` instead of redeclaring it ++ ++expand_module_file_not_found = ++ file not found for module `{$name}` ++ .help = to create the module `{$name}`, create file "{$default_path}" or "{$secondary_path}" ++ ++expand_module_multiple_candidates = ++ file for module `{$name}` found at both "{$default_path}" and "{$secondary_path}" ++ .help = delete or rename one of them to remove the ambiguity +diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs +index 7155db32e53b7..cb39e997436e0 100644 +--- a/compiler/rustc_errors/src/diagnostic_impls.rs ++++ b/compiler/rustc_errors/src/diagnostic_impls.rs +@@ -152,6 +152,12 @@ impl IntoDiagnosticArg for ast::Path { + } + } + ++impl IntoDiagnosticArg for &ast::Path { ++ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { ++ DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(self))) ++ } ++} ++ + impl IntoDiagnosticArg for ast::token::Token { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(pprust::token_to_string(&self)) +diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs +index 9d6a4f9a1fd7d..6f159663e80cf 100644 +--- a/compiler/rustc_expand/src/base.rs ++++ b/compiler/rustc_expand/src/base.rs +@@ -1,3 +1,11 @@ ++#![deny(rustc::untranslatable_diagnostic)] ++ ++use crate::errors::{ ++ ArgumentNotAttributes, AttrNoArguments, AttributeMetaItem, AttributeSingleWord, ++ AttributesWrongForm, CannotBeNameOfMacro, ExpectedCommaInList, HelperAttributeNameInvalid, ++ MacroBodyStability, MacroConstStability, NotAMetaItem, OnlyOneArgument, OnlyOneWord, ++ ResolveRelativePath, TakesNoArguments, ++}; + use crate::expand::{self, AstFragment, Invocation}; + use crate::module::DirOwnership; + +@@ -789,26 +797,16 @@ impl SyntaxExtension { + .unwrap_or_else(|| (None, helper_attrs)); + let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span); + if let Some((_, sp)) = const_stability { +- sess.parse_sess +- .span_diagnostic +- .struct_span_err(sp, "macros cannot have const stability attributes") +- .span_label(sp, "invalid const stability attribute") +- .span_label( +- sess.source_map().guess_head_span(span), +- "const stability attribute affects this macro", +- ) +- .emit(); ++ sess.emit_err(MacroConstStability { ++ span: sp, ++ head_span: sess.source_map().guess_head_span(span), ++ }); + } + if let Some((_, sp)) = body_stability { +- sess.parse_sess +- .span_diagnostic +- .struct_span_err(sp, "macros cannot have body stability attributes") +- .span_label(sp, "invalid body stability attribute") +- .span_label( +- sess.source_map().guess_head_span(span), +- "body stability attribute affects this macro", +- ) +- .emit(); ++ sess.emit_err(MacroBodyStability { ++ span: sp, ++ head_span: sess.source_map().guess_head_span(span), ++ }); + } + + SyntaxExtension { +@@ -1200,13 +1198,11 @@ pub fn resolve_path( + .expect("attempting to resolve a file path in an external file"), + FileName::DocTest(path, _) => path, + other => { +- return Err(parse_sess.span_diagnostic.struct_span_err( ++ return Err(ResolveRelativePath { + span, +- &format!( +- "cannot resolve relative path in non-file source `{}`", +- parse_sess.source_map().filename_for_diagnostics(&other) +- ), +- )); ++ path: parse_sess.source_map().filename_for_diagnostics(&other).to_string(), ++ } ++ .into_diagnostic(&parse_sess.span_diagnostic)); + } + }; + result.pop(); +@@ -1222,6 +1218,8 @@ pub fn resolve_path( + /// The returned bool indicates whether an applicable suggestion has already been + /// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)` + /// indicates that an ast error was encountered. ++// FIXME(Nilstrieb) Make this function setup translatable ++#[allow(rustc::untranslatable_diagnostic)] + pub fn expr_to_spanned_string<'a>( + cx: &'a mut ExtCtxt<'_>, + expr: P, +@@ -1280,9 +1278,9 @@ pub fn expr_to_string( + /// compilation should call + /// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be + /// done as rarely as possible). +-pub fn check_zero_tts(cx: &ExtCtxt<'_>, sp: Span, tts: TokenStream, name: &str) { ++pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) { + if !tts.is_empty() { +- cx.span_err(sp, &format!("{} takes no arguments", name)); ++ cx.emit_err(TakesNoArguments { span, name }); + } + } + +@@ -1304,31 +1302,27 @@ pub fn parse_expr(p: &mut parser::Parser<'_>) -> Option> { + /// expect exactly one string literal, or emit an error and return `None`. + pub fn get_single_str_from_tts( + cx: &mut ExtCtxt<'_>, +- sp: Span, ++ span: Span, + tts: TokenStream, + name: &str, + ) -> Option { + let mut p = cx.new_parser_from_tts(tts); + if p.token == token::Eof { +- cx.span_err(sp, &format!("{} takes 1 argument", name)); ++ cx.emit_err(OnlyOneArgument { span, name }); + return None; + } + let ret = parse_expr(&mut p)?; + let _ = p.eat(&token::Comma); + + if p.token != token::Eof { +- cx.span_err(sp, &format!("{} takes 1 argument", name)); ++ cx.emit_err(OnlyOneArgument { span, name }); + } + expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s) + } + + /// Extracts comma-separated expressions from `tts`. + /// On error, emit it, and return `None`. +-pub fn get_exprs_from_tts( +- cx: &mut ExtCtxt<'_>, +- sp: Span, +- tts: TokenStream, +-) -> Option>> { ++pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, tts: TokenStream) -> Option>> { + let mut p = cx.new_parser_from_tts(tts); + let mut es = Vec::new(); + while p.token != token::Eof { +@@ -1343,7 +1337,7 @@ pub fn get_exprs_from_tts( + continue; + } + if p.token != token::Eof { +- cx.span_err(sp, "expected token: `,`"); ++ cx.emit_err(ExpectedCommaInList { span: p.token.span }); + return None; + } + } +@@ -1353,64 +1347,58 @@ pub fn get_exprs_from_tts( + pub fn parse_macro_name_and_helper_attrs( + diag: &rustc_errors::Handler, + attr: &Attribute, +- descr: &str, ++ macro_type: &str, + ) -> Option<(Symbol, Vec)> { + // Once we've located the `#[proc_macro_derive]` attribute, verify + // that it's of the form `#[proc_macro_derive(Foo)]` or + // `#[proc_macro_derive(Foo, attributes(A, ..))]` + let list = attr.meta_item_list()?; + if list.len() != 1 && list.len() != 2 { +- diag.span_err(attr.span, "attribute must have either one or two arguments"); ++ diag.emit_err(AttrNoArguments { span: attr.span }); + return None; + } + let Some(trait_attr) = list[0].meta_item() else { +- diag.span_err(list[0].span(), "not a meta item"); ++ diag.emit_err(NotAMetaItem {span: list[0].span()}); + return None; + }; + let trait_ident = match trait_attr.ident() { + Some(trait_ident) if trait_attr.is_word() => trait_ident, + _ => { +- diag.span_err(trait_attr.span, "must only be one word"); ++ diag.emit_err(OnlyOneWord { span: trait_attr.span }); + return None; + } + }; + + if !trait_ident.name.can_be_raw() { +- diag.span_err( +- trait_attr.span, +- &format!("`{}` cannot be a name of {} macro", trait_ident, descr), +- ); ++ diag.emit_err(CannotBeNameOfMacro { span: trait_attr.span, trait_ident, macro_type }); + } + + let attributes_attr = list.get(1); + let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr { + if !attr.has_name(sym::attributes) { +- diag.span_err(attr.span(), "second argument must be `attributes`"); ++ diag.emit_err(ArgumentNotAttributes { span: attr.span() }); + } + attr.meta_item_list() + .unwrap_or_else(|| { +- diag.span_err(attr.span(), "attribute must be of form: `attributes(foo, bar)`"); ++ diag.emit_err(AttributesWrongForm { span: attr.span() }); + &[] + }) + .iter() + .filter_map(|attr| { + let Some(attr) = attr.meta_item() else { +- diag.span_err(attr.span(), "not a meta item"); ++ diag.emit_err(AttributeMetaItem { span: attr.span() }); + return None; + }; + + let ident = match attr.ident() { + Some(ident) if attr.is_word() => ident, + _ => { +- diag.span_err(attr.span, "must only be one word"); ++ diag.emit_err(AttributeSingleWord { span: attr.span }); + return None; + } + }; + if !ident.name.can_be_raw() { +- diag.span_err( +- attr.span, +- &format!("`{}` cannot be a name of derive helper attribute", ident), +- ); ++ diag.emit_err(HelperAttributeNameInvalid { span: attr.span, name: ident }); + } + + Some(ident.name) +diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs +index 2510795c2e3ed..f4c6f3386ade2 100644 +--- a/compiler/rustc_expand/src/config.rs ++++ b/compiler/rustc_expand/src/config.rs +@@ -1,5 +1,9 @@ + //! Conditional compilation stripping. + ++use crate::errors::{ ++ FeatureIncludedInEdition, FeatureNotAllowed, FeatureRemoved, FeatureRemovedReason, InvalidCfg, ++ MalformedFeatureAttribute, MalformedFeatureAttributeHelp, RemoveExprNotSupported, ++}; + use rustc_ast::ptr::P; + use rustc_ast::token::{Delimiter, Token, TokenKind}; + use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree}; +@@ -10,7 +14,6 @@ use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem + use rustc_attr as attr; + use rustc_data_structures::fx::FxHashMap; + use rustc_data_structures::map_in_place::MapInPlace; +-use rustc_errors::{error_code, struct_span_err, Applicability, Handler}; + use rustc_feature::{Feature, Features, State as FeatureState}; + use rustc_feature::{ + ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES, +@@ -33,18 +36,12 @@ pub struct StripUnconfigured<'a> { + pub lint_node_id: NodeId, + } + +-fn get_features( +- sess: &Session, +- span_handler: &Handler, +- krate_attrs: &[ast::Attribute], +-) -> Features { +- fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { +- let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed"); +- err.span_label(span, "feature has been removed"); +- if let Some(reason) = reason { +- err.note(reason); +- } +- err.emit(); ++fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features { ++ fn feature_removed(sess: &Session, span: Span, reason: Option<&str>) { ++ sess.emit_err(FeatureRemoved { ++ span, ++ reason: reason.map(|reason| FeatureRemovedReason { reason }), ++ }); + } + + fn active_features_up_to(edition: Edition) -> impl Iterator { +@@ -117,34 +114,34 @@ fn get_features( + continue; + }; + +- let bad_input = |span| { +- struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input") +- }; +- + for mi in list { + let name = match mi.ident() { + Some(ident) if mi.is_word() => ident.name, + Some(ident) => { +- bad_input(mi.span()) +- .span_suggestion( +- mi.span(), +- "expected just one word", +- ident.name, +- Applicability::MaybeIncorrect, +- ) +- .emit(); ++ sess.emit_err(MalformedFeatureAttribute { ++ span: mi.span(), ++ help: MalformedFeatureAttributeHelp::Suggestion { ++ span: mi.span(), ++ suggestion: ident.name, ++ }, ++ }); + continue; + } + None => { +- bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit(); ++ sess.emit_err(MalformedFeatureAttribute { ++ span: mi.span(), ++ help: MalformedFeatureAttributeHelp::Label { span: mi.span() }, ++ }); + continue; + } + }; + +- if let Some(edition) = edition_enabled_features.get(&name) { +- let msg = +- &format!("the feature `{}` is included in the Rust {} edition", name, edition); +- span_handler.struct_span_warn_with_code(mi.span(), msg, error_code!(E0705)).emit(); ++ if let Some(&edition) = edition_enabled_features.get(&name) { ++ sess.emit_warning(FeatureIncludedInEdition { ++ span: mi.span(), ++ feature: name, ++ edition, ++ }); + continue; + } + +@@ -159,7 +156,7 @@ fn get_features( + if let FeatureState::Removed { reason } | FeatureState::Stabilized { reason } = + state + { +- feature_removed(span_handler, mi.span(), *reason); ++ feature_removed(sess, mi.span(), *reason); + continue; + } + } +@@ -173,14 +170,7 @@ fn get_features( + + if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() { + if allowed.iter().all(|f| name.as_str() != f) { +- struct_span_err!( +- span_handler, +- mi.span(), +- E0725, +- "the feature `{}` is not in the list of allowed features", +- name +- ) +- .emit(); ++ sess.emit_err(FeatureNotAllowed { span: mi.span(), name }); + continue; + } + } +@@ -221,7 +211,7 @@ pub fn features( + } + Some(attrs) => { + krate.attrs = attrs; +- let features = get_features(sess, diag, &krate.attrs); ++ let features = get_features(sess, &krate.attrs); + if err_count == diag.err_count() { + // Avoid reconfiguring malformed `cfg_attr`s. + strip_unconfigured.features = Some(&features); +@@ -503,8 +493,7 @@ impl<'a> StripUnconfigured<'a> { + // N.B., this is intentionally not part of the visit_expr() function + // in order for filter_map_expr() to be able to avoid this check + if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(*a)) { +- let msg = "removing an expression is not supported in this position"; +- self.sess.parse_sess.span_diagnostic.span_err(attr.span, msg); ++ self.sess.emit_err(RemoveExprNotSupported { span: attr.span }); + } + + self.process_cfg_attrs(expr); +@@ -513,27 +502,26 @@ impl<'a> StripUnconfigured<'a> { + } + + pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> { +- let error = |span, msg, suggestion: &str| { +- let mut err = sess.parse_sess.span_diagnostic.struct_span_err(span, msg); +- if !suggestion.is_empty() { +- err.span_suggestion( +- span, +- "expected syntax is", +- suggestion, +- Applicability::HasPlaceholders, +- ); +- } +- err.emit(); +- None +- }; + let span = meta_item.span; + match meta_item.meta_item_list() { +- None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"), +- Some([]) => error(span, "`cfg` predicate is not specified", ""), +- Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""), ++ None => { ++ sess.emit_err(InvalidCfg::NotFollowedByParens { span }); ++ None ++ } ++ Some([]) => { ++ sess.emit_err(InvalidCfg::NoPredicate { span }); ++ None ++ } ++ Some([_, .., l]) => { ++ sess.emit_err(InvalidCfg::MultiplePredicates { span: l.span() }); ++ None ++ } + Some([single]) => match single.meta_item() { + Some(meta_item) => Some(meta_item), +- None => error(single.span(), "`cfg` predicate key cannot be a literal", ""), ++ None => { ++ sess.emit_err(InvalidCfg::PredicateLiteral { span: single.span() }); ++ None ++ } + }, + } + } +diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs +index d383f4832f699..afe5169d3f5c0 100644 +--- a/compiler/rustc_expand/src/errors.rs ++++ b/compiler/rustc_expand/src/errors.rs +@@ -1,6 +1,10 @@ ++use rustc_ast::ast; + use rustc_macros::Diagnostic; +-use rustc_span::symbol::MacroRulesNormalizedIdent; +-use rustc_span::Span; ++use rustc_session::Limit; ++use rustc_span::edition::Edition; ++use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; ++use rustc_span::{Span, Symbol}; ++use std::borrow::Cow; + + #[derive(Diagnostic)] + #[diag(expand_expr_repeat_no_syntax_vars)] +@@ -46,3 +50,321 @@ pub(crate) struct MetaVarsDifSeqMatchers { + pub span: Span, + pub msg: String, + } ++ ++#[derive(Diagnostic)] ++#[diag(expand_resolve_relative_path)] ++pub(crate) struct ResolveRelativePath { ++ #[primary_span] ++ pub span: Span, ++ pub path: String, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_macro_const_stability)] ++pub(crate) struct MacroConstStability { ++ #[primary_span] ++ #[label] ++ pub span: Span, ++ #[label(label2)] ++ pub head_span: Span, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_macro_body_stability)] ++pub(crate) struct MacroBodyStability { ++ #[primary_span] ++ #[label] ++ pub span: Span, ++ #[label(label2)] ++ pub head_span: Span, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_attr_no_arguments)] ++pub(crate) struct AttrNoArguments { ++ #[primary_span] ++ pub span: Span, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_not_a_meta_item)] ++pub(crate) struct NotAMetaItem { ++ #[primary_span] ++ pub span: Span, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_only_one_word)] ++pub(crate) struct OnlyOneWord { ++ #[primary_span] ++ pub span: Span, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_cannot_be_name_of_macro)] ++pub(crate) struct CannotBeNameOfMacro<'a> { ++ #[primary_span] ++ pub span: Span, ++ pub trait_ident: Ident, ++ pub macro_type: &'a str, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_arg_not_attributes)] ++pub(crate) struct ArgumentNotAttributes { ++ #[primary_span] ++ pub span: Span, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_attributes_wrong_form)] ++pub(crate) struct AttributesWrongForm { ++ #[primary_span] ++ pub span: Span, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_attribute_meta_item)] ++pub(crate) struct AttributeMetaItem { ++ #[primary_span] ++ pub span: Span, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_attribute_single_word)] ++pub(crate) struct AttributeSingleWord { ++ #[primary_span] ++ pub span: Span, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_helper_attribute_name_invalid)] ++pub(crate) struct HelperAttributeNameInvalid { ++ #[primary_span] ++ pub span: Span, ++ pub name: Ident, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_expected_comma_in_list)] ++pub(crate) struct ExpectedCommaInList { ++ #[primary_span] ++ pub span: Span, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_only_one_argument)] ++pub(crate) struct OnlyOneArgument<'a> { ++ #[primary_span] ++ pub span: Span, ++ pub name: &'a str, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_takes_no_arguments)] ++pub(crate) struct TakesNoArguments<'a> { ++ #[primary_span] ++ pub span: Span, ++ pub name: &'a str, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_feature_included_in_edition, code = "E0705")] ++pub(crate) struct FeatureIncludedInEdition { ++ #[primary_span] ++ pub span: Span, ++ pub feature: Symbol, ++ pub edition: Edition, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_feature_removed, code = "E0557")] ++pub(crate) struct FeatureRemoved<'a> { ++ #[primary_span] ++ #[label] ++ pub span: Span, ++ #[subdiagnostic] ++ pub reason: Option>, ++} ++ ++#[derive(Subdiagnostic)] ++#[note(reason)] ++pub(crate) struct FeatureRemovedReason<'a> { ++ pub reason: &'a str, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_feature_not_allowed, code = "E0725")] ++pub(crate) struct FeatureNotAllowed { ++ #[primary_span] ++ pub span: Span, ++ pub name: Symbol, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_recursion_limit_reached)] ++#[help] ++pub(crate) struct RecursionLimitReached<'a> { ++ #[primary_span] ++ pub span: Span, ++ pub descr: String, ++ pub suggested_limit: Limit, ++ pub crate_name: &'a str, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_malformed_feature_attribute, code = "E0556")] ++pub(crate) struct MalformedFeatureAttribute { ++ #[primary_span] ++ pub span: Span, ++ #[subdiagnostic] ++ pub help: MalformedFeatureAttributeHelp, ++} ++ ++#[derive(Subdiagnostic)] ++pub(crate) enum MalformedFeatureAttributeHelp { ++ #[label(expected)] ++ Label { ++ #[primary_span] ++ span: Span, ++ }, ++ #[suggestion(expected, code = "{suggestion}", applicability = "maybe-incorrect")] ++ Suggestion { ++ #[primary_span] ++ span: Span, ++ suggestion: Symbol, ++ }, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_remove_expr_not_supported)] ++pub(crate) struct RemoveExprNotSupported { ++ #[primary_span] ++ pub span: Span, ++} ++ ++#[derive(Diagnostic)] ++pub(crate) enum InvalidCfg { ++ #[diag(expand_invalid_cfg_no_parens)] ++ NotFollowedByParens { ++ #[primary_span] ++ #[suggestion( ++ expand_invalid_cfg_expected_syntax, ++ code = "cfg(/* predicate */)", ++ applicability = "has-placeholders" ++ )] ++ span: Span, ++ }, ++ #[diag(expand_invalid_cfg_no_predicate)] ++ NoPredicate { ++ #[primary_span] ++ #[suggestion( ++ expand_invalid_cfg_expected_syntax, ++ code = "cfg(/* predicate */)", ++ applicability = "has-placeholders" ++ )] ++ span: Span, ++ }, ++ #[diag(expand_invalid_cfg_multiple_predicates)] ++ MultiplePredicates { ++ #[primary_span] ++ span: Span, ++ }, ++ #[diag(expand_invalid_cfg_predicate_literal)] ++ PredicateLiteral { ++ #[primary_span] ++ span: Span, ++ }, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_wrong_fragment_kind)] ++pub(crate) struct WrongFragmentKind<'a> { ++ #[primary_span] ++ pub span: Span, ++ pub kind: &'a str, ++ pub name: &'a ast::Path, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_unsupported_key_value)] ++pub(crate) struct UnsupportedKeyValue { ++ #[primary_span] ++ pub span: Span, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_incomplete_parse)] ++#[note] ++pub(crate) struct IncompleteParse<'a> { ++ #[primary_span] ++ pub span: Span, ++ pub token: Cow<'a, str>, ++ #[label] ++ pub label_span: Span, ++ pub macro_path: &'a ast::Path, ++ pub kind_name: &'a str, ++ ++ #[suggestion( ++ suggestion_add_semi, ++ style = "verbose", ++ code = ";", ++ applicability = "maybe-incorrect" ++ )] ++ pub add_semicolon: Option, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_remove_node_not_supported)] ++pub(crate) struct RemoveNodeNotSupported { ++ #[primary_span] ++ pub span: Span, ++ pub descr: &'static str, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_module_circular)] ++pub(crate) struct ModuleCircular { ++ #[primary_span] ++ pub span: Span, ++ pub modules: String, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_module_in_block)] ++pub(crate) struct ModuleInBlock { ++ #[primary_span] ++ pub span: Span, ++ #[subdiagnostic] ++ pub name: Option, ++} ++ ++#[derive(Subdiagnostic)] ++#[note(note)] ++pub(crate) struct ModuleInBlockName { ++ #[primary_span] ++ pub span: Span, ++ pub name: Ident, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_module_file_not_found, code = "E0583")] ++#[help] ++pub(crate) struct ModuleFileNotFound { ++ #[primary_span] ++ pub span: Span, ++ pub name: Ident, ++ pub default_path: String, ++ pub secondary_path: String, ++} ++ ++#[derive(Diagnostic)] ++#[diag(expand_module_multiple_candidates, code = "E0761")] ++#[help] ++pub(crate) struct ModuleMultipleCandidates { ++ #[primary_span] ++ pub span: Span, ++ pub name: Ident, ++ pub default_path: String, ++ pub secondary_path: String, ++} +diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs +index 1014ec2209c61..e26c16dcd7ee7 100644 +--- a/compiler/rustc_expand/src/expand.rs ++++ b/compiler/rustc_expand/src/expand.rs +@@ -1,5 +1,9 @@ + use crate::base::*; + use crate::config::StripUnconfigured; ++use crate::errors::{ ++ IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, ++ UnsupportedKeyValue, WrongFragmentKind, ++}; + use crate::hygiene::SyntaxContext; + use crate::mbe::diagnostics::annotate_err_with_kind; + use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; +@@ -18,7 +22,7 @@ use rustc_ast::{NestedMetaItem, NodeId, PatKind, StmtKind, TyKind}; + use rustc_ast_pretty::pprust; + use rustc_data_structures::map_in_place::MapInPlace; + use rustc_data_structures::sync::Lrc; +-use rustc_errors::{Applicability, PResult}; ++use rustc_errors::PResult; + use rustc_feature::Features; + use rustc_parse::parser::{ + AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma, +@@ -606,29 +610,22 @@ impl<'a, 'b> MacroExpander<'a, 'b> { + Limit(0) => Limit(2), + limit => limit * 2, + }; +- self.cx +- .struct_span_err( +- expn_data.call_site, +- &format!("recursion limit reached while expanding `{}`", expn_data.kind.descr()), +- ) +- .help(&format!( +- "consider increasing the recursion limit by adding a \ +- `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", +- suggested_limit, self.cx.ecfg.crate_name, +- )) +- .emit(); ++ ++ self.cx.emit_err(RecursionLimitReached { ++ span: expn_data.call_site, ++ descr: expn_data.kind.descr(), ++ suggested_limit, ++ crate_name: &self.cx.ecfg.crate_name, ++ }); ++ + self.cx.trace_macros_diag(); + } + + /// A macro's expansion does not fit in this fragment kind. + /// For example, a non-type macro in a type position. + fn error_wrong_fragment_kind(&mut self, kind: AstFragmentKind, mac: &ast::MacCall, span: Span) { +- let msg = format!( +- "non-{kind} macro in {kind} position: {path}", +- kind = kind.name(), +- path = pprust::path_to_string(&mac.path), +- ); +- self.cx.span_err(span, &msg); ++ self.cx.emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path }); ++ + self.cx.trace_macros_diag(); + } + +@@ -707,7 +704,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { + }; + let attr_item = attr.unwrap_normal_item(); + if let AttrArgs::Eq(..) = attr_item.args { +- self.cx.span_err(span, "key-value macro attributes are not supported"); ++ self.cx.emit_err(UnsupportedKeyValue { span }); + } + let inner_tokens = attr_item.args.inner_tokens(); + let Ok(tok_result) = expander.expand(self.cx, span, inner_tokens, tokens) else { +@@ -729,9 +726,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { + } + }; + if fragment_kind == AstFragmentKind::Expr && items.is_empty() { +- let msg = +- "removing an expression is not supported in this position"; +- self.cx.span_err(span, msg); ++ self.cx.emit_err(RemoveExprNotSupported { span }); + fragment_kind.dummy(span) + } else { + fragment_kind.expect_from_annotatables(items) +@@ -939,38 +934,32 @@ pub fn parse_ast_fragment<'a>( + } + + pub fn ensure_complete_parse<'a>( +- this: &mut Parser<'a>, ++ parser: &mut Parser<'a>, + macro_path: &ast::Path, + kind_name: &str, + span: Span, + ) { +- if this.token != token::Eof { +- let token = pprust::token_to_string(&this.token); +- let msg = format!("macro expansion ignores token `{}` and any following", token); ++ if parser.token != token::Eof { ++ let token = pprust::token_to_string(&parser.token); + // Avoid emitting backtrace info twice. +- let def_site_span = this.token.span.with_ctxt(SyntaxContext::root()); +- let mut err = this.struct_span_err(def_site_span, &msg); +- err.span_label(span, "caused by the macro expansion here"); +- let msg = format!( +- "the usage of `{}!` is likely invalid in {} context", +- pprust::path_to_string(macro_path), +- kind_name, +- ); +- err.note(&msg); ++ let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root()); + +- let semi_span = this.sess.source_map().next_point(span); +- match this.sess.source_map().span_to_snippet(semi_span) { ++ let semi_span = parser.sess.source_map().next_point(span); ++ let add_semicolon = match parser.sess.source_map().span_to_snippet(semi_span) { + Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => { +- err.span_suggestion( +- span.shrink_to_hi(), +- "you might be missing a semicolon here", +- ";", +- Applicability::MaybeIncorrect, +- ); ++ Some(span.shrink_to_hi()) + } +- _ => {} +- } +- err.emit(); ++ _ => None, ++ }; ++ ++ parser.sess.emit_err(IncompleteParse { ++ span: def_site_span, ++ token, ++ label_span: span, ++ macro_path, ++ kind_name, ++ add_semicolon, ++ }); + } + } + +@@ -1766,9 +1755,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { + if self.expand_cfg_true(node, attr, pos) { + continue; + } +- let msg = +- format!("removing {} is not supported in this position", Node::descr()); +- self.cx.span_err(span, &msg); ++ ++ self.cx.emit_err(RemoveNodeNotSupported { span, descr: Node::descr() }); + continue; + } + sym::cfg_attr => { +diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs +index b34de94fb7db4..897268566358a 100644 +--- a/compiler/rustc_expand/src/lib.rs ++++ b/compiler/rustc_expand/src/lib.rs +@@ -10,6 +10,7 @@ + #![feature(rustc_attrs)] + #![feature(try_blocks)] + #![recursion_limit = "256"] ++#![deny(rustc::untranslatable_diagnostic)] + + #[macro_use] + extern crate rustc_macros; +@@ -31,8 +32,13 @@ pub mod config; + pub mod errors; + pub mod expand; + pub mod module; ++ ++// FIXME(Nilstrieb) Translate proc_macro diagnostics ++#[allow(rustc::untranslatable_diagnostic)] + pub mod proc_macro; + ++// FIXME(Nilstrieb) Translate macro_rules diagnostics ++#[allow(rustc::untranslatable_diagnostic)] + pub(crate) mod mbe; + + // HACK(Centril, #64197): These shouldn't really be here. +diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs +index 9002a24e42f9d..07f47a9c3a4f2 100644 +--- a/compiler/rustc_expand/src/module.rs ++++ b/compiler/rustc_expand/src/module.rs +@@ -1,13 +1,17 @@ + use crate::base::ModuleData; ++use crate::errors::{ ++ ModuleCircular, ModuleFileNotFound, ModuleInBlock, ModuleInBlockName, ModuleMultipleCandidates, ++}; + use rustc_ast::ptr::P; + use rustc_ast::{token, AttrVec, Attribute, Inline, Item, ModSpans}; +-use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorGuaranteed}; ++use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; + use rustc_parse::new_parser_from_file; + use rustc_parse::validate_attr; + use rustc_session::parse::ParseSess; + use rustc_session::Session; + use rustc_span::symbol::{sym, Ident}; + use rustc_span::Span; ++use std::iter::once; + + use std::path::{self, Path, PathBuf}; + +@@ -242,57 +246,41 @@ pub fn default_submod_path<'a>( + + impl ModError<'_> { + fn report(self, sess: &Session, span: Span) -> ErrorGuaranteed { +- let diag = &sess.parse_sess.span_diagnostic; + match self { + ModError::CircularInclusion(file_paths) => { +- let mut msg = String::from("circular modules: "); +- for file_path in &file_paths { +- msg.push_str(&file_path.display().to_string()); +- msg.push_str(" -> "); +- } +- msg.push_str(&file_paths[0].display().to_string()); +- diag.struct_span_err(span, &msg) +- } +- ModError::ModInBlock(ident) => { +- let msg = "cannot declare a non-inline module inside a block unless it has a path attribute"; +- let mut err = diag.struct_span_err(span, msg); +- if let Some(ident) = ident { +- let note = +- format!("maybe `use` the module `{}` instead of redeclaring it", ident); +- err.span_note(span, ¬e); +- } +- err ++ let path_to_string = |path: &PathBuf| path.display().to_string(); ++ ++ let paths = file_paths ++ .iter() ++ .map(path_to_string) ++ .chain(once(path_to_string(&file_paths[0]))) ++ .collect::>(); ++ ++ let modules = paths.join(" -> "); ++ ++ sess.emit_err(ModuleCircular { span, modules }) + } +- ModError::FileNotFound(ident, default_path, secondary_path) => { +- let mut err = struct_span_err!( +- diag, ++ ModError::ModInBlock(ident) => sess.emit_err(ModuleInBlock { ++ span, ++ name: ident.map(|name| ModuleInBlockName { span, name }), ++ }), ++ ModError::FileNotFound(name, default_path, secondary_path) => { ++ sess.emit_err(ModuleFileNotFound { + span, +- E0583, +- "file not found for module `{}`", +- ident, +- ); +- err.help(&format!( +- "to create the module `{}`, create file \"{}\" or \"{}\"", +- ident, +- default_path.display(), +- secondary_path.display(), +- )); +- err ++ name, ++ default_path: default_path.display().to_string(), ++ secondary_path: secondary_path.display().to_string(), ++ }) + } +- ModError::MultipleCandidates(ident, default_path, secondary_path) => { +- let mut err = struct_span_err!( +- diag, ++ ModError::MultipleCandidates(name, default_path, secondary_path) => { ++ sess.emit_err(ModuleMultipleCandidates { + span, +- E0761, +- "file for module `{}` found at both \"{}\" and \"{}\"", +- ident, +- default_path.display(), +- secondary_path.display(), +- ); +- err.help("delete or rename one of them to remove the ambiguity"); +- err ++ name, ++ default_path: default_path.display().to_string(), ++ secondary_path: secondary_path.display().to_string(), ++ }) + } +- ModError::ParserError(err) => err, +- }.emit() ++ ModError::ParserError(mut err) => err.emit(), ++ } + } + } +diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs +index 539b04535a0d0..8f3bea29ffd28 100644 +--- a/compiler/rustc_expand/src/tests.rs ++++ b/compiler/rustc_expand/src/tests.rs +@@ -154,6 +154,7 @@ fn test_harness(file_text: &str, span_labels: Vec, expected_output: & + false, + ); + let handler = Handler::with_emitter(true, None, Box::new(emitter)); ++ #[allow(rustc::untranslatable_diagnostic)] + handler.span_err(msp, "foo"); + + assert!( +diff --git a/src/test/rustdoc-ui/doc-cfg.stderr b/src/test/rustdoc-ui/doc-cfg.stderr +index b379f6febe29f..14b7b17e04d3a 100644 +--- a/src/test/rustdoc-ui/doc-cfg.stderr ++++ b/src/test/rustdoc-ui/doc-cfg.stderr +@@ -2,7 +2,7 @@ error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:3:7 + | + LL | #[doc(cfg(), cfg(foo, bar))] +- | ^^^^^ ++ | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` + + error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:3:23 +@@ -14,7 +14,7 @@ error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:7:7 + | + LL | #[doc(cfg())] +- | ^^^^^ ++ | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` + + error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:8:16 +diff --git a/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +index d4bd673b84e1b..d5b4349c00f6f 100644 +--- a/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr ++++ b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +@@ -14,7 +14,7 @@ error: `cfg` predicate is not specified + --> $DIR/cfg-attr-syntax-validation.rs:7:1 + | + LL | #[cfg()] +- | ^^^^^^^^ ++ | ^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + + error: multiple `cfg` predicates are specified + --> $DIR/cfg-attr-syntax-validation.rs:10:10 +diff --git a/src/test/ui/macros/macro-in-expression-context.stderr b/src/test/ui/macros/macro-in-expression-context.stderr +index 1023189eaa30f..36aba8aa08a0b 100644 +--- a/src/test/ui/macros/macro-in-expression-context.stderr ++++ b/src/test/ui/macros/macro-in-expression-context.stderr +@@ -5,11 +5,13 @@ LL | assert_eq!("B", "B"); + | ^^^^^^^^^ + ... + LL | foo!() +- | ------- help: you might be missing a semicolon here: `;` +- | | +- | caused by the macro expansion here ++ | ------ caused by the macro expansion here + | + = note: the usage of `foo!` is likely invalid in expression context ++help: you might be missing a semicolon here ++ | ++LL | foo!(); ++ | + + + warning: trailing semicolon in macro used in expression position + --> $DIR/macro-in-expression-context.rs:5:29 +diff --git a/src/test/ui/proc-macro/attr-invalid-exprs.stderr b/src/test/ui/proc-macro/attr-invalid-exprs.stderr +index bcb54df0ecac7..f96939bb6efce 100644 +--- a/src/test/ui/proc-macro/attr-invalid-exprs.stderr ++++ b/src/test/ui/proc-macro/attr-invalid-exprs.stderr +@@ -8,21 +8,25 @@ error: macro expansion ignores token `,` and any following + --> $DIR/attr-invalid-exprs.rs:15:13 + | + LL | let _ = #[duplicate] "Hello, world!"; +- | ^^^^^^^^^^^^- help: you might be missing a semicolon here: `;` +- | | +- | caused by the macro expansion here ++ | ^^^^^^^^^^^^ caused by the macro expansion here + | + = note: the usage of `duplicate!` is likely invalid in expression context ++help: you might be missing a semicolon here ++ | ++LL | let _ = #[duplicate]; "Hello, world!"; ++ | + + + error: macro expansion ignores token `,` and any following + --> $DIR/attr-invalid-exprs.rs:24:9 + | + LL | #[duplicate] +- | ^^^^^^^^^^^^- help: you might be missing a semicolon here: `;` +- | | +- | caused by the macro expansion here ++ | ^^^^^^^^^^^^ caused by the macro expansion here + | + = note: the usage of `duplicate!` is likely invalid in expression context ++help: you might be missing a semicolon here ++ | ++LL | #[duplicate]; ++ | + + + error: aborting due to 3 previous errors + +diff --git a/src/test/ui/proc-macro/attribute.rs b/src/test/ui/proc-macro/attribute.rs +index 5531b32362125..9e40e4d9ba63e 100644 +--- a/src/test/ui/proc-macro/attribute.rs ++++ b/src/test/ui/proc-macro/attribute.rs +@@ -53,19 +53,19 @@ pub fn foo11(input: TokenStream) -> TokenStream { input } + pub fn foo12(input: TokenStream) -> TokenStream { input } + + #[proc_macro_derive(d13, attributes("a"))] +-//~^ ERROR: not a meta item ++//~^ ERROR: attribute must be a meta item, not a literal + pub fn foo13(input: TokenStream) -> TokenStream { input } + + #[proc_macro_derive(d14, attributes(a = ""))] +-//~^ ERROR: must only be one word ++//~^ ERROR: attribute must only be a single word + pub fn foo14(input: TokenStream) -> TokenStream { input } + + #[proc_macro_derive(d15, attributes(m::a))] +-//~^ ERROR: must only be one word ++//~^ ERROR: attribute must only be a single word + pub fn foo15(input: TokenStream) -> TokenStream { input } + + #[proc_macro_derive(d16, attributes(a(b)))] +-//~^ ERROR: must only be one word ++//~^ ERROR: attribute must only be a single word + pub fn foo16(input: TokenStream) -> TokenStream { input } + + #[proc_macro_derive(d17, attributes(self))] +diff --git a/src/test/ui/proc-macro/attribute.stderr b/src/test/ui/proc-macro/attribute.stderr +index 021e7cad09b69..3269aaf7f917e 100644 +--- a/src/test/ui/proc-macro/attribute.stderr ++++ b/src/test/ui/proc-macro/attribute.stderr +@@ -70,25 +70,25 @@ error: attribute must be of form: `attributes(foo, bar)` + LL | #[proc_macro_derive(d12, attributes)] + | ^^^^^^^^^^ + +-error: not a meta item ++error: attribute must be a meta item, not a literal + --> $DIR/attribute.rs:55:37 + | + LL | #[proc_macro_derive(d13, attributes("a"))] + | ^^^ + +-error: must only be one word ++error: attribute must only be a single word + --> $DIR/attribute.rs:59:37 + | + LL | #[proc_macro_derive(d14, attributes(a = ""))] + | ^^^^^^ + +-error: must only be one word ++error: attribute must only be a single word + --> $DIR/attribute.rs:63:37 + | + LL | #[proc_macro_derive(d15, attributes(m::a))] + | ^^^^ + +-error: must only be one word ++error: attribute must only be a single word + --> $DIR/attribute.rs:67:37 + | + LL | #[proc_macro_derive(d16, attributes(a(b)))] +diff --git a/src/test/ui/proc-macro/expand-expr.stderr b/src/test/ui/proc-macro/expand-expr.stderr +index c6c4695fd9c43..0004f2fe17f01 100644 +--- a/src/test/ui/proc-macro/expand-expr.stderr ++++ b/src/test/ui/proc-macro/expand-expr.stderr +@@ -26,21 +26,25 @@ error: macro expansion ignores token `hello` and any following + --> $DIR/expand-expr.rs:115:47 + | + LL | expand_expr_is!("string", echo_tts!("string"; hello)); +- | --------------------^^^^^-- help: you might be missing a semicolon here: `;` +- | | +- | caused by the macro expansion here ++ | --------------------^^^^^- caused by the macro expansion here + | + = note: the usage of `echo_tts!` is likely invalid in expression context ++help: you might be missing a semicolon here ++ | ++LL | expand_expr_is!("string", echo_tts!("string"; hello);); ++ | + + + error: macro expansion ignores token `;` and any following + --> $DIR/expand-expr.rs:116:44 + | + LL | expand_expr_is!("string", echo_pm!("string"; hello)); +- | -----------------^-------- help: you might be missing a semicolon here: `;` +- | | +- | caused by the macro expansion here ++ | -----------------^------- caused by the macro expansion here + | + = note: the usage of `echo_pm!` is likely invalid in expression context ++help: you might be missing a semicolon here ++ | ++LL | expand_expr_is!("string", echo_pm!("string"; hello);); ++ | + + + error: recursion limit reached while expanding `recursive_expand!` + --> $DIR/expand-expr.rs:124:16 -- cgit v1.2.3