Skip to content

Commit

Permalink
Auto merge of rust-lang#121589 - bvanjoi:fix-98291, r=petrochenkov
Browse files Browse the repository at this point in the history
delay expand macro bang when there has indeterminate path

Related rust-lang#98291

I will attempt to clarify the root problem through several examples:

Firstly,

```rs
// rustc code.rs --edition=2018

macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!(_a!());
}
```

The above case will compile successfully because `_a` is defined after the `wrap` expaned, ensuring `_a` can be resolved without any issues.

And,

```rs
// rustc code.rs --edition=2018

macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!("{}", a!());
}
```

The above example will also compile successfully because the `parse_args` in `expand_format_args_impl` will return a value `MacroInput { fmtstr: Expr::Lit::Str, args: [Expr::MacroCall]}`. Since the graph for `args` will be build lately, `a` will eventually be resolved.

However, in the case of:

```rs
// rustc code.rs --edition=2018

macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!(a!());
}
```

The result of `parse_args` is `MacroInput {fmtstr: Expr::Lit::Macro, args: [] }`, we attempt to expand `fmtstr` **eagerly** within `expr_to_spanned_string`. Although we have recorded `(root, _a)` into resolutions, `use _a as a` is an indeterminate import, which will not try to resolve under the conditions of `expander.monotonic = false`.

Therefore, I've altered the strategy for resolving indeterminate imports, ensuring it will also resolve during eager expansion. This could be a significant change to the resolution infra. However, I think it's acceptable if the goal of avoiding resolution under eager expansion is to save time.

r? `@petrochenkov`
  • Loading branch information
bors committed Mar 13, 2024
2 parents 9ce37dc + 8fcdf54 commit 184c5ab
Show file tree
Hide file tree
Showing 22 changed files with 509 additions and 263 deletions.
76 changes: 44 additions & 32 deletions compiler/rustc_builtin_macros/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -443,7 +443,7 @@ fn parse_reg<'a>(
fn expand_preparsed_asm(
ecx: &mut ExtCtxt<'_>,
args: AsmArgs,
) -> Result<ast::InlineAsm, ErrorGuaranteed> {
) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
let mut template = vec![];
// Register operands are implicitly used since they are not allowed to be
// referenced in the template string.
Expand All @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -729,24 +733,27 @@ fn expand_preparsed_asm(
}
}

Ok(ast::InlineAsm {
ExpandResult::Ready(Ok(ast::InlineAsm {
template,
template_strs: template_strs.into_boxed_slice(),
operands: args.operands,
clobber_abis: args.clobber_abis,
options: args.options,
line_spans,
})
}))
}

pub(super) fn expand_asm<'cx>(
ecx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> {
match parse_args(ecx, sp, tts, false) {
) -> MacroExpanderResult<'cx> {
ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
Ok(args) => {
let expr = match expand_preparsed_asm(ecx, args) {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
return ExpandResult::Retry(());
};
let expr = match mac {
Ok(inline_asm) => P(ast::Expr {
id: ast::DUMMY_NODE_ID,
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
Expand All @@ -762,34 +769,39 @@ pub(super) fn expand_asm<'cx>(
let guar = err.emit();
DummyResult::any(sp, guar)
}
}
})
}

pub(super) fn expand_global_asm<'cx>(
ecx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> {
match parse_args(ecx, sp, tts, true) {
Ok(args) => match expand_preparsed_asm(ecx, args) {
Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item {
ident: Ident::empty(),
attrs: ast::AttrVec::new(),
id: ast::DUMMY_NODE_ID,
kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
vis: ast::Visibility {
span: sp.shrink_to_lo(),
kind: ast::VisibilityKind::Inherited,
) -> MacroExpanderResult<'cx> {
ExpandResult::Ready(match parse_args(ecx, sp, tts, true) {
Ok(args) => {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
return ExpandResult::Retry(());
};
match mac {
Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item {
ident: Ident::empty(),
attrs: ast::AttrVec::new(),
id: ast::DUMMY_NODE_ID,
kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
vis: ast::Visibility {
span: sp.shrink_to_lo(),
kind: ast::VisibilityKind::Inherited,
tokens: None,
},
span: sp,
tokens: None,
},
span: sp,
tokens: None,
})]),
Err(guar) => DummyResult::any(sp, guar),
},
})]),
Err(guar) => DummyResult::any(sp, guar),
}
}
Err(err) => {
let guar = err.emit();
DummyResult::any(sp, guar)
}
}
})
}
8 changes: 4 additions & 4 deletions compiler/rustc_builtin_macros/src/assert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -19,12 +19,12 @@ pub fn expand_assert<'cx>(
cx: &'cx mut ExtCtxt<'_>,
span: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) {
Ok(assert) => assert,
Err(err) => {
let guar = err.emit();
return DummyResult::any(span, guar);
return ExpandResult::Ready(DummyResult::any(span, guar));
}
};

