about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbohan <bohan-zhang@foxmail.com>2024-03-12 10:55:17 +0800
committerbohan <bohan-zhang@foxmail.com>2024-03-13 16:11:16 +0800
commit8fcdf54a6b98c129e951caf3a97cbf20db677ee3 (patch)
treef34b8d1a37fdbe0e539f2c38e91b74a4358d98ef /compiler
parent5a6c1aa2bccfcbfa42f486a54c09bd698378faef (diff)
downloadrust-8fcdf54a6b98c129e951caf3a97cbf20db677ee3.tar.gz
rust-8fcdf54a6b98c129e951caf3a97cbf20db677ee3.zip
delay expand macro bang when there has indeterminate path
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs76
-rw-r--r--compiler/rustc_builtin_macros/src/assert.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/compile_error.rs14
-rw-r--r--compiler/rustc_builtin_macros/src/concat.rs25
-rw-r--r--compiler/rustc_builtin_macros/src/concat_bytes.rs25
-rw-r--r--compiler/rustc_builtin_macros/src/concat_idents.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/edition_panic.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/env.rs54
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs121
-rw-r--r--compiler/rustc_builtin_macros/src/log_syntax.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs80
-rw-r--r--compiler/rustc_builtin_macros/src/trace_macros.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/type_ascribe.rs8
-rw-r--r--compiler/rustc_expand/src/base.rs95
-rw-r--r--compiler/rustc_expand/src/expand.rs13
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs14
-rw-r--r--compiler/rustc_resolve/src/macros.rs85
18 files changed, 399 insertions, 263 deletions
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index bc851fadc2e..62c02817011 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -5,7 +5,7 @@ use rustc_ast::token::{self, Delimiter};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::PResult;
-use rustc_expand::base::{self, *};
+use rustc_expand::base::*;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_parse::parser::Parser;
 use rustc_parse_format as parse;
@@ -443,7 +443,7 @@ fn parse_reg<'a>(
 fn expand_preparsed_asm(
     ecx: &mut ExtCtxt<'_>,
     args: AsmArgs,
-) -> Result<ast::InlineAsm, ErrorGuaranteed> {
+) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
     let mut template = vec![];
     // Register operands are implicitly used since they are not allowed to be
     // referenced in the template string.
@@ -465,16 +465,20 @@ fn expand_preparsed_asm(
 
         let msg = "asm template must be a string literal";
         let template_sp = template_expr.span;
-        let (template_str, template_style, template_span) =
-            match expr_to_spanned_string(ecx, template_expr, msg) {
+        let (template_str, template_style, template_span) = {
+            let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else {
+                return ExpandResult::Retry(());
+            };
+            match mac {
                 Ok(template_part) => template_part,
                 Err(err) => {
-                    return Err(match err {
+                    return ExpandResult::Ready(Err(match err {
                         Ok((err, _)) => err.emit(),
                         Err(guar) => guar,
-                    });
+                    }));
                 }
-            };
+            }
+        };
 
         let str_style = match template_style {
             ast::StrStyle::Cooked => None,
@@ -562,7 +566,7 @@ fn expand_preparsed_asm(
                 e.span_label(err_sp, label);
             }
             let guar = e.emit();
-            return Err(guar);
+            return ExpandResult::Ready(Err(guar));
         }
 
         curarg = parser.curarg;
@@ -729,24 +733,27 @@ fn expand_preparsed_asm(
         }
     }
 
-    Ok(ast::InlineAsm {
+    ExpandResult::Ready(Ok(ast::InlineAsm {
         template,
         template_strs: template_strs.into_boxed_slice(),
         operands: args.operands,
         clobber_abis: args.clobber_abis,
         options: args.options,
         line_spans,
-    })
+    }))
 }
 
 pub(super) fn expand_asm<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
-    match parse_args(ecx, sp, tts, false) {
+) -> MacroExpanderResult<'cx> {
+    ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
         Ok(args) => {
-            let expr = match expand_preparsed_asm(ecx, args) {
+            let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
+                return ExpandResult::Retry(());
+            };
+            let expr = match mac {
                 Ok(inline_asm) => P(ast::Expr {
                     id: ast::DUMMY_NODE_ID,
                     kind: ast::ExprKind::InlineAsm(P(inline_asm)),
@@ -762,34 +769,39 @@ pub(super) fn expand_asm<'cx>(
             let guar = err.emit();
             DummyResult::any(sp, guar)
         }
-    }
+    })
 }
 
 pub(super) fn expand_global_asm<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
-    match parse_args(ecx, sp, tts, true) {
-        Ok(args) => match expand_preparsed_asm(ecx, args) {
-            Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item {
-                ident: Ident::empty(),
-                attrs: ast::AttrVec::new(),
-                id: ast::DUMMY_NODE_ID,
-                kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
-                vis: ast::Visibility {
-                    span: sp.shrink_to_lo(),
-                    kind: ast::VisibilityKind::Inherited,
+) -> MacroExpanderResult<'cx> {
+    ExpandResult::Ready(match parse_args(ecx, sp, tts, true) {
+        Ok(args) => {
+            let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
+                return ExpandResult::Retry(());
+            };
+            match mac {
+                Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item {
+                    ident: Ident::empty(),
+                    attrs: ast::AttrVec::new(),
+                    id: ast::DUMMY_NODE_ID,
+                    kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
+                    vis: ast::Visibility {
+                        span: sp.shrink_to_lo(),
+                        kind: ast::VisibilityKind::Inherited,
+                        tokens: None,
+                    },
+                    span: sp,
                     tokens: None,
-                },
-                span: sp,
-                tokens: None,
-            })]),
-            Err(guar) => DummyResult::any(sp, guar),
-        },
+                })]),
+                Err(guar) => DummyResult::any(sp, guar),
+            }
+        }
         Err(err) => {
             let guar = err.emit();
             DummyResult::any(sp, guar)
         }
