1
Fork 0

delay expand macro bang when there has indeterminate path

This commit is contained in:
bohan 2024-03-12 10:55:17 +08:00
parent 5a6c1aa2bc
commit 8fcdf54a6b
22 changed files with 509 additions and 263 deletions

View file

@ -5,7 +5,7 @@ use rustc_ast::token::{self, Delimiter};
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::PResult; use rustc_errors::PResult;
use rustc_expand::base::{self, *}; use rustc_expand::base::*;
use rustc_index::bit_set::GrowableBitSet; use rustc_index::bit_set::GrowableBitSet;
use rustc_parse::parser::Parser; use rustc_parse::parser::Parser;
use rustc_parse_format as parse; use rustc_parse_format as parse;
@ -443,7 +443,7 @@ fn parse_reg<'a>(
fn expand_preparsed_asm( fn expand_preparsed_asm(
ecx: &mut ExtCtxt<'_>, ecx: &mut ExtCtxt<'_>,
args: AsmArgs, args: AsmArgs,
) -> Result<ast::InlineAsm, ErrorGuaranteed> { ) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
let mut template = vec![]; let mut template = vec![];
// Register operands are implicitly used since they are not allowed to be // Register operands are implicitly used since they are not allowed to be
// referenced in the template string. // referenced in the template string.
@ -465,16 +465,20 @@ fn expand_preparsed_asm(
let msg = "asm template must be a string literal"; let msg = "asm template must be a string literal";
let template_sp = template_expr.span; let template_sp = template_expr.span;
let (template_str, template_style, template_span) = let (template_str, template_style, template_span) = {
match expr_to_spanned_string(ecx, template_expr, msg) { let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else {
return ExpandResult::Retry(());
};
match mac {
Ok(template_part) => template_part, Ok(template_part) => template_part,
Err(err) => { Err(err) => {
return Err(match err { return ExpandResult::Ready(Err(match err {
Ok((err, _)) => err.emit(), Ok((err, _)) => err.emit(),
Err(guar) => guar, Err(guar) => guar,
}); }));
} }
}; }
};
let str_style = match template_style { let str_style = match template_style {
ast::StrStyle::Cooked => None, ast::StrStyle::Cooked => None,
@ -562,7 +566,7 @@ fn expand_preparsed_asm(
e.span_label(err_sp, label); e.span_label(err_sp, label);
} }
let guar = e.emit(); let guar = e.emit();
return Err(guar); return ExpandResult::Ready(Err(guar));
} }
curarg = parser.curarg; curarg = parser.curarg;
@ -729,24 +733,27 @@ fn expand_preparsed_asm(
} }
} }
Ok(ast::InlineAsm { ExpandResult::Ready(Ok(ast::InlineAsm {
template, template,
template_strs: template_strs.into_boxed_slice(), template_strs: template_strs.into_boxed_slice(),
operands: args.operands, operands: args.operands,
clobber_abis: args.clobber_abis, clobber_abis: args.clobber_abis,
options: args.options, options: args.options,
line_spans, line_spans,
}) }))
} }
pub(super) fn expand_asm<'cx>( pub(super) fn expand_asm<'cx>(
ecx: &'cx mut ExtCtxt<'_>, ecx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
match parse_args(ecx, sp, tts, false) { ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
Ok(args) => { 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 { Ok(inline_asm) => P(ast::Expr {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
kind: ast::ExprKind::InlineAsm(P(inline_asm)), kind: ast::ExprKind::InlineAsm(P(inline_asm)),
@ -762,34 +769,39 @@ pub(super) fn expand_asm<'cx>(
let guar = err.emit(); let guar = err.emit();
DummyResult::any(sp, guar) DummyResult::any(sp, guar)
} }
} })
} }
pub(super) fn expand_global_asm<'cx>( pub(super) fn expand_global_asm<'cx>(
ecx: &'cx mut ExtCtxt<'_>, ecx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
match parse_args(ecx, sp, tts, true) { ExpandResult::Ready(match parse_args(ecx, sp, tts, true) {
Ok(args) => match expand_preparsed_asm(ecx, args) { Ok(args) => {
Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item { let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
ident: Ident::empty(), return ExpandResult::Retry(());
attrs: ast::AttrVec::new(), };
id: ast::DUMMY_NODE_ID, match mac {
kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item {
vis: ast::Visibility { ident: Ident::empty(),
span: sp.shrink_to_lo(), attrs: ast::AttrVec::new(),
kind: ast::VisibilityKind::Inherited, 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, tokens: None,
}, })]),
span: sp, Err(guar) => DummyResult::any(sp, guar),
tokens: None, }
})]), }
Err(guar) => DummyResult::any(sp, guar),
},
Err(err) => { Err(err) => {
let guar = err.emit(); let guar = err.emit();
DummyResult::any(sp, guar) DummyResult::any(sp, guar)
} }
} })
} }

