From 8fcdf54a6b98c129e951caf3a97cbf20db677ee3 Mon Sep 17 00:00:00 2001 From: bohan Date: Tue, 12 Mar 2024 10:55:17 +0800 Subject: [PATCH] delay expand macro bang when there has indeterminate path --- compiler/rustc_builtin_macros/src/asm.rs | 76 ++++++----- compiler/rustc_builtin_macros/src/assert.rs | 8 +- compiler/rustc_builtin_macros/src/cfg.rs | 8 +- .../rustc_builtin_macros/src/compile_error.rs | 14 +- compiler/rustc_builtin_macros/src/concat.rs | 25 ++-- .../rustc_builtin_macros/src/concat_bytes.rs | 25 ++-- .../rustc_builtin_macros/src/concat_idents.rs | 12 +- .../rustc_builtin_macros/src/edition_panic.rs | 10 +- compiler/rustc_builtin_macros/src/env.rs | 54 +++++--- compiler/rustc_builtin_macros/src/format.rs | 121 ++++++++++-------- .../rustc_builtin_macros/src/log_syntax.rs | 8 +- .../rustc_builtin_macros/src/source_util.rs | 80 ++++++------ .../rustc_builtin_macros/src/trace_macros.rs | 6 +- .../rustc_builtin_macros/src/type_ascribe.rs | 8 +- compiler/rustc_expand/src/base.rs | 95 ++++++++++---- compiler/rustc_expand/src/expand.rs | 13 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 14 +- compiler/rustc_resolve/src/macros.rs | 85 +++++++----- tests/ui/macros/expand-full-asm.rs | 27 ++++ tests/ui/macros/expand-full-in-format-str.rs | 33 +++++ tests/ui/macros/expand-full-no-resolution.rs | 20 +++ .../macros/expand-full-no-resolution.stderr | 30 +++++ 22 files changed, 509 insertions(+), 263 deletions(-) create mode 100644 tests/ui/macros/expand-full-asm.rs create mode 100644 tests/ui/macros/expand-full-in-format-str.rs create mode 100644 tests/ui/macros/expand-full-no-resolution.rs create mode 100644 tests/ui/macros/expand-full-no-resolution.stderr diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index bc851fadc2e24..62c02817011fd 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 { +) -> ExpandResult, ()> { 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 { - 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 { - 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 613ce43dec2d6..35a0857fe51ce 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 { +) -> 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 04bf7dceeff49..9197b9ebdf9fc 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 { +) -> 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 b4455d7823f35..2f2a87fc9aa00 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 { - 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 0bfb848859bd8..93a7ac05a9bef 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 { - 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 502bfb4467e52..a2f827c5567d8 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 { - 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 fffcddc5325bd..3ddb0ae45b51a 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 { +) -> 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 1e1dadab48067..fa22e91164232 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 { +) -> 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 { +) -> 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 { +) -> 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 193b38a83238a..bce710e5cab12 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 { - 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 { - 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 385c90ff14b2d..6f031f270cae5 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, args: FormatArguments, @@ -160,54 +161,61 @@ fn make_format_args( ecx: &mut ExtCtxt<'_>, input: MacroInput, append_newline: bool, -) -> Result { +) -> ExpandResult, ()> { 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 { +) -> 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 { +) -> 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 { +) -> 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 ede34a7612589..288a475ac241c 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 { +) -> 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 2da9bda19e034..dbb86df6811da 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 { +) -> 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 { +) -> 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 { +) -> 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 { +) -> 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 { +) -> 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::>().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 { +) -> 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>) -> Option> { + impl<'a> MacResult for ExpandInclude<'a> { + fn make_expr(mut self: Box>) -> Option> { 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>) -> Option; 1]>> { + fn make_items(mut self: Box>) -> Option; 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 { +) -> 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 { +) -> 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 e076aa6da73d3..696d99004ba01 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 { +) -> 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 e8b8fe75338cb..f3e66ffc759db 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 { +) -> 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, P)> { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 69dfb48919cdb..30ee02ea3c0aa 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -245,6 +245,15 @@ pub enum ExpandResult { Retry(U), } +impl ExpandResult { + pub fn map E>(self, f: F) -> ExpandResult { + 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; + ) -> MacroExpanderResult<'cx>; } +pub type MacroExpanderResult<'cx> = ExpandResult, ()>; + pub type MacroExpanderFn = - for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> Box; + for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> MacroExpanderResult<'cx>; impl TTMacroExpander for F where - F: for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> Box, + F: for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> MacroExpanderResult<'cx>, { fn expand<'cx>( &self, ecx: &'cx mut ExtCtxt<'_>, span: Span, input: TokenStream, - ) -> Box { + ) -> MacroExpanderResult<'cx> { self(ecx, span, input) } } @@ -904,8 +915,11 @@ impl SyntaxExtension { cx: &'cx mut ExtCtxt<'_>, span: Span, _: TokenStream, - ) -> Box { - 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; + fn macro_accessible( + &mut self, + expn_id: LocalExpnId, + path: &ast::Path, + ) -> Result; /// 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, 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, err_msg: &'static str, -) -> Result< - (Symbol, ast::StrStyle, Span), - Result<(Diag<'a>, bool /* has_suggestions */), ErrorGuaranteed>, -> { +) -> ExpandResult, ()> { + if !cx.force_mode + && let ast::ExprKind::MacCall(m) = &expr.kind + && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err() + { + return ExpandResult::Retry(()); + } + // Perform eager expansion on the expression. // We want to be able to handle e.g., `concat!("foo", "bar")`. let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); - 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, err_msg: &'static str, -) -> Result<(Symbol, ast::StrStyle), ErrorGuaranteed> { - expr_to_spanned_string(cx, expr, err_msg) - .map_err(|err| match err { +) -> ExpandResult, ()> { + expr_to_spanned_string(cx, expr, err_msg).map(|res| { + res.map_err(|err| match err { Ok((err, _)) => err.emit(), Err(guar) => guar, }) .map(|(symbol, style, _)| (symbol, style)) + }) } /// Non-fatally assert that `tts` is empty. Note that this function @@ -1343,19 +1378,22 @@ pub fn get_single_str_from_tts( span: Span, tts: TokenStream, name: &str, -) -> Result { +) -> ExpandResult, ()> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); - return 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>, ErrorGuaranteed> { +) -> ExpandResult>, 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 fcc439e71f95b..3544a8f0a8d92 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 8903fc45defbc..3f29d7f74659c 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 { - 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 { - DummyResult::any(span, self.0) + ) -> ExpandResult, ()> { + ExpandResult::Ready(DummyResult::any(span, self.0)) } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index d8fd8d22439c2..dbca2f9895d20 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 { - 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 { + 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 { + 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) + } } diff --git a/tests/ui/macros/expand-full-asm.rs b/tests/ui/macros/expand-full-asm.rs new file mode 100644 index 0000000000000..0b61aa718f301 --- /dev/null +++ b/tests/ui/macros/expand-full-asm.rs @@ -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!()); diff --git a/tests/ui/macros/expand-full-in-format-str.rs b/tests/ui/macros/expand-full-in-format-str.rs new file mode 100644 index 0000000000000..f47f7651a812b --- /dev/null +++ b/tests/ui/macros/expand-full-in-format-str.rs @@ -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!()); +} diff --git a/tests/ui/macros/expand-full-no-resolution.rs b/tests/ui/macros/expand-full-no-resolution.rs new file mode 100644 index 0000000000000..4d90b8e2a531a --- /dev/null +++ b/tests/ui/macros/expand-full-no-resolution.rs @@ -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 +} diff --git a/tests/ui/macros/expand-full-no-resolution.stderr b/tests/ui/macros/expand-full-no-resolution.stderr new file mode 100644 index 0000000000000..2537a5032a92d --- /dev/null +++ b/tests/ui/macros/expand-full-no-resolution.stderr @@ -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 +