-    }
+    })
 }
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index 613ce43dec2..35a0857fe51 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -9,7 +9,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream};
 use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp};
 use rustc_ast_pretty::pprust;
 use rustc_errors::PResult;
-use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
 use rustc_parse::parser::Parser;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -19,12 +19,12 @@ pub fn expand_assert<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     span: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) {
         Ok(assert) => assert,
         Err(err) => {
             let guar = err.emit();
-            return DummyResult::any(span, guar);
+            return ExpandResult::Ready(DummyResult::any(span, guar));
         }
     };
 
@@ -92,7 +92,7 @@ pub fn expand_assert<'cx>(
         expr_if_not(cx, call_site_span, cond_expr, then, None)
     };
 
-    MacEager::expr(expr)
+    ExpandResult::Ready(MacEager::expr(expr))
 }
 
 struct Assert {
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index 04bf7dceeff..9197b9ebdf9 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -8,17 +8,17 @@ use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_attr as attr;
 use rustc_errors::PResult;
-use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
 use rustc_span::Span;
 
 pub fn expand_cfg(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
 
-    match parse_cfg(cx, sp, tts) {
+    ExpandResult::Ready(match parse_cfg(cx, sp, tts) {
         Ok(cfg) => {
             let matches_cfg = attr::cfg_matches(
                 &cfg,
@@ -32,7 +32,7 @@ pub fn expand_cfg(
             let guar = err.emit();
             DummyResult::any(sp, guar)
         }
-    }
+    })
 }
 
 fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs
index b4455d7823f..2f2a87fc9aa 100644
--- a/compiler/rustc_builtin_macros/src/compile_error.rs
+++ b/compiler/rustc_builtin_macros/src/compile_error.rs
@@ -1,22 +1,26 @@
 // The compiler code necessary to support the compile_error! extension.
 
 use rustc_ast::tokenstream::TokenStream;
-use rustc_expand::base::{get_single_str_from_tts, DummyResult, ExtCtxt, MacResult};
+use rustc_expand::base::get_single_str_from_tts;
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
 use rustc_span::Span;
 
 pub fn expand_compile_error<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
-    let var = match get_single_str_from_tts(cx, sp, tts, "compile_error!") {
+) -> MacroExpanderResult<'cx> {
+    let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "compile_error!") else {
+        return ExpandResult::Retry(());
+    };
+    let var = match mac {
         Ok(var) => var,
-        Err(guar) => return DummyResult::any(sp, guar),
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
 
     #[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")]
     #[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
     let guar = cx.dcx().span_err(sp, var.to_string());
 
-    DummyResult::any(sp, guar)
+    ExpandResult::Ready(DummyResult::any(sp, guar))
 }
diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs
index 0bfb848859b..93a7ac05a9b 100644
--- a/compiler/rustc_builtin_macros/src/concat.rs
+++ b/compiler/rustc_builtin_macros/src/concat.rs
@@ -1,6 +1,7 @@
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{ExprKind, LitKind, UnOp};
-use rustc_expand::base::{get_exprs_from_tts, DummyResult, ExtCtxt, MacEager, MacResult};
+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;
 
@@ -10,10 +11,13 @@ pub fn expand_concat(
     cx: &mut ExtCtxt<'_>,
     sp: rustc_span::Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'static> {
-    let es = match get_exprs_from_tts(cx, tts) {
+) -> MacroExpanderResult<'static> {
+    let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
+        return ExpandResult::Retry(());
+    };
+    let es = match mac {
         Ok(es) => es,
-        Err(guar) => return DummyResult::any(sp, guar),
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
     let mut accumulator = String::new();
     let mut missing_literal = vec![];
@@ -70,12 +74,13 @@ pub fn expand_concat(
         }
     }
 
-    if !missing_literal.is_empty() {
+    ExpandResult::Ready(if !missing_literal.is_empty() {
         let guar = cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal });
-        return DummyResult::any(sp, guar);
+        DummyResult::any(sp, guar)
     } else if let Some(guar) = guar {
-        return DummyResult::any(sp, guar);
-    }
-    let sp = cx.with_def_site_ctxt(sp);
-    MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
+        DummyResult::any(sp, guar)
+    } else {
+        let sp = cx.with_def_site_ctxt(sp);
+        MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
+    })
 }
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index 502bfb4467e..a2f827c5567 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -1,5 +1,6 @@
 use rustc_ast::{ptr::P, token, tokenstream::TokenStream, ExprKind, LitIntType, LitKind, UintTy};
-use rustc_expand::base::{get_exprs_from_tts, DummyResult, ExtCtxt, MacEager, MacResult};
+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};
 
@@ -111,10 +112,13 @@ pub fn expand_concat_bytes(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'static> {
-    let es = match get_exprs_from_tts(cx, tts) {
+) -> MacroExpanderResult<'static> {
+    let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
+        return ExpandResult::Retry(());
+    };
+    let es = match mac {
         Ok(es) => es,
-        Err(guar) => return DummyResult::any(sp, guar),
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
     let mut accumulator = Vec::new();
     let mut missing_literals = vec![];
@@ -170,12 +174,13 @@ pub fn expand_concat_bytes(
             }
         }
     }