View file

@ -9,7 +9,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream};
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp}; use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_errors::PResult; 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_parse::parser::Parser;
use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
@ -19,12 +19,12 @@ pub fn expand_assert<'cx>(
cx: &'cx mut ExtCtxt<'_>, cx: &'cx mut ExtCtxt<'_>,
span: Span, span: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) { let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) {
Ok(assert) => assert, Ok(assert) => assert,
Err(err) => { Err(err) => {
let guar = err.emit(); 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) expr_if_not(cx, call_site_span, cond_expr, then, None)
}; };
MacEager::expr(expr) ExpandResult::Ready(MacEager::expr(expr))
} }
struct Assert { struct Assert {

View file

@ -8,17 +8,17 @@ use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_attr as attr; use rustc_attr as attr;
use rustc_errors::PResult; 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; use rustc_span::Span;
pub fn expand_cfg( pub fn expand_cfg(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'static> { ) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp); let sp = cx.with_def_site_ctxt(sp);
match parse_cfg(cx, sp, tts) { ExpandResult::Ready(match parse_cfg(cx, sp, tts) {
Ok(cfg) => { Ok(cfg) => {
let matches_cfg = attr::cfg_matches( let matches_cfg = attr::cfg_matches(
&cfg, &cfg,
@ -32,7 +32,7 @@ pub fn expand_cfg(
let guar = err.emit(); let guar = err.emit();
DummyResult::any(sp, guar) DummyResult::any(sp, guar)
} }
} })
} }
fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {

View file

@ -1,22 +1,26 @@
// The compiler code necessary to support the compile_error! extension. // The compiler code necessary to support the compile_error! extension.
use rustc_ast::tokenstream::TokenStream; 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; use rustc_span::Span;
pub fn expand_compile_error<'cx>( pub fn expand_compile_error<'cx>(
cx: &'cx mut ExtCtxt<'_>, cx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
let var = match get_single_str_from_tts(cx, sp, tts, "compile_error!") { 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, 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::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")]
#[expect(rustc::untranslatable_diagnostic, 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()); let guar = cx.dcx().span_err(sp, var.to_string());
DummyResult::any(sp, guar) ExpandResult::Ready(DummyResult::any(sp, guar))
} }

View file

@ -1,6 +1,7 @@
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{ExprKind, LitKind, UnOp}; 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_session::errors::report_lit_error;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
@ -10,10 +11,13 @@ pub fn expand_concat(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
sp: rustc_span::Span, sp: rustc_span::Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'static> { ) -> MacroExpanderResult<'static> {
let es = match get_exprs_from_tts(cx, tts) { let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
return ExpandResult::Retry(());
};
let es = match mac {
Ok(es) => es, 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 accumulator = String::new();
let mut missing_literal = vec![]; 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 }); 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 { } else if let Some(guar) = guar {
return DummyResult::any(sp, guar); DummyResult::any(sp, guar)
} } else {
let sp = cx.with_def_site_ctxt(sp); let sp = cx.with_def_site_ctxt(sp);
MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
})
} }

View file

@ -1,5 +1,6 @@
use rustc_ast::{ptr::P, token, tokenstream::TokenStream, ExprKind, LitIntType, LitKind, UintTy}; 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_session::errors::report_lit_error;
use rustc_span::{ErrorGuaranteed, Span}; use rustc_span::{ErrorGuaranteed, Span};
@ -111,10 +112,13 @@ pub fn expand_concat_bytes(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'static> { ) -> MacroExpanderResult<'static> {
let es = match get_exprs_from_tts(cx, tts) { let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
return ExpandResult::Retry(());
};
let es = match mac {
Ok(es) => es, 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 accumulator = Vec::new();
let mut missing_literals = vec![]; 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 }); 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 { } else if let Some(guar) = guar {
return MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); MacEager::expr(DummyResult::raw_expr(sp, Some(guar)))
} } else {
let sp = cx.with_def_site_ctxt(sp); let sp = cx.with_def_site_ctxt(sp);
MacEager::expr(cx.expr_byte_str(sp, accumulator)) MacEager::expr(cx.expr_byte_str(sp, accumulator))
})
} }

View file

