diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 2a5bc58af3b..0f158990319 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -118,6 +118,8 @@ builtin_macros_env_not_unicode = environment variable `{$var}` is not a valid Un
builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
+builtin_macros_expected_comma_in_list = expected token: `,`
+
builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
builtin_macros_expected_register_class_or_explicit_register = expected register class or explicit register
@@ -219,12 +221,16 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive
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_only_one_argument = {$name} takes 1 argument
+
builtin_macros_proc_macro = `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
builtin_macros_requires_cfg_pattern =
macro requires a cfg-pattern as an argument
.label = cfg-pattern required
+builtin_macros_takes_no_arguments = {$name} takes no arguments
+
builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests
.label = `{$kind}` because of this
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 137ac441579..49b1b8cf992 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -1,3 +1,5 @@
+use crate::errors;
+use crate::util::expr_to_spanned_string;
use ast::token::IdentIsRaw;
use rustc_ast as ast;
use rustc_ast::ptr::P;
@@ -16,8 +18,6 @@ use rustc_span::{ErrorGuaranteed, InnerSpan, Span};
use rustc_target::asm::InlineAsmArch;
use smallvec::smallvec;
-use crate::errors;
-
pub struct AsmArgs {
pub templates: Vec
>,
pub operands: Vec<(ast::InlineAsmOperand, Span)>,
diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs
index 2f2a87fc9aa..833e9cb5d75 100644
--- a/compiler/rustc_builtin_macros/src/compile_error.rs
+++ b/compiler/rustc_builtin_macros/src/compile_error.rs
@@ -1,7 +1,7 @@
// The compiler code necessary to support the compile_error! extension.
+use crate::util::get_single_str_from_tts;
use rustc_ast::tokenstream::TokenStream;
-use rustc_expand::base::get_single_str_from_tts;
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
use rustc_span::Span;
diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs
index 93a7ac05a9b..125f4bc6dc4 100644
--- a/compiler/rustc_builtin_macros/src/concat.rs
+++ b/compiler/rustc_builtin_macros/src/concat.rs
@@ -1,12 +1,11 @@
+use crate::errors;
+use crate::util::get_exprs_from_tts;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{ExprKind, LitKind, UnOp};
-use rustc_expand::base::get_exprs_from_tts;
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_session::errors::report_lit_error;
use rustc_span::symbol::Symbol;
-use crate::errors;
-
pub fn expand_concat(
cx: &mut ExtCtxt<'_>,
sp: rustc_span::Span,
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index 45fec294578..f9d3f4a1425 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -1,11 +1,10 @@
+use crate::errors;
+use crate::util::get_exprs_from_tts;
use rustc_ast::{ptr::P, token, tokenstream::TokenStream, ExprKind, LitIntType, LitKind, UintTy};
-use rustc_expand::base::get_exprs_from_tts;
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_session::errors::report_lit_error;
use rustc_span::{ErrorGuaranteed, Span};
-use crate::errors;
-
/// Emits errors for literal expressions that are invalid inside and outside of an array.
fn invalid_type_err(
cx: &ExtCtxt<'_>,
diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs
index 93873045943..3903c77b669 100644
--- a/compiler/rustc_builtin_macros/src/env.rs
+++ b/compiler/rustc_builtin_macros/src/env.rs
@@ -3,10 +3,11 @@
// interface.
//
+use crate::errors;
+use crate::util::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts};
use rustc_ast::token::{self, LitKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability};
-use rustc_expand::base::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
@@ -14,8 +15,6 @@ use std::env;
use std::env::VarError;
use thin_vec::thin_vec;
-use crate::errors;
-
fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result {
let var = var.as_str();
if let Some(value) = cx.sess.opts.logical_env.get(var) {
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 6b6647ef085..055ff79a8ad 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -842,3 +842,26 @@ pub(crate) struct ExpectedRegisterClassOrExplicitRegister {
#[primary_span]
pub(crate) span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_expected_comma_in_list)]
+pub(crate) struct ExpectedCommaInList {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_only_one_argument)]
+pub(crate) struct OnlyOneArgument<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_takes_no_arguments)]
+pub(crate) struct TakesNoArguments<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: &'a str,
+}
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 51d6058a744..3f44096714c 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -1,3 +1,5 @@
+use crate::errors;
+use crate::util::expr_to_spanned_string;
use parse::Position::ArgumentNamed;
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
@@ -10,14 +12,13 @@ use rustc_ast::{
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans};
use rustc_expand::base::*;
+use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
+use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
use rustc_parse::parser::Recovered;
use rustc_parse_format as parse;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{BytePos, ErrorGuaranteed, InnerSpan, Span};
-use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
-use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
-
// The format_args!() macro is expanded in three steps:
// 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax,
// but doesn't parse the template (the literal) itself.
@@ -38,8 +39,6 @@ enum PositionUsedAs {
}
use PositionUsedAs::*;
-use crate::errors;
-
#[derive(Debug)]
struct MacroInput {
fmtstr: P,
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 56a72432689..7c7b9c2d65f 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -50,13 +50,13 @@ mod pattern_type;
mod source_util;
mod test;
mod trace_macros;
-mod util;
pub mod asm;
pub mod cmdline_attrs;
pub mod proc_macro_harness;
pub mod standard_library_imports;
pub mod test_harness;
+pub mod util;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index c79ae716806..033c7446b26 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -1,3 +1,6 @@
+use crate::util::{
+ check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
+};
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::token;
@@ -5,11 +8,8 @@ use rustc_ast::tokenstream::TokenStream;
use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc;
use rustc_expand::base::{
- check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
- resolve_path,
+ resolve_path, DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult,
};
-use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt};
-use rustc_expand::base::{MacEager, MacResult, MacroExpanderResult};
use rustc_expand::module::DirOwnership;
use rustc_parse::new_parser_from_file;
use rustc_parse::parser::{ForceCollect, Parser};
diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs
index ad6b09ba574..49687c6a0ad 100644
--- a/compiler/rustc_builtin_macros/src/util.rs
+++ b/compiler/rustc_builtin_macros/src/util.rs
@@ -1,9 +1,14 @@
-use rustc_ast::{attr, AttrStyle, Attribute, MetaItem};
-use rustc_expand::base::{Annotatable, ExtCtxt};
+use crate::errors;
+use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::{self as ast, attr, ptr::P, token, AttrStyle, Attribute, MetaItem};
+use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
+use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt};
+use rustc_expand::expand::AstFragment;
use rustc_feature::AttributeTemplate;
use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
-use rustc_parse::validate_attr;
-use rustc_span::Symbol;
+use rustc_parse::{parser, validate_attr};
+use rustc_session::errors::report_lit_error;
+use rustc_span::{BytePos, Span, Symbol};
pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
// All the built-in macro attributes are "words" at the moment.
@@ -46,3 +51,178 @@ pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name:
}
}
}
+
+/// `Ok` represents successfully retrieving the string literal at the correct
+/// position, e.g., `println("abc")`.
+type ExprToSpannedStringResult<'a> = Result<(Symbol, ast::StrStyle, Span), UnexpectedExprKind<'a>>;
+
+/// - `Ok` is returned when the conversion to a string literal is unsuccessful,
+/// but another type of expression is obtained instead.
+/// - `Err` is returned when the conversion process fails.
+type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), ErrorGuaranteed>;
+
+/// Extracts a string literal from the macro expanded version of `expr`,
+/// returning a diagnostic error of `err_msg` if `expr` is not a string literal.
+/// The returned bool indicates whether an applicable suggestion has already been
+/// added to the diagnostic to avoid emitting multiple suggestions. `Err(Err(ErrorGuaranteed))`
+/// indicates that an ast error was encountered.
+// FIXME(Nilstrieb) Make this function setup translatable
+#[allow(rustc::untranslatable_diagnostic)]
+pub(crate) fn expr_to_spanned_string<'a>(
+ cx: &'a mut ExtCtxt<'_>,
+ expr: P,
+ err_msg: &'static str,
+) -> ExpandResult, ()> {
+ if !cx.force_mode
+ && let ast::ExprKind::MacCall(m) = &expr.kind
+ && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err()
+ {
+ return ExpandResult::Retry(());
+ }
+
+ // Perform eager expansion on the expression.
+ // We want to be able to handle e.g., `concat!("foo", "bar")`.
+ let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
+
+ ExpandResult::Ready(Err(match expr.kind {
+ ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
+ Ok(ast::LitKind::Str(s, style)) => {
+ return ExpandResult::Ready(Ok((s, style, expr.span)));
+ }
+ Ok(ast::LitKind::ByteStr(..)) => {
+ let mut err = cx.dcx().struct_span_err(expr.span, err_msg);
+ let span = expr.span.shrink_to_lo();
+ err.span_suggestion(
+ span.with_hi(span.lo() + BytePos(1)),
+ "consider removing the leading `b`",
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ Ok((err, true))
+ }
+ Ok(ast::LitKind::Err(guar)) => Err(guar),
+ Err(err) => Err(report_lit_error(&cx.sess.psess, err, token_lit, expr.span)),
+ _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)),
+ },
+ ast::ExprKind::Err(guar) => Err(guar),
+ ast::ExprKind::Dummy => {
+ cx.dcx().span_bug(expr.span, "tried to get a string literal from `ExprKind::Dummy`")
+ }
+ _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)),
+ }))
+}
+
+/// Extracts a string literal from the macro expanded version of `expr`,
+/// emitting `err_msg` if `expr` is not a string literal. This does not stop
+/// compilation on error, merely emits a non-fatal error and returns `Err`.
+pub(crate) fn expr_to_string(
+ cx: &mut ExtCtxt<'_>,
+ expr: P,
+ err_msg: &'static str,
+) -> ExpandResult, ()> {
+ expr_to_spanned_string(cx, expr, err_msg).map(|res| {
+ res.map_err(|err| match err {
+ Ok((err, _)) => err.emit(),
+ Err(guar) => guar,
+ })
+ .map(|(symbol, style, _)| (symbol, style))
+ })
+}
+
+/// Non-fatally assert that `tts` is empty. Note that this function
+/// returns even when `tts` is non-empty, macros that *need* to stop
+/// compilation should call `cx.diagnostic().abort_if_errors()`
+/// (this should be done as rarely as possible).
+pub(crate) fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) {
+ if !tts.is_empty() {
+ cx.dcx().emit_err(errors::TakesNoArguments { span, name });
+ }
+}
+
+/// Parse an expression. On error, emit it, advancing to `Eof`, and return `Err`.
+pub(crate) fn parse_expr(p: &mut parser::Parser<'_>) -> Result, ErrorGuaranteed> {
+ let guar = match p.parse_expr() {
+ Ok(expr) => return Ok(expr),
+ Err(err) => err.emit(),
+ };
+ while p.token != token::Eof {
+ p.bump();
+ }
+ Err(guar)
+}
+
+/// Interpreting `tts` as a comma-separated sequence of expressions,
+/// expect exactly one string literal, or emit an error and return `Err`.
+pub(crate) fn get_single_str_from_tts(
+ cx: &mut ExtCtxt<'_>,
+ span: Span,
+ tts: TokenStream,
+ name: &str,
+) -> ExpandResult, ()> {
+ get_single_str_spanned_from_tts(cx, span, tts, name).map(|res| res.map(|(s, _)| s))
+}
+
+pub(crate) fn get_single_str_spanned_from_tts(
+ cx: &mut ExtCtxt<'_>,
+ span: Span,
+ tts: TokenStream,
+ name: &str,
+) -> ExpandResult, ()> {
+ let mut p = cx.new_parser_from_tts(tts);
+ if p.token == token::Eof {
+ let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
+ return ExpandResult::Ready(Err(guar));
+ }
+ let ret = match parse_expr(&mut p) {
+ Ok(ret) => ret,
+ Err(guar) => return ExpandResult::Ready(Err(guar)),
+ };
+ let _ = p.eat(&token::Comma);
+
+ if p.token != token::Eof {
+ cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
+ }
+ expr_to_spanned_string(cx, ret, "argument must be a string literal").map(|res| {
+ res.map_err(|err| match err {
+ Ok((err, _)) => err.emit(),
+ Err(guar) => guar,
+ })
+ .map(|(symbol, _style, span)| (symbol, span))
+ })
+}
+
+/// Extracts comma-separated expressions from `tts`.
+/// On error, emit it, and return `Err`.
+pub(crate) fn get_exprs_from_tts(
+ cx: &mut ExtCtxt<'_>,
+ tts: TokenStream,
+) -> ExpandResult>, ErrorGuaranteed>, ()> {
+ let mut p = cx.new_parser_from_tts(tts);
+ let mut es = Vec::new();
+ while p.token != token::Eof {
+ let expr = match parse_expr(&mut p) {
+ Ok(expr) => expr,
+ Err(guar) => return ExpandResult::Ready(Err(guar)),
+ };
+ if !cx.force_mode
+ && let ast::ExprKind::MacCall(m) = &expr.kind
+ && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err()
+ {
+ return ExpandResult::Retry(());
+ }
+
+ // Perform eager expansion on the expression.
+ // We want to be able to handle e.g., `concat!("foo", "bar")`.
+ let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
+
+ es.push(expr);
+ if p.eat(&token::Comma) {
+ continue;
+ }
+ if p.token != token::Eof {
+ let guar = cx.dcx().emit_err(errors::ExpectedCommaInList { span: p.token.span });
+ return ExpandResult::Ready(Err(guar));
+ }
+ }
+ ExpandResult::Ready(Ok(es))
+}
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index fdd1a87cae8..b7aae2af9ef 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -30,9 +30,6 @@ expand_duplicate_matcher_binding = duplicate matcher binding
.label = duplicate binding
.label2 = previous binding
-expand_expected_comma_in_list =
- expected token: `,`
-
expand_expected_paren_or_brace =
expected `(` or `{"{"}`, found `{$token}`
@@ -116,9 +113,6 @@ expand_must_repeat_once =
expand_not_a_meta_item =
not a meta item
-expand_only_one_argument =
- {$name} takes 1 argument
-
expand_only_one_word =
must only be one word
@@ -146,9 +140,6 @@ expand_remove_node_not_supported =
expand_resolve_relative_path =
cannot resolve relative path in non-file source `{$path}`
-expand_takes_no_arguments =
- {$name} takes no arguments
-
expand_trace_macro = trace_macro
expand_unsupported_key_value =
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index d75c2530710..10067ba2974 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -5,27 +5,26 @@ use crate::module::DirOwnership;
use rustc_ast::attr::MarkedAttrs;
use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Nonterminal};
+use rustc_ast::token::Nonterminal;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
use rustc_attr::{self as attr, Deprecation, Stability};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::{self, Lrc};
-use rustc_errors::{Applicability, Diag, DiagCtxt, ErrorGuaranteed, PResult};
+use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult};
use rustc_feature::Features;
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, RegisteredTools};
use rustc_parse::{parser, MACRO_ARGUMENTS};
use rustc_session::config::CollapseMacroDebuginfo;
-use rustc_session::errors::report_lit_error;
use rustc_session::{parse::ParseSess, Limit, Session};
use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
use rustc_span::edition::Edition;
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
+use rustc_span::{FileName, Span, DUMMY_SP};
use smallvec::{smallvec, SmallVec};
use std::default::Default;
use std::iter;
@@ -1274,181 +1273,6 @@ pub fn resolve_path(sess: &Session, path: impl Into, span: Span) -> PRe
}
}
-/// `Ok` represents successfully retrieving the string literal at the correct
-/// position, e.g., `println("abc")`.
-type ExprToSpannedStringResult<'a> = Result<(Symbol, ast::StrStyle, Span), UnexpectedExprKind<'a>>;
-
-/// - `Ok` is returned when the conversion to a string literal is unsuccessful,
-/// but another type of expression is obtained instead.
-/// - `Err` is returned when the conversion process fails.
-type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), ErrorGuaranteed>;
-
-/// Extracts a string literal from the macro expanded version of `expr`,
-/// returning a diagnostic error of `err_msg` if `expr` is not a string literal.
-/// The returned bool indicates whether an applicable suggestion has already been
-/// added to the diagnostic to avoid emitting multiple suggestions. `Err(Err(ErrorGuaranteed))`
-/// 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,
- err_msg: &'static str,
-) -> ExpandResult, ()> {
- if !cx.force_mode
- && let ast::ExprKind::MacCall(m) = &expr.kind
- && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err()
- {
- return ExpandResult::Retry(());
- }
-
- // Perform eager expansion on the expression.
- // We want to be able to handle e.g., `concat!("foo", "bar")`.
- let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
-
- ExpandResult::Ready(Err(match expr.kind {
- ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
- Ok(ast::LitKind::Str(s, style)) => {
- return ExpandResult::Ready(Ok((s, style, expr.span)));
- }
- Ok(ast::LitKind::ByteStr(..)) => {
- let mut err = cx.dcx().struct_span_err(expr.span, err_msg);
- let span = expr.span.shrink_to_lo();
- err.span_suggestion(
- span.with_hi(span.lo() + BytePos(1)),
- "consider removing the leading `b`",
- "",
- Applicability::MaybeIncorrect,
- );
- Ok((err, true))
- }
- Ok(ast::LitKind::Err(guar)) => Err(guar),
- Err(err) => Err(report_lit_error(&cx.sess.psess, err, token_lit, expr.span)),
- _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)),
- },
- ast::ExprKind::Err(guar) => Err(guar),
- ast::ExprKind::Dummy => {
- cx.dcx().span_bug(expr.span, "tried to get a string literal from `ExprKind::Dummy`")
- }
- _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)),
- }))
-}
-
-/// Extracts a string literal from the macro expanded version of `expr`,
-/// emitting `err_msg` if `expr` is not a string literal. This does not stop
-/// compilation on error, merely emits a non-fatal error and returns `Err`.
-pub fn expr_to_string(
- cx: &mut ExtCtxt<'_>,
- expr: P,
- err_msg: &'static str,
-) -> ExpandResult, ()> {
- expr_to_spanned_string(cx, expr, err_msg).map(|res| {
- res.map_err(|err| match err {
- Ok((err, _)) => err.emit(),
- Err(guar) => guar,
- })
- .map(|(symbol, style, _)| (symbol, style))
- })
-}
-
-/// Non-fatally assert that `tts` is empty. Note that this function
-/// returns even when `tts` is non-empty, macros that *need* to stop
-/// compilation should call `cx.diagnostic().abort_if_errors()`
-/// (this should be done as rarely as possible).
-pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) {
- if !tts.is_empty() {
- cx.dcx().emit_err(errors::TakesNoArguments { span, name });
- }
-}
-
-/// Parse an expression. On error, emit it, advancing to `Eof`, and return `Err`.
-pub fn parse_expr(p: &mut parser::Parser<'_>) -> Result, ErrorGuaranteed> {
- let guar = match p.parse_expr() {
- Ok(expr) => return Ok(expr),
- Err(err) => err.emit(),
- };
- while p.token != token::Eof {
- p.bump();
- }
- Err(guar)
-}
-
-/// Interpreting `tts` as a comma-separated sequence of expressions,
-/// expect exactly one string literal, or emit an error and return `Err`.
-pub fn get_single_str_from_tts(
- cx: &mut ExtCtxt<'_>,
- span: Span,
- tts: TokenStream,
- name: &str,
-) -> ExpandResult, ()> {
- get_single_str_spanned_from_tts(cx, span, tts, name).map(|res| res.map(|(s, _)| s))
-}
-
-pub fn get_single_str_spanned_from_tts(
- cx: &mut ExtCtxt<'_>,
- span: Span,
- tts: TokenStream,
- name: &str,
-) -> ExpandResult, ()> {
- let mut p = cx.new_parser_from_tts(tts);
- if p.token == token::Eof {
- let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
- return ExpandResult::Ready(Err(guar));
- }
- let ret = match parse_expr(&mut p) {
- Ok(ret) => ret,
- Err(guar) => return ExpandResult::Ready(Err(guar)),
- };
- let _ = p.eat(&token::Comma);
-
- if p.token != token::Eof {
- cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
- }
- expr_to_spanned_string(cx, ret, "argument must be a string literal").map(|res| {
- res.map_err(|err| match err {
- Ok((err, _)) => err.emit(),
- Err(guar) => guar,
- })
- .map(|(symbol, _style, span)| (symbol, span))
- })
-}
-
-/// Extracts comma-separated expressions from `tts`.
-/// On error, emit it, and return `Err`.
-pub fn get_exprs_from_tts(
- cx: &mut ExtCtxt<'_>,
- tts: TokenStream,
-) -> ExpandResult>, ErrorGuaranteed>, ()> {
- let mut p = cx.new_parser_from_tts(tts);
- let mut es = Vec::new();
- while p.token != token::Eof {
- let expr = match parse_expr(&mut p) {
- Ok(expr) => expr,
- Err(guar) => return ExpandResult::Ready(Err(guar)),
- };
- if !cx.force_mode
- && let ast::ExprKind::MacCall(m) = &expr.kind
- && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err()
- {
- return ExpandResult::Retry(());
- }
-
- // Perform eager expansion on the expression.
- // We want to be able to handle e.g., `concat!("foo", "bar")`.
- let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
-
- es.push(expr);
- if p.eat(&token::Comma) {
- continue;
- }
- if p.token != token::Eof {
- let guar = cx.dcx().emit_err(errors::ExpectedCommaInList { span: p.token.span });
- return ExpandResult::Ready(Err(guar));
- }
- }
- ExpandResult::Ready(Ok(es))
-}
-
pub fn parse_macro_name_and_helper_attrs(
dcx: &rustc_errors::DiagCtxt,
attr: &Attribute,
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 21ce5e1d81e..db8e4ba07e8 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -152,29 +152,6 @@ pub(crate) struct HelperAttributeNameInvalid {
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_removed, code = E0557)]
pub(crate) struct FeatureRemoved<'a> {