-    if !missing_literals.is_empty() {
+    ExpandResult::Ready(if !missing_literals.is_empty() {
         let guar = cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals });
-        return MacEager::expr(DummyResult::raw_expr(sp, Some(guar)));
+        MacEager::expr(DummyResult::raw_expr(sp, Some(guar)))
     } else if let Some(guar) = guar {
-        return MacEager::expr(DummyResult::raw_expr(sp, Some(guar)));
-    }
-    let sp = cx.with_def_site_ctxt(sp);
-    MacEager::expr(cx.expr_byte_str(sp, accumulator))
+        MacEager::expr(DummyResult::raw_expr(sp, Some(guar)))
+    } else {
+        let sp = cx.with_def_site_ctxt(sp);
+        MacEager::expr(cx.expr_byte_str(sp, accumulator))
+    })
 }
diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs
index fffcddc5325..3ddb0ae45b5 100644
--- a/compiler/rustc_builtin_macros/src/concat_idents.rs
+++ b/compiler/rustc_builtin_macros/src/concat_idents.rs
@@ -2,7 +2,7 @@ use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Token};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::{AttrVec, Expr, ExprKind, Path, Ty, TyKind, DUMMY_NODE_ID};
-use rustc_expand::base::{DummyResult, ExtCtxt, MacResult};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
 
@@ -12,10 +12,10 @@ pub fn expand_concat_idents<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     if tts.is_empty() {
         let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp });
-        return DummyResult::any(sp, guar);
+        return ExpandResult::Ready(DummyResult::any(sp, guar));
     }
 
     let mut res_str = String::new();
@@ -25,7 +25,7 @@ pub fn expand_concat_idents<'cx>(
                 TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
                 _ => {
                     let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp });
-                    return DummyResult::any(sp, guar);
+                    return ExpandResult::Ready(DummyResult::any(sp, guar));
                 }
             }
         } else {
@@ -37,7 +37,7 @@ pub fn expand_concat_idents<'cx>(
             }
 
             let guar = cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp });
-            return DummyResult::any(sp, guar);
+            return ExpandResult::Ready(DummyResult::any(sp, guar));
         }
     }
 
@@ -68,5 +68,5 @@ pub fn expand_concat_idents<'cx>(
         }
     }
 
-    Box::new(ConcatIdentsResult { ident })
+    ExpandResult::Ready(Box::new(ConcatIdentsResult { ident }))
 }
diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs
index 1e1dadab480..fa22e911642 100644
--- a/compiler/rustc_builtin_macros/src/edition_panic.rs
+++ b/compiler/rustc_builtin_macros/src/edition_panic.rs
@@ -20,7 +20,7 @@ pub fn expand_panic<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     let mac = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 };
     expand(mac, cx, sp, tts)
 }
@@ -33,7 +33,7 @@ pub fn expand_unreachable<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     let mac = if use_panic_2021(sp) { sym::unreachable_2021 } else { sym::unreachable_2015 };
     expand(mac, cx, sp, tts)
 }
@@ -43,10 +43,10 @@ fn expand<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     let sp = cx.with_call_site_ctxt(sp);
 
-    MacEager::expr(
+    ExpandResult::Ready(MacEager::expr(
         cx.expr(
             sp,
             ExprKind::MacCall(P(MacCall {
@@ -66,7 +66,7 @@ fn expand<'cx>(
                 }),
             })),
         ),
-    )
+    ))
 }
 
 pub fn use_panic_2021(mut span: Span) -> bool {
diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs
index 193b38a8323..bce710e5cab 100644
--- a/compiler/rustc_builtin_macros/src/env.rs
+++ b/compiler/rustc_builtin_macros/src/env.rs
@@ -6,10 +6,8 @@
 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, DummyResult, ExtCtxt, MacEager,
-    MacResult,
-};
+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;
 use std::env;
@@ -31,10 +29,13 @@ pub fn expand_option_env<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
-    let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") {
+) -> MacroExpanderResult<'cx> {
+    let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "option_env!") else {
+        return ExpandResult::Retry(());
+    };
+    let var = match mac {
         Ok(var) => var,
-        Err(guar) => return DummyResult::any(sp, guar),
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
 
     let sp = cx.with_def_site_ctxt(sp);
@@ -61,35 +62,48 @@ pub fn expand_option_env<'cx>(
             thin_vec![cx.expr_str(sp, value)],
         ),
     };
-    MacEager::expr(e)
+    ExpandResult::Ready(MacEager::expr(e))
 }
 
 pub fn expand_env<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
-    let mut exprs = match get_exprs_from_tts(cx, tts) {
+) -> MacroExpanderResult<'cx> {
+    let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
+        return ExpandResult::Retry(());
+    };
+    let mut exprs = match mac {
         Ok(exprs) if exprs.is_empty() || exprs.len() > 2 => {
             let guar = cx.dcx().emit_err(errors::EnvTakesArgs { span: sp });
-            return DummyResult::any(sp, guar);
+            return ExpandResult::Ready(DummyResult::any(sp, guar));
         }
-        Err(guar) => return DummyResult::any(sp, guar),
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
         Ok(exprs) => exprs.into_iter(),
     };
 
     let var_expr = exprs.next().unwrap();
-    let var = match expr_to_string(cx, var_expr.clone(), "expected string literal") {
+    let ExpandResult::Ready(mac) = expr_to_string(cx, var_expr.clone(), "expected string literal")
+    else {
+        return ExpandResult::Retry(());
+    };
+    let var = match mac {
         Ok((var, _)) => var,
-        Err(guar) => return DummyResult::any(sp, guar),
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
 
     let custom_msg = match exprs.next() {
         None => None,
-        Some(second) => match expr_to_string(cx, second, "expected string literal") {
-            Ok((s, _)) => Some(s),
-            Err(guar) => return DummyResult::any(sp, guar),
-        },
+        Some(second) => {
+            let ExpandResult::Ready(mac) = expr_to_string(cx, second, "expected string literal")
+            else {
+                return ExpandResult::Retry(());
+            };
+            match mac {
+                Ok((s, _)) => Some(s),
+                Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
+            }
+        }
     };
 
     let span = cx.with_def_site_ctxt(sp);
@@ -120,11 +134,11 @@ pub fn expand_env<'cx>(
                 })
             };
 