@ -2,7 +2,7 @@ use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token}; use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::{AttrVec, Expr, ExprKind, Path, Ty, TyKind, DUMMY_NODE_ID}; 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::symbol::{Ident, Symbol};
use rustc_span::Span; use rustc_span::Span;
@ -12,10 +12,10 @@ pub fn expand_concat_idents<'cx>(
cx: &'cx mut ExtCtxt<'_>, cx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
if tts.is_empty() { if tts.is_empty() {
let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp }); 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(); let mut res_str = String::new();
@ -25,7 +25,7 @@ pub fn expand_concat_idents<'cx>(
TokenTree::Token(Token { kind: token::Comma, .. }, _) => {} TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
_ => { _ => {
let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp }); let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp });
return DummyResult::any(sp, guar); return ExpandResult::Ready(DummyResult::any(sp, guar));
} }
} }
} else { } else {
@ -37,7 +37,7 @@ pub fn expand_concat_idents<'cx>(
} }
let guar = cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp }); 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 }))
} }

View file

@ -20,7 +20,7 @@ pub fn expand_panic<'cx>(
cx: &'cx mut ExtCtxt<'_>, cx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
let mac = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 }; let mac = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 };
expand(mac, cx, sp, tts) expand(mac, cx, sp, tts)
} }
@ -33,7 +33,7 @@ pub fn expand_unreachable<'cx>(
cx: &'cx mut ExtCtxt<'_>, cx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
let mac = if use_panic_2021(sp) { sym::unreachable_2021 } else { sym::unreachable_2015 }; let mac = if use_panic_2021(sp) { sym::unreachable_2021 } else { sym::unreachable_2015 };
expand(mac, cx, sp, tts) expand(mac, cx, sp, tts)
} }
@ -43,10 +43,10 @@ fn expand<'cx>(
cx: &'cx mut ExtCtxt<'_>, cx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
let sp = cx.with_call_site_ctxt(sp); let sp = cx.with_call_site_ctxt(sp);
MacEager::expr( ExpandResult::Ready(MacEager::expr(
cx.expr( cx.expr(
sp, sp,
ExprKind::MacCall(P(MacCall { ExprKind::MacCall(P(MacCall {
@ -66,7 +66,7 @@ fn expand<'cx>(
}), }),
})), })),
), ),
) ))
} }
pub fn use_panic_2021(mut span: Span) -> bool { pub fn use_panic_2021(mut span: Span) -> bool {

View file

@ -6,10 +6,8 @@
use rustc_ast::token::{self, LitKind}; use rustc_ast::token::{self, LitKind};
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability}; use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability};
use rustc_expand::base::{ use rustc_expand::base::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts};
expr_to_string, get_exprs_from_tts, get_single_str_from_tts, DummyResult, ExtCtxt, MacEager, use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
MacResult,
};
use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span; use rustc_span::Span;
use std::env; use std::env;
@ -31,10 +29,13 @@ pub fn expand_option_env<'cx>(
cx: &'cx mut ExtCtxt<'_>, cx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { 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, 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); 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)], thin_vec![cx.expr_str(sp, value)],
), ),
}; };
MacEager::expr(e) ExpandResult::Ready(MacEager::expr(e))
} }
pub fn expand_env<'cx>( pub fn expand_env<'cx>(
cx: &'cx mut ExtCtxt<'_>, cx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
let mut exprs = match get_exprs_from_tts(cx, tts) { 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 => { Ok(exprs) if exprs.is_empty() || exprs.len() > 2 => {
let guar = cx.dcx().emit_err(errors::EnvTakesArgs { span: sp }); 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(), Ok(exprs) => exprs.into_iter(),
}; };
let var_expr = exprs.next().unwrap(); 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, 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() { let custom_msg = match exprs.next() {
None => None, None => None,
Some(second) => match expr_to_string(cx, second, "expected string literal") { Some(second) => {
Ok((s, _)) => Some(s), let ExpandResult::Ready(mac) = expr_to_string(cx, second, "expected string literal")
Err(guar) => return DummyResult::any(sp, guar), 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); 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), 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. /// Returns `true` if an environment variable from `env!` is one used by Cargo.

View file

@ -9,7 +9,7 @@ use rustc_ast::{
}; };
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans}; 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::parser::Recovered;
use rustc_parse_format as parse; use rustc_parse_format as parse;
use rustc_span::symbol::{Ident, Symbol}; use rustc_span::symbol::{Ident, Symbol};
@ -40,6 +40,7 @@ use PositionUsedAs::*;
use crate::errors; use crate::errors;
#[derive(Debug)]
struct MacroInput { struct MacroInput {
fmtstr: P<Expr>, fmtstr: P<Expr>,
args: FormatArguments, args: FormatArguments,
@ -160,54 +161,61 @@ fn make_format_args(
ecx: &mut ExtCtxt<'_>, ecx: &mut ExtCtxt<'_>,
input: MacroInput, input: MacroInput,
append_newline: bool, append_newline: bool,
) -> Result<FormatArgs, ErrorGuaranteed> { ) -> ExpandResult<Result<FormatArgs, ErrorGuaranteed>, ()> {
let msg = "format argument must be a string literal"; let msg = "format argument must be a string literal";
let unexpanded_fmt_span = input.fmtstr.span; let unexpanded_fmt_span = input.fmtstr.span;
let MacroInput { fmtstr: efmt, mut args, is_direct_literal } = input; 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) { let (fmt_str, fmt_style, fmt_span) = {
Ok(mut fmt) if append_newline => { let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, efmt.clone(), msg) else {
fmt.0 = Symbol::intern(&format!("{}\n", fmt.0)); return ExpandResult::Retry(());
fmt };
} match mac {
Ok(fmt) => fmt, Ok(mut fmt) if append_newline => {
Err(err) => { fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
let guar = match err { fmt
Ok((mut err, suggested)) => { }
if !suggested { Ok(fmt) => fmt,
if let ExprKind::Block(block, None) = &efmt.kind Err(err) => {
&& block.stmts.len() == 1 let guar = match err {
&& let StmtKind::Expr(expr) = &block.stmts[0].kind Ok((mut err, suggested)) => {
&& let ExprKind::Path(None, path) = &expr.kind if !suggested {
&& path.is_potential_trivial_const_arg() if let ExprKind::Block(block, None) = &efmt.kind
{ && block.stmts.len() == 1
err.multipart_suggestion( && let StmtKind::Expr(expr) = &block.stmts[0].kind
"quote your inlined format argument to use as string literal", && let ExprKind::Path(None, path) = &expr.kind
vec![ && path.is_potential_trivial_const_arg()
(unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()), {
(unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()), err.multipart_suggestion(
], "quote your inlined format argument to use as string literal",
Applicability::MaybeIncorrect, vec![
); (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()),
} else { (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()),
let sugg_fmt = match args.explicit_args().len() { ],
0 => "{}".to_string(), Applicability::MaybeIncorrect,
_ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())), );
}; } else {
err.span_suggestion( let sugg_fmt = match args.explicit_args().len() {
unexpanded_fmt_span.shrink_to_lo(), 0 => "{}".to_string(),
"you might be missing a string literal to format with", _ => {
format!("\"{sugg_fmt}\", "), format!("{}{{}}", "{} ".repeat(args.explicit_args().len()))
Applicability::MaybeIncorrect, }
); };
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,
} };
Err(guar) => guar, return ExpandResult::Ready(Err(guar));
}; }
return Err(guar);
} }
}; };
@ -297,7 +305,7 @@ fn make_format_args(
} }
} }
let guar = ecx.dcx().emit_err(e); let guar = ecx.dcx().emit_err(e);
return Err(guar); return ExpandResult::Ready(Err(guar));
} }
let to_span = |inner_span: rustc_parse_format::InnerSpan| { 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( fn invalid_placeholder_type_error(
@ -972,25 +980,32 @@ fn expand_format_args_impl<'cx>(
mut sp: Span, mut sp: Span,
tts: TokenStream, tts: TokenStream,
nl: bool, nl: bool,
) -> Box<dyn base::MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
sp = ecx.with_def_site_ctxt(sp); sp = ecx.with_def_site_ctxt(sp);
match parse_args(ecx, sp, tts) { ExpandResult::Ready(match parse_args(ecx, sp, tts) {
Ok(input) => match make_format_args(ecx, input, nl) { Ok(input) => {
Ok(format_args) => MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))), let ExpandResult::Ready(mac) = make_format_args(ecx, input, nl) else {
Err(guar) => MacEager::expr(DummyResult::raw_expr(sp, Some(guar))), 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) => { Err(err) => {
let guar = err.emit(); let guar = err.emit();
DummyResult::any(sp, guar) DummyResult::any(sp, guar)
} }
} })
} }
pub fn expand_format_args<'cx>( pub fn expand_format_args<'cx>(
ecx: &'cx mut ExtCtxt<'_>, ecx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
expand_format_args_impl(ecx, sp, tts, false) expand_format_args_impl(ecx, sp, tts, false)
} }
@ -998,6 +1013,6 @@ pub fn expand_format_args_nl<'cx>(
ecx: &'cx mut ExtCtxt<'_>, ecx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
expand_format_args_impl(ecx, sp, tts, true) expand_format_args_impl(ecx, sp, tts, true)
} }