Expand Down Expand Up @@ -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 {
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_builtin_macros/src/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_attr as attr;
use rustc_errors::PResult;
use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_span::Span;

pub fn expand_cfg(
cx: &mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp);

match parse_cfg(cx, sp, tts) {
ExpandResult::Ready(match parse_cfg(cx, sp, tts) {
Ok(cfg) => {
let matches_cfg = attr::cfg_matches(
&cfg,
Expand All @@ -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> {
Expand Down
14 changes: 9 additions & 5 deletions compiler/rustc_builtin_macros/src/compile_error.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
// The compiler code necessary to support the compile_error! extension.

use rustc_ast::tokenstream::TokenStream;
use rustc_expand::base::{get_single_str_from_tts, DummyResult, ExtCtxt, MacResult};
use rustc_expand::base::get_single_str_from_tts;
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
use rustc_span::Span;

pub fn expand_compile_error<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
let var = match get_single_str_from_tts(cx, sp, tts, "compile_error!") {
) -> MacroExpanderResult<'cx> {
let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "compile_error!") else {
return ExpandResult::Retry(());
};
let var = match mac {
Ok(var) => var,
Err(guar) => return DummyResult::any(sp, guar),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};

#[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")]
#[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
let guar = cx.dcx().span_err(sp, var.to_string());

DummyResult::any(sp, guar)
ExpandResult::Ready(DummyResult::any(sp, guar))
}
25 changes: 15 additions & 10 deletions compiler/rustc_builtin_macros/src/concat.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -10,10 +11,13 @@ pub fn expand_concat(
cx: &mut ExtCtxt<'_>,
sp: rustc_span::Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
let es = match get_exprs_from_tts(cx, tts) {
) -> MacroExpanderResult<'static> {
let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
return ExpandResult::Retry(());
};
let es = match mac {
Ok(es) => es,
Err(guar) => return DummyResult::any(sp, guar),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
let mut accumulator = String::new();
let mut missing_literal = vec![];
Expand Down Expand Up @@ -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)))
})
}
25 changes: 15 additions & 10 deletions compiler/rustc_builtin_macros/src/concat_bytes.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -111,10 +112,13 @@ pub fn expand_concat_bytes(
cx: &mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
let es = match get_exprs_from_tts(cx, tts) {
) -> MacroExpanderResult<'static> {
let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
return ExpandResult::Retry(());
};
let es = match mac {
Ok(es) => es,
Err(guar) => return DummyResult::any(sp, guar),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
let mut accumulator = Vec::new();
let mut missing_literals = vec![];
Expand Down Expand Up @@ -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))
})
}
12 changes: 6 additions & 6 deletions compiler/rustc_builtin_macros/src/concat_idents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -12,10 +12,10 @@ pub fn expand_concat_idents<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
if tts.is_empty() {
let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp });
return DummyResult::any(sp, guar);
return ExpandResult::Ready(DummyResult::any(sp, guar));
}

let mut res_str = String::new();
Expand All @@ -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 {
Expand All @@ -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));
}
}

Expand Down Expand Up @@ -68,5 +68,5 @@ pub fn expand_concat_idents<'cx>(
}
}

Box::new(ConcatIdentsResult { ident })
ExpandResult::Ready(Box::new(ConcatIdentsResult { ident }))
}
Loading

0 comments on commit 184c5ab

Please sign in to comment.