-            return DummyResult::any(sp, guar);
+            return ExpandResult::Ready(DummyResult::any(sp, guar));
         }
         Some(value) => cx.expr_str(span, value),
     };
-    MacEager::expr(e)
+    ExpandResult::Ready(MacEager::expr(e))
 }
 
 /// Returns `true` if an environment variable from `env!` is one used by Cargo.
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 385c90ff14b..6f031f270ca 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -9,7 +9,7 @@ use rustc_ast::{
 };
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans};
-use rustc_expand::base::{self, *};
+use rustc_expand::base::*;
 use rustc_parse::parser::Recovered;
 use rustc_parse_format as parse;
 use rustc_span::symbol::{Ident, Symbol};
@@ -40,6 +40,7 @@ use PositionUsedAs::*;
 
 use crate::errors;
 
+#[derive(Debug)]
 struct MacroInput {
     fmtstr: P<Expr>,
     args: FormatArguments,
@@ -160,54 +161,61 @@ fn make_format_args(
     ecx: &mut ExtCtxt<'_>,
     input: MacroInput,
     append_newline: bool,
-) -> Result<FormatArgs, ErrorGuaranteed> {
+) -> ExpandResult<Result<FormatArgs, ErrorGuaranteed>, ()> {
     let msg = "format argument must be a string literal";
     let unexpanded_fmt_span = input.fmtstr.span;
 
     let MacroInput { fmtstr: efmt, mut args, is_direct_literal } = input;
 
-    let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt.clone(), msg) {
-        Ok(mut fmt) if append_newline => {
-            fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
-            fmt
-        }
-        Ok(fmt) => fmt,
-        Err(err) => {
-            let guar = match err {
-                Ok((mut err, suggested)) => {
-                    if !suggested {
-                        if let ExprKind::Block(block, None) = &efmt.kind
-                            && block.stmts.len() == 1
-                            && let StmtKind::Expr(expr) = &block.stmts[0].kind
-                            && let ExprKind::Path(None, path) = &expr.kind
-                            && path.is_potential_trivial_const_arg()
-                        {
-                            err.multipart_suggestion(
-                                "quote your inlined format argument to use as string literal",
-                                vec![
-                                    (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()),
-                                    (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()),
-                                ],
-                                Applicability::MaybeIncorrect,
-                            );
-                        } else {
-                            let sugg_fmt = match args.explicit_args().len() {
-                                0 => "{}".to_string(),
-                                _ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())),
-                            };
-                            err.span_suggestion(
-                                unexpanded_fmt_span.shrink_to_lo(),
-                                "you might be missing a string literal to format with",
-                                format!("\"{sugg_fmt}\", "),
-                                Applicability::MaybeIncorrect,
-                            );
+    let (fmt_str, fmt_style, fmt_span) = {
+        let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, efmt.clone(), msg) else {
+            return ExpandResult::Retry(());
+        };
+        match mac {
+            Ok(mut fmt) if append_newline => {
+                fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
+                fmt
+            }
+            Ok(fmt) => fmt,
+            Err(err) => {
+                let guar = match err {
+                    Ok((mut err, suggested)) => {
+                        if !suggested {
+                            if let ExprKind::Block(block, None) = &efmt.kind
+                                && block.stmts.len() == 1
+                                && let StmtKind::Expr(expr) = &block.stmts[0].kind
+                                && let ExprKind::Path(None, path) = &expr.kind
+                                && path.is_potential_trivial_const_arg()
+                            {
+                                err.multipart_suggestion(
+                                    "quote your inlined format argument to use as string literal",
+                                    vec![
+                                        (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()),
+                                        (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()),
+                                    ],
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else {
+                                let sugg_fmt = match args.explicit_args().len() {
+                                    0 => "{}".to_string(),
+                                    _ => {
+                                        format!("{}{{}}", "{} ".repeat(args.explicit_args().len()))
+                                    }
+                                };
+                                err.span_suggestion(
+                                    unexpanded_fmt_span.shrink_to_lo(),
+                                    "you might be missing a string literal to format with",
+                                    format!("\"{sugg_fmt}\", "),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
                         }
+                        err.emit()
                     }
-                    err.emit()
-                }
-                Err(guar) => guar,
-            };
-            return Err(guar);
+                    Err(guar) => guar,
+                };
+                return ExpandResult::Ready(Err(guar));
+            }
         }
     };
 
@@ -297,7 +305,7 @@ fn make_format_args(
             }
         }
         let guar = ecx.dcx().emit_err(e);
-        return Err(guar);
+        return ExpandResult::Ready(Err(guar));
     }
 
     let to_span = |inner_span: rustc_parse_format::InnerSpan| {
@@ -564,7 +572,7 @@ fn make_format_args(
         }
     }
 
-    Ok(FormatArgs { span: fmt_span, template, arguments: args })
+    ExpandResult::Ready(Ok(FormatArgs { span: fmt_span, template, arguments: args }))
 }
 
 fn invalid_placeholder_type_error(
@@ -972,25 +980,32 @@ fn expand_format_args_impl<'cx>(
     mut sp: Span,
     tts: TokenStream,
     nl: bool,
-) -> Box<dyn base::MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     sp = ecx.with_def_site_ctxt(sp);
-    match parse_args(ecx, sp, tts) {
-        Ok(input) => match make_format_args(ecx, input, nl) {
-            Ok(format_args) => MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))),
-            Err(guar) => MacEager::expr(DummyResult::raw_expr(sp, Some(guar))),
-        },
+    ExpandResult::Ready(match parse_args(ecx, sp, tts) {
+        Ok(input) => {
+            let ExpandResult::Ready(mac) = make_format_args(ecx, input, nl) else {
+                return ExpandResult::Retry(());
+            };
+            match mac {
+                Ok(format_args) => {
+                    MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args))))
+                }
+                Err(guar) => MacEager::expr(DummyResult::raw_expr(sp, Some(guar))),
+            }
+        }
         Err(err) => {
             let guar = err.emit();
             DummyResult::any(sp, guar)
         }