View file

@ -1,14 +1,14 @@
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_expand::base; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
pub fn expand_log_syntax<'cx>( pub fn expand_log_syntax<'cx>(
_cx: &'cx mut base::ExtCtxt<'_>, _cx: &'cx mut ExtCtxt<'_>,
sp: rustc_span::Span, sp: rustc_span::Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
println!("{}", pprust::tts_to_string(&tts)); println!("{}", pprust::tts_to_string(&tts));
// any so that `log_syntax` can be invoked as an expression and item. // any so that `log_syntax` can be invoked as an expression and item.
base::DummyResult::any_valid(sp) ExpandResult::Ready(DummyResult::any_valid(sp))
} }

View file

@ -3,10 +3,9 @@ use rustc_ast::ptr::P;
use rustc_ast::token; use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_expand::base::{ use rustc_expand::base::{check_zero_tts, get_single_str_from_tts, parse_expr, resolve_path};
check_zero_tts, get_single_str_from_tts, parse_expr, resolve_path, DummyResult, ExtCtxt, use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt};
MacEager, MacResult, use rustc_expand::base::{MacEager, MacResult, MacroExpanderResult};
};
use rustc_expand::module::DirOwnership; use rustc_expand::module::DirOwnership;
use rustc_parse::new_parser_from_file; use rustc_parse::new_parser_from_file;
use rustc_parse::parser::{ForceCollect, Parser}; use rustc_parse::parser::{ForceCollect, Parser};
@ -26,14 +25,14 @@ pub fn expand_line(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'static> { ) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp); let sp = cx.with_def_site_ctxt(sp);
check_zero_tts(cx, sp, tts, "line!"); check_zero_tts(cx, sp, tts, "line!");
let topmost = cx.expansion_cause().unwrap_or(sp); let topmost = cx.expansion_cause().unwrap_or(sp);
let loc = cx.source_map().lookup_char_pos(topmost.lo()); 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 */ /* column!(): expands to the current column number */
@ -41,14 +40,14 @@ pub fn expand_column(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'static> { ) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp); let sp = cx.with_def_site_ctxt(sp);
check_zero_tts(cx, sp, tts, "column!"); check_zero_tts(cx, sp, tts, "column!");
let topmost = cx.expansion_cause().unwrap_or(sp); let topmost = cx.expansion_cause().unwrap_or(sp);
let loc = cx.source_map().lookup_char_pos(topmost.lo()); 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 */ /// file!(): expands to the current filename */
@ -58,7 +57,7 @@ pub fn expand_file(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'static> { ) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp); let sp = cx.with_def_site_ctxt(sp);
check_zero_tts(cx, sp, tts, "file!"); 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()); let loc = cx.source_map().lookup_char_pos(topmost.lo());
use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt}; use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
MacEager::expr(cx.expr_str( ExpandResult::Ready(MacEager::expr(cx.expr_str(
topmost, topmost,
Symbol::intern( Symbol::intern(
&loc.file.name.for_scope(cx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(), &loc.file.name.for_scope(cx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
), ),
)) )))
} }
pub fn expand_stringify( pub fn expand_stringify(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'static> { ) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp); let sp = cx.with_def_site_ctxt(sp);
let s = pprust::tts_to_string(&tts); 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( pub fn expand_mod(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'static> { ) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp); let sp = cx.with_def_site_ctxt(sp);
check_zero_tts(cx, sp, tts, "module_path!"); check_zero_tts(cx, sp, tts, "module_path!");
let mod_path = &cx.current_expansion.module.mod_path; let mod_path = &cx.current_expansion.module.mod_path;
let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::"); 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 /// include! : parse the given file as an expr
@ -104,18 +103,21 @@ pub fn expand_include<'cx>(
cx: &'cx mut ExtCtxt<'_>, cx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
let sp = cx.with_def_site_ctxt(sp); 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, 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 // The file will be added to the code map by the parser
let file = match resolve_path(&cx.sess, file.as_str(), sp) { let file = match resolve_path(&cx.sess, file.as_str(), sp) {
Ok(f) => f, Ok(f) => f,
Err(err) => { Err(err) => {
let guar = err.emit(); 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)); 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.module = Rc::new(cx.current_expansion.module.with_dir_path(dir_path));
cx.current_expansion.dir_ownership = DirOwnership::Owned { relative: None }; cx.current_expansion.dir_ownership = DirOwnership::Owned { relative: None };
struct ExpandResult<'a> { struct ExpandInclude<'a> {
p: Parser<'a>, p: Parser<'a>,
node_id: ast::NodeId, node_id: ast::NodeId,
} }
impl<'a> MacResult for ExpandResult<'a> { impl<'a> MacResult for ExpandInclude<'a> {
fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> { fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<P<ast::Expr>> {
let expr = parse_expr(&mut self.p).ok()?; let expr = parse_expr(&mut self.p).ok()?;
if self.p.token != token::Eof { if self.p.token != token::Eof {
self.p.psess.buffer_lint( self.p.psess.buffer_lint(
@ -146,7 +148,7 @@ pub fn expand_include<'cx>(
Some(expr) 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(); let mut ret = SmallVec::new();
loop { loop {
match self.p.parse_item(ForceCollect::No) { 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 /// `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<'_>, cx: &mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'static> { ) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp); 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, 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) { let file = match resolve_path(&cx.sess, file.as_str(), sp) {
Ok(f) => f, Ok(f) => f,
Err(err) => { Err(err) => {
let guar = err.emit(); 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(bytes) => match std::str::from_utf8(&bytes) {
Ok(src) => { Ok(src) => {
let interned_src = Symbol::intern(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)); let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
DummyResult::any(sp, guar) DummyResult::any(sp, guar)
} }
} })
} }
pub fn expand_include_bytes( pub fn expand_include_bytes(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn MacResult + 'static> { ) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp); 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, 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) { let file = match resolve_path(&cx.sess, file.as_str(), sp) {
Ok(f) => f, Ok(f) => f,
Err(err) => { Err(err) => {
let guar = err.emit(); 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) => { Ok(bytes) => {
let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes));
MacEager::expr(expr) 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)); let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
DummyResult::any(sp, guar) DummyResult::any(sp, guar)
} }
} })
} }

View file

@ -1,6 +1,6 @@
use crate::errors; use crate::errors;
use rustc_ast::tokenstream::{TokenStream, TokenTree}; 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::symbol::kw;
use rustc_span::Span; use rustc_span::Span;
@ -8,7 +8,7 @@ pub fn expand_trace_macros(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
sp: Span, sp: Span,
tt: TokenStream, tt: TokenStream,
) -> Box<dyn base::MacResult + 'static> { ) -> MacroExpanderResult<'static> {
let mut cursor = tt.trees(); let mut cursor = tt.trees();
let mut err = false; let mut err = false;
let value = match &cursor.next() { let value = match &cursor.next() {
@ -26,5 +26,5 @@ pub fn expand_trace_macros(
cx.set_trace_macros(value); cx.set_trace_macros(value);
} }
base::DummyResult::any_valid(sp) ExpandResult::Ready(DummyResult::any_valid(sp))
} }

View file

@ -2,25 +2,25 @@ use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{token, Expr, ExprKind, Ty}; use rustc_ast::{token, Expr, ExprKind, Ty};
use rustc_errors::PResult; 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; use rustc_span::Span;
pub fn expand_type_ascribe( pub fn expand_type_ascribe(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
span: Span, span: Span,
tts: TokenStream, tts: TokenStream,
) -> Box<dyn base::MacResult + 'static> { ) -> MacroExpanderResult<'static> {
let (expr, ty) = match parse_ascribe(cx, tts) { let (expr, ty) = match parse_ascribe(cx, tts) {
Ok(parsed) => parsed, Ok(parsed) => parsed,
Err(err) => { Err(err) => {
let guar = err.emit(); 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)); 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>)> { fn parse_ascribe<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Expr>, P<Ty>)> {

View file

@ -245,6 +245,15 @@ pub enum ExpandResult<T, U> {
Retry(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 { pub trait MultiItemModifier {
/// `meta_item` is the attribute, and `item` is the item being modified. /// `meta_item` is the attribute, and `item` is the item being modified.
fn expand( fn expand(
@ -330,22 +339,24 @@ pub trait TTMacroExpander {
ecx: &'cx mut ExtCtxt<'_>, ecx: &'cx mut ExtCtxt<'_>,
span: Span, span: Span,
input: TokenStream, input: TokenStream,
) -> Box<dyn MacResult + 'cx>; ) -> MacroExpanderResult<'cx>;
} }
pub type MacroExpanderResult<'cx> = ExpandResult<Box<dyn MacResult + 'cx>, ()>;
pub type MacroExpanderFn = 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 impl<F> TTMacroExpander for F
where 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>( fn expand<'cx>(
&self, &self,
ecx: &'cx mut ExtCtxt<'_>, ecx: &'cx mut ExtCtxt<'_>,
span: Span, span: Span,
input: TokenStream, input: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
self(ecx, span, input) self(ecx, span, input)
} }
} }
@ -904,8 +915,11 @@ impl SyntaxExtension {
cx: &'cx mut ExtCtxt<'_>, cx: &'cx mut ExtCtxt<'_>,
span: Span, span: Span,
_: TokenStream, _: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
DummyResult::any(span, cx.dcx().span_delayed_bug(span, "expanded a dummy bang macro")) ExpandResult::Ready(DummyResult::any(
span,
cx.dcx().span_delayed_bug(span, "expanded a dummy bang macro"),
))
} }
SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Box::new(expander)), edition) SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Box::new(expander)), edition)
} }
@ -1008,6 +1022,11 @@ pub trait ResolverExpand {
expn_id: LocalExpnId, expn_id: LocalExpnId,
path: &ast::Path, path: &ast::Path,
) -> Result<bool, Indeterminate>; ) -> 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. /// Decodes the proc-macro quoted span in the specified crate, with the specified id.
/// No caching is performed. /// 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`, /// 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. /// 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 /// 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<'_>, cx: &'a mut ExtCtxt<'_>,
expr: P<ast::Expr>, expr: P<ast::Expr>,
err_msg: &'static str, err_msg: &'static str,
) -> Result< ) -> ExpandResult<ExprToSpannedStringResult<'a>, ()> {
(Symbol, ast::StrStyle, Span), if !cx.force_mode
Result<(Diag<'a>, bool /* has_suggestions */), ErrorGuaranteed>, && 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. // Perform eager expansion on the expression.
// We want to be able to handle e.g., `concat!("foo", "bar")`. // We want to be able to handle e.g., `concat!("foo", "bar")`.
let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); 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) { 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(..)) => { Ok(ast::LitKind::ByteStr(..)) => {
let mut err = cx.dcx().struct_span_err(expr.span, err_msg); let mut err = cx.dcx().struct_span_err(expr.span, err_msg);
let span = expr.span.shrink_to_lo(); 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`") 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)), _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)),
}) }))
} }
/// Extracts a string literal from the macro expanded version of `expr`, /// Extracts a string literal from the macro expanded version of `expr`,
@ -1305,13 +1339,14 @@ pub fn expr_to_string(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
expr: P<ast::Expr>, expr: P<ast::Expr>,
err_msg: &'static str, err_msg: &'static str,
) -> Result<(Symbol, ast::StrStyle), ErrorGuaranteed> { ) -> ExpandResult<Result<(Symbol, ast::StrStyle), ErrorGuaranteed>, ()> {
expr_to_spanned_string(cx, expr, err_msg) expr_to_spanned_string(cx, expr, err_msg).map(|res| {
.map_err(|err| match err { res.map_err(|err| match err {
Ok((err, _)) => err.emit(), Ok((err, _)) => err.emit(),
Err(guar) => guar, Err(guar) => guar,
}) })
.map(|(symbol, style, _)| (symbol, style)) .map(|(symbol, style, _)| (symbol, style))
})
} }
/// Non-fatally assert that `tts` is empty. Note that this function /// Non-fatally assert that `tts` is empty. Note that this function
@ -1343,19 +1378,22 @@ pub fn get_single_str_from_tts(
span: Span, span: Span,
tts: TokenStream, tts: TokenStream,
name: &str, name: &str,
) -> Result<Symbol, ErrorGuaranteed> { ) -> ExpandResult<Result<Symbol, ErrorGuaranteed>, ()> {
let mut p = cx.new_parser_from_tts(tts); let mut p = cx.new_parser_from_tts(tts);
if p.token == token::Eof { if p.token == token::Eof {
let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); 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); let _ = p.eat(&token::Comma);
if p.token != token::Eof { if p.token != token::Eof {
cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); 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`. /// Extracts comma-separated expressions from `tts`.
@ -1363,11 +1401,20 @@ pub fn get_single_str_from_tts(
pub fn get_exprs_from_tts( pub fn get_exprs_from_tts(
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
tts: TokenStream, 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 p = cx.new_parser_from_tts(tts);
let mut es = Vec::new(); let mut es = Vec::new();
while p.token != token::Eof { 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. // Perform eager expansion on the expression.
// We want to be able to handle e.g., `concat!("foo", "bar")`. // 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 { if p.token != token::Eof {
let guar = cx.dcx().emit_err(errors::ExpectedCommaInList { span: p.token.span }); 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( pub fn parse_macro_name_and_helper_attrs(

View file

@ -659,7 +659,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
ExpandResult::Ready(match invoc.kind { ExpandResult::Ready(match invoc.kind {
InvocationKind::Bang { mac, .. } => match ext { InvocationKind::Bang { mac, span } => match ext {
SyntaxExtensionKind::Bang(expander) => { SyntaxExtensionKind::Bang(expander) => {
match expander.expand(self.cx, span, mac.args.tokens.clone()) { match expander.expand(self.cx, span, mac.args.tokens.clone()) {
Ok(tok_result) => { Ok(tok_result) => {
@ -669,7 +669,16 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
} }
} }
SyntaxExtensionKind::LegacyBang(expander) => { 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) { let result = if let Some(result) = fragment_kind.make_from(tok_result) {
result result
} else { } else {

View file

@ -1,5 +1,5 @@
use crate::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; use crate::base::{DummyResult, SyntaxExtension, SyntaxExtensionKind};
use crate::base::{SyntaxExtension, SyntaxExtensionKind}; use crate::base::{ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, TTMacroExpander};
use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind}; use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind};
use crate::mbe; use crate::mbe;
use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg}; use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
@ -111,8 +111,8 @@ impl TTMacroExpander for MacroRulesMacroExpander {
cx: &'cx mut ExtCtxt<'_>, cx: &'cx mut ExtCtxt<'_>,
sp: Span, sp: Span,
input: TokenStream, input: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> MacroExpanderResult<'cx> {
expand_macro( ExpandResult::Ready(expand_macro(
cx, cx,
sp, sp,
self.span, self.span,
@ -122,7 +122,7 @@ impl TTMacroExpander for MacroRulesMacroExpander {
input, input,
&self.lhses, &self.lhses,
&self.rhses, &self.rhses,
) ))
} }
} }
@ -134,8 +134,8 @@ impl TTMacroExpander for DummyExpander {
_: &'cx mut ExtCtxt<'_>, _: &'cx mut ExtCtxt<'_>,
span: Span, span: Span,
_: TokenStream, _: TokenStream,
) -> Box<dyn MacResult + 'cx> { ) -> ExpandResult<Box<dyn MacResult + 'cx>, ()> {
DummyResult::any(span, self.0) ExpandResult::Ready(DummyResult::any(span, self.0))
} }
} }

View file

@ -19,7 +19,7 @@ use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, Resolver
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::compile_declarative_macro; use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind, SupportsMacroExpansion}; 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_hir::def_id::{CrateNum, DefId, LocalDefId};
use rustc_middle::middle::stability; use rustc_middle::middle::stability;
use rustc_middle::ty::RegisteredTools; use rustc_middle::ty::RegisteredTools;
@ -431,40 +431,15 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
expn_id: LocalExpnId, expn_id: LocalExpnId,
path: &ast::Path, path: &ast::Path,
) -> Result<bool, Indeterminate> { ) -> Result<bool, Indeterminate> {
let span = path.span; self.path_accessible(expn_id, path, &[TypeNS, ValueNS, MacroNS])
let path = &Segment::from_path(path); }
let parent_scope = self.invocation_parent_scopes[&expn_id];
let mut indeterminate = false; fn macro_accessible(
for ns in [TypeNS, ValueNS, MacroNS].iter().copied() { &mut self,
match self.maybe_resolve_path(path, Some(ns), &parent_scope) { expn_id: LocalExpnId,
PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true), path: &ast::Path,
PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => { ) -> Result<bool, Indeterminate> {
return Ok(true); self.path_accessible(expn_id, path, &[MacroNS])
}
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)
} }
fn get_proc_macro_quoted_span(&self, krate: CrateNum, id: usize) -> Span { 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!() }; let ItemKind::MacroDef(def) = &item.kind else { unreachable!() };
MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: def.macro_rules } 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)
}
} }

View file

@ -0,0 +1,27 @@
//@only-aarch64
//@check-pass
//@edition: 2018
// https://github.com/rust-lang/rust/issues/98291
use std::arch::{asm, global_asm};
macro_rules! wrap {
() => {
macro_rules! _a {
() => {
"nop"
};
}
};
}
wrap!();
use _a as a;
fn main() {
unsafe { asm!(a!()); }
}
global_asm!(a!());

View file

@ -0,0 +1,33 @@
//@check-pass
//@edition: 2018
// https://github.com/rust-lang/rust/issues/98291
macro_rules! wrap {
() => {
macro_rules! _a {
() => {
"auxiliary/macro-include-items-expr.rs"
};
}
macro_rules! _env_name {
() => {
"PATH"
}
}
};
}
wrap!();
use _a as a;
use _env_name as env_name;
fn main() {
format_args!(a!());
include!(a!());
include_str!(a!());
include_bytes!(a!());
env!(env_name!());
option_env!(env_name!());
}

View file

@ -0,0 +1,20 @@
//@edition: 2018
// https://github.com/rust-lang/rust/issues/98291
macro_rules! wrap {
() => {
macro_rules! _a {
() => {
""
};
}
};
}
wrap!();
fn main() {
format_args!(a!()); //~ ERROR: cannot find macro `a` in this scope
env!(a!()); //~ ERROR: cannot find macro `a` in this scope
}

View file

@ -0,0 +1,30 @@
error: cannot find macro `a` in this scope
--> $DIR/expand-full-no-resolution.rs:18:18
|
LL | macro_rules! _a {
| --------------- similarly named macro `_a` defined here
...
LL | format_args!(a!());
| ^
|
help: a macro with a similar name exists, consider renaming `_a` into `a`
|
LL | macro_rules! a {
| ~
error: cannot find macro `a` in this scope
--> $DIR/expand-full-no-resolution.rs:19:10
|
LL | macro_rules! _a {
| --------------- similarly named macro `_a` defined here
...
LL | env!(a!());
| ^
|
help: a macro with a similar name exists, consider renaming `_a` into `a`
|
LL | macro_rules! a {
| ~
error: aborting due to 2 previous errors