-    }
+    })
 }
 
 pub fn expand_format_args<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     expand_format_args_impl(ecx, sp, tts, false)
 }
 
@@ -998,6 +1013,6 @@ pub fn expand_format_args_nl<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     expand_format_args_impl(ecx, sp, tts, true)
 }
diff --git a/compiler/rustc_builtin_macros/src/log_syntax.rs b/compiler/rustc_builtin_macros/src/log_syntax.rs
index ede34a76125..288a475ac24 100644
--- a/compiler/rustc_builtin_macros/src/log_syntax.rs
+++ b/compiler/rustc_builtin_macros/src/log_syntax.rs
@@ -1,14 +1,14 @@
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast_pretty::pprust;
-use rustc_expand::base;
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
 
 pub fn expand_log_syntax<'cx>(
-    _cx: &'cx mut base::ExtCtxt<'_>,
+    _cx: &'cx mut ExtCtxt<'_>,
     sp: rustc_span::Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     println!("{}", pprust::tts_to_string(&tts));
 
     // any so that `log_syntax` can be invoked as an expression and item.
-    base::DummyResult::any_valid(sp)
+    ExpandResult::Ready(DummyResult::any_valid(sp))
 }
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 2da9bda19e0..dbb86df6811 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -3,10 +3,9 @@ use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast_pretty::pprust;
-use rustc_expand::base::{
-    check_zero_tts, get_single_str_from_tts, parse_expr, resolve_path, DummyResult, ExtCtxt,
-    MacEager, MacResult,
-};
+use rustc_expand::base::{check_zero_tts, get_single_str_from_tts, parse_expr, resolve_path};
+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};
@@ -26,14 +25,14 @@ pub fn expand_line(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
     check_zero_tts(cx, sp, tts, "line!");
 
     let topmost = cx.expansion_cause().unwrap_or(sp);
     let loc = cx.source_map().lookup_char_pos(topmost.lo());
 
-    MacEager::expr(cx.expr_u32(topmost, loc.line as u32))
+    ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.line as u32)))
 }
 
 /* column!(): expands to the current column number */
@@ -41,14 +40,14 @@ pub fn expand_column(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
     check_zero_tts(cx, sp, tts, "column!");
 
     let topmost = cx.expansion_cause().unwrap_or(sp);
     let loc = cx.source_map().lookup_char_pos(topmost.lo());
 
-    MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1))
+    ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1)))
 }
 
 /// file!(): expands to the current filename */
@@ -58,7 +57,7 @@ pub fn expand_file(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
     check_zero_tts(cx, sp, tts, "file!");
 
@@ -66,35 +65,35 @@ pub fn expand_file(
     let loc = cx.source_map().lookup_char_pos(topmost.lo());
 
     use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
-    MacEager::expr(cx.expr_str(
+    ExpandResult::Ready(MacEager::expr(cx.expr_str(
         topmost,
         Symbol::intern(
             &loc.file.name.for_scope(cx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
         ),
-    ))
+    )))
 }
 
 pub fn expand_stringify(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
     let s = pprust::tts_to_string(&tts);
-    MacEager::expr(cx.expr_str(sp, Symbol::intern(&s)))
+    ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))))
 }
 
 pub fn expand_mod(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
     check_zero_tts(cx, sp, tts, "module_path!");
     let mod_path = &cx.current_expansion.module.mod_path;
     let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
 
-    MacEager::expr(cx.expr_str(sp, Symbol::intern(&string)))
+    ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))))
 }
 
 /// include! : parse the given file as an expr
@@ -104,18 +103,21 @@ pub fn expand_include<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     let sp = cx.with_def_site_ctxt(sp);
-    let file = match get_single_str_from_tts(cx, sp, tts, "include!") {
+    let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include!") else {
+        return ExpandResult::Retry(());
+    };
+    let file = match mac {
         Ok(file) => file,
-        Err(guar) => return DummyResult::any(sp, guar),
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
     // The file will be added to the code map by the parser
     let file = match resolve_path(&cx.sess, file.as_str(), sp) {
         Ok(f) => f,
         Err(err) => {
             let guar = err.emit();
-            return DummyResult::any(sp, guar);
+            return ExpandResult::Ready(DummyResult::any(sp, guar));
         }
     };
     let p = new_parser_from_file(cx.psess(), &file, Some(sp));
@@ -128,12 +130,12 @@ pub fn expand_include<'cx>(
     cx.current_expansion.module = Rc::new(cx.current_expansion.module.with_dir_path(dir_path));
     cx.current_expansion.dir_ownership = DirOwnership::Owned { relative: None };
 
-    struct ExpandResult<'a> {
+    struct ExpandInclude<'a> {
         p: Parser<'a>,
         node_id: ast::NodeId,
     }
-    impl<'a> MacResult for ExpandResult<'a> {
-        fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
+    impl<'a> MacResult for ExpandInclude<'a> {
+        fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<P<ast::Expr>> {
             let expr = parse_expr(&mut self.p).ok()?;
             if self.p.token != token::Eof {
                 self.p.psess.buffer_lint(
@@ -146,7 +148,7 @@ pub fn expand_include<'cx>(
             Some(expr)
         }
 
-        fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
+        fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
             let mut ret = SmallVec::new();
             loop {
                 match self.p.parse_item(ForceCollect::No) {
@@ -170,7 +172,7 @@ pub fn expand_include<'cx>(
         }
     }
 
-    Box::new(ExpandResult { p, node_id: cx.current_expansion.lint_node_id })
+    ExpandResult::Ready(Box::new(ExpandInclude { p, node_id: cx.current_expansion.lint_node_id }))
 }
 
 /// `include_str!`: read the given file, insert it as a literal string expr
@@ -178,20 +180,23 @@ pub fn expand_include_str(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
-    let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") {
+    let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include_str!") else {
+        return ExpandResult::Retry(());
+    };
+    let file = match mac {
         Ok(file) => file,
-        Err(guar) => return DummyResult::any(sp, guar),
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
     let file = match resolve_path(&cx.sess, file.as_str(), sp) {
         Ok(f) => f,
         Err(err) => {
             let guar = err.emit();
-            return DummyResult::any(sp, guar);
+            return ExpandResult::Ready(DummyResult::any(sp, guar));
         }
     };
-    match cx.source_map().load_binary_file(&file) {
+    ExpandResult::Ready(match cx.source_map().load_binary_file(&file) {
         Ok(bytes) => match std::str::from_utf8(&bytes) {
             Ok(src) => {
                 let interned_src = Symbol::intern(src);
@@ -206,27 +211,30 @@ pub fn expand_include_str(
             let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
             DummyResult::any(sp, guar)
         }
-    }
+    })
 }
 
 pub fn expand_include_bytes(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
-    let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") {
+    let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else {
+        return ExpandResult::Retry(());
+    };
+    let file = match mac {
         Ok(file) => file,
-        Err(guar) => return DummyResult::any(sp, guar),
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
     let file = match resolve_path(&cx.sess, file.as_str(), sp) {
         Ok(f) => f,
         Err(err) => {
             let guar = err.emit();
-            return DummyResult::any(sp, guar);
+            return ExpandResult::Ready(DummyResult::any(sp, guar));
         }
     };
-    match cx.source_map().load_binary_file(&file) {
+    ExpandResult::Ready(match cx.source_map().load_binary_file(&file) {
         Ok(bytes) => {
             let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes));
             MacEager::expr(expr)
@@ -235,5 +243,5 @@ pub fn expand_include_bytes(
             let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
             DummyResult::any(sp, guar)
         }
-    }
+    })
 }
diff --git a/compiler/rustc_builtin_macros/src/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs
index e076aa6da73..696d99004ba 100644
--- a/compiler/rustc_builtin_macros/src/trace_macros.rs
+++ b/compiler/rustc_builtin_macros/src/trace_macros.rs
@@ -1,6 +1,6 @@
 use crate::errors;
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
-use rustc_expand::base::{self, ExtCtxt};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
 use rustc_span::symbol::kw;
 use rustc_span::Span;
 
@@ -8,7 +8,7 @@ pub fn expand_trace_macros(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tt: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let mut cursor = tt.trees();
     let mut err = false;
     let value = match &cursor.next() {
@@ -26,5 +26,5 @@ pub fn expand_trace_macros(
         cx.set_trace_macros(value);
     }
 
-    base::DummyResult::any_valid(sp)
+    ExpandResult::Ready(DummyResult::any_valid(sp))
 }
diff --git a/compiler/rustc_builtin_macros/src/type_ascribe.rs b/compiler/rustc_builtin_macros/src/type_ascribe.rs
index e8b8fe75338..f3e66ffc759 100644
--- a/compiler/rustc_builtin_macros/src/type_ascribe.rs
+++ b/compiler/rustc_builtin_macros/src/type_ascribe.rs
@@ -2,25 +2,25 @@ use rustc_ast::ptr::P;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{token, Expr, ExprKind, Ty};
 use rustc_errors::PResult;
-use rustc_expand::base::{self, DummyResult, ExtCtxt, MacEager};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
 use rustc_span::Span;
 
 pub fn expand_type_ascribe(
     cx: &mut ExtCtxt<'_>,
     span: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let (expr, ty) = match parse_ascribe(cx, tts) {
         Ok(parsed) => parsed,
         Err(err) => {
             let guar = err.emit();
-            return DummyResult::any(span, guar);
+            return ExpandResult::Ready(DummyResult::any(span, guar));
         }
     };
 
     let asc_expr = cx.expr(span, ExprKind::Type(expr, ty));
 
-    return MacEager::expr(asc_expr);
+    ExpandResult::Ready(MacEager::expr(asc_expr))
 }
 
 fn parse_ascribe<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Expr>, P<Ty>)> {
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 69dfb48919c..30ee02ea3c0 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -245,6 +245,15 @@ pub enum ExpandResult<T, U> {
     Retry(U),
 }
 
+impl<T, U> ExpandResult<T, U> {
+    pub fn map<E, F: FnOnce(T) -> E>(self, f: F) -> ExpandResult<E, U> {
+        match self {
+            ExpandResult::Ready(t) => ExpandResult::Ready(f(t)),
+            ExpandResult::Retry(u) => ExpandResult::Retry(u),
+        }
+    }
+}
+
 pub trait MultiItemModifier {
     /// `meta_item` is the attribute, and `item` is the item being modified.
     fn expand(
@@ -330,22 +339,24 @@ pub trait TTMacroExpander {
         ecx: &'cx mut ExtCtxt<'_>,
         span: Span,
         input: TokenStream,
-    ) -> Box<dyn MacResult + 'cx>;
+    ) -> MacroExpanderResult<'cx>;
 }
 
+pub type MacroExpanderResult<'cx> = ExpandResult<Box<dyn MacResult + 'cx>, ()>;
+
 pub type MacroExpanderFn =
-    for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> Box<dyn MacResult + 'cx>;
+    for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> MacroExpanderResult<'cx>;
 
 impl<F> TTMacroExpander for F
 where
-    F: for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> Box<dyn MacResult + 'cx>,
+    F: for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> MacroExpanderResult<'cx>,
 {
     fn expand<'cx>(
         &self,
         ecx: &'cx mut ExtCtxt<'_>,
         span: Span,
         input: TokenStream,
-    ) -> Box<dyn MacResult + 'cx> {
+    ) -> MacroExpanderResult<'cx> {
         self(ecx, span, input)
     }
 }
@@ -904,8 +915,11 @@ impl SyntaxExtension {
             cx: &'cx mut ExtCtxt<'_>,
             span: Span,
             _: TokenStream,
-        ) -> Box<dyn MacResult + 'cx> {
-            DummyResult::any(span, cx.dcx().span_delayed_bug(span, "expanded a dummy bang macro"))
+        ) -> MacroExpanderResult<'cx> {
+            ExpandResult::Ready(DummyResult::any(
+                span,
+                cx.dcx().span_delayed_bug(span, "expanded a dummy bang macro"),
+            ))
         }
         SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Box::new(expander)), edition)
     }
@@ -1008,6 +1022,11 @@ pub trait ResolverExpand {
         expn_id: LocalExpnId,
         path: &ast::Path,
     ) -> Result<bool, Indeterminate>;
+    fn macro_accessible(
+        &mut self,
+        expn_id: LocalExpnId,
+        path: &ast::Path,
+    ) -> Result<bool, Indeterminate>;
 
     /// Decodes the proc-macro quoted span in the specified crate, with the specified id.
     /// No caching is performed.
@@ -1253,6 +1272,15 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, 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
@@ -1264,17 +1292,23 @@ pub fn expr_to_spanned_string<'a>(
     cx: &'a mut ExtCtxt<'_>,
     expr: P<ast::Expr>,
     err_msg: &'static str,
-) -> Result<
-    (Symbol, ast::StrStyle, Span),
-    Result<(Diag<'a>, bool /* has_suggestions */), ErrorGuaranteed>,
-> {
+) -> ExpandResult<ExprToSpannedStringResult<'a>, ()> {
+    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();
 
-    Err(match expr.kind {
+    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 Ok((s, style, expr.span)),
+            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();
@@ -1295,7 +1329,7 @@ pub fn expr_to_spanned_string<'a>(
             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`,
@@ -1305,13 +1339,14 @@ pub fn expr_to_string(
     cx: &mut ExtCtxt<'_>,
     expr: P<ast::Expr>,
     err_msg: &'static str,
-) -> Result<(Symbol, ast::StrStyle), ErrorGuaranteed> {
-    expr_to_spanned_string(cx, expr, err_msg)
-        .map_err(|err| match err {
+) -> ExpandResult<Result<(Symbol, ast::StrStyle), ErrorGuaranteed>, ()> {
+    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
@@ -1343,19 +1378,22 @@ pub fn get_single_str_from_tts(
     span: Span,
     tts: TokenStream,
     name: &str,
-) -> Result<Symbol, ErrorGuaranteed> {
+) -> ExpandResult<Result<Symbol, ErrorGuaranteed>, ()> {
     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 Err(guar);
+        return ExpandResult::Ready(Err(guar));
     }
-    let ret = parse_expr(&mut p)?;
+    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_string(cx, ret, "argument must be a string literal").map(|(s, _)| s)
+    expr_to_string(cx, ret, "argument must be a string literal").map(|s| s.map(|(s, _)| s))
 }
 
 /// Extracts comma-separated expressions from `tts`.
@@ -1363,11 +1401,20 @@ pub fn get_single_str_from_tts(
 pub fn get_exprs_from_tts(
     cx: &mut ExtCtxt<'_>,
     tts: TokenStream,
-) -> Result<Vec<P<ast::Expr>>, ErrorGuaranteed> {
+) -> ExpandResult<Result<Vec<P<ast::Expr>>, ErrorGuaranteed>, ()> {
     let mut p = cx.new_parser_from_tts(tts);
     let mut es = Vec::new();
     while p.token != token::Eof {
-        let expr = parse_expr(&mut p)?;
+        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")`.
@@ -1379,10 +1426,10 @@ pub fn get_exprs_from_tts(
         }
         if p.token != token::Eof {
             let guar = cx.dcx().emit_err(errors::ExpectedCommaInList { span: p.token.span });
-            return Err(guar);
+            return ExpandResult::Ready(Err(guar));
         }
     }
-    Ok(es)
+    ExpandResult::Ready(Ok(es))
 }
 
 pub fn parse_macro_name_and_helper_attrs(
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index fcc439e71f9..3544a8f0a8d 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -659,7 +659,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
         let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
         ExpandResult::Ready(match invoc.kind {
-            InvocationKind::Bang { mac, .. } => match ext {
+            InvocationKind::Bang { mac, span } => match ext {
                 SyntaxExtensionKind::Bang(expander) => {
                     match expander.expand(self.cx, span, mac.args.tokens.clone()) {
                         Ok(tok_result) => {
@@ -669,7 +669,16 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     }
                 }
                 SyntaxExtensionKind::LegacyBang(expander) => {
-                    let tok_result = expander.expand(self.cx, span, mac.args.tokens.clone());
+                    let tok_result = match expander.expand(self.cx, span, mac.args.tokens.clone()) {
+                        ExpandResult::Ready(tok_result) => tok_result,
+                        ExpandResult::Retry(_) => {
+                            // retry the original
+                            return ExpandResult::Retry(Invocation {
+                                kind: InvocationKind::Bang { mac, span },
+                                ..invoc
+                            });
+                        }
+                    };
                     let result = if let Some(result) = fragment_kind.make_from(tok_result) {
                         result
                     } else {
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 8903fc45def..3f29d7f7465 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -1,5 +1,5 @@
-use crate::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
-use crate::base::{SyntaxExtension, SyntaxExtensionKind};
+use crate::base::{DummyResult, SyntaxExtension, SyntaxExtensionKind};
+use crate::base::{ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, TTMacroExpander};
 use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind};
 use crate::mbe;
 use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
@@ -111,8 +111,8 @@ impl TTMacroExpander for MacroRulesMacroExpander {
         cx: &'cx mut ExtCtxt<'_>,
         sp: Span,
         input: TokenStream,
-    ) -> Box<dyn MacResult + 'cx> {
-        expand_macro(
+    ) -> MacroExpanderResult<'cx> {
+        ExpandResult::Ready(expand_macro(
             cx,
             sp,
             self.span,
@@ -122,7 +122,7 @@ impl TTMacroExpander for MacroRulesMacroExpander {
             input,
             &self.lhses,
             &self.rhses,
-        )
+        ))
     }
 }
 
@@ -134,8 +134,8 @@ impl TTMacroExpander for DummyExpander {
         _: &'cx mut ExtCtxt<'_>,
         span: Span,
         _: TokenStream,
-    ) -> Box<dyn MacResult + 'cx> {
-        DummyResult::any(span, self.0)
+    ) -> ExpandResult<Box<dyn MacResult + 'cx>, ()> {
+        ExpandResult::Ready(DummyResult::any(span, self.0))
     }
 }
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index d8fd8d22439..dbca2f9895d 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -19,7 +19,7 @@ use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, Resolver
 use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::compile_declarative_macro;
 use rustc_expand::expand::{AstFragment, Invocation, InvocationKind, SupportsMacroExpansion};
-use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
+use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_middle::middle::stability;
 use rustc_middle::ty::RegisteredTools;
@@ -431,40 +431,15 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
         expn_id: LocalExpnId,
         path: &ast::Path,
     ) -> Result<bool, Indeterminate> {
-        let span = path.span;
-        let path = &Segment::from_path(path);
-        let parent_scope = self.invocation_parent_scopes[&expn_id];
-
-        let mut indeterminate = false;
-        for ns in [TypeNS, ValueNS, MacroNS].iter().copied() {
-            match self.maybe_resolve_path(path, Some(ns), &parent_scope) {
-                PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true),
-                PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => {
-                    return Ok(true);
-                }
-                PathResult::NonModule(..) |
-                // HACK(Urgau): This shouldn't be necessary
-                PathResult::Failed { is_error_from_last_segment: false, .. } => {
-                    self.dcx()
-                        .emit_err(errors::CfgAccessibleUnsure { span });
-
-                    // If we get a partially resolved NonModule in one namespace, we should get the
-                    // same result in any other namespaces, so we can return early.
-                    return Ok(false);
-                }
-                PathResult::Indeterminate => indeterminate = true,
-                // We can only be sure that a path doesn't exist after having tested all the
-                // possibilities, only at that time we can return false.
-                PathResult::Failed { .. } => {}
-                PathResult::Module(_) => panic!("unexpected path resolution"),
-            }
-        }
-
-        if indeterminate {
-            return Err(Indeterminate);
-        }
+        self.path_accessible(expn_id, path, &[TypeNS, ValueNS, MacroNS])
+    }
 
-        Ok(false)
+    fn macro_accessible(
+        &mut self,
+        expn_id: LocalExpnId,
+        path: &ast::Path,
+    ) -> Result<bool, Indeterminate> {
+        self.path_accessible(expn_id, path, &[MacroNS])
     }
 
     fn get_proc_macro_quoted_span(&self, krate: CrateNum, id: usize) -> Span {
@@ -960,4 +935,46 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let ItemKind::MacroDef(def) = &item.kind else { unreachable!() };
         MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: def.macro_rules }
     }
+
+    fn path_accessible(
+        &mut self,
+        expn_id: LocalExpnId,
+        path: &ast::Path,
+        namespaces: &[Namespace],
+    ) -> Result<bool, Indeterminate> {
+        let span = path.span;
+        let path = &Segment::from_path(path);
+        let parent_scope = self.invocation_parent_scopes[&expn_id];
+
+        let mut indeterminate = false;
+        for ns in namespaces {
+            match self.maybe_resolve_path(path, Some(*ns), &parent_scope) {
+                PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true),
+                PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => {
+                    return Ok(true);
+                }
+                PathResult::NonModule(..) |
+                // HACK(Urgau): This shouldn't be necessary
+                PathResult::Failed { is_error_from_last_segment: false, .. } => {
+                    self.dcx()
+                        .emit_err(errors::CfgAccessibleUnsure { span });
+
+                    // If we get a partially resolved NonModule in one namespace, we should get the
+                    // same result in any other namespaces, so we can return early.
+                    return Ok(false);
+                }
+                PathResult::Indeterminate => indeterminate = true,
+                // We can only be sure that a path doesn't exist after having tested all the
+                // possibilities, only at that time we can return false.
+                PathResult::Failed { .. } => {}
+                PathResult::Module(_) => panic!("unexpected path resolution"),
+            }
+        }
+
+        if indeterminate {
+            return Err(Indeterminate);
+        }
+
+        Ok(false)
+    }
 }