Skip to content

Commit 3866917

Browse files
committed
Auto merge of rust-lang#128605 - futile:expand1-cont, r=<try>
Make declarative macro expansion a part of query system (cont. of rust-lang#125356) This is a continuation of the effort to make declarative macro expansion a part of the query system from rust-lang#125356 by `@SparrowLii.` #### Description from that PR: > This is an attempt to make the macro expansion a part of incremental compilation. > > Processing of procedural macros is difficult since they may involve interactions with the external environment. Declaring macros is a good start. > > **It is not yet possible to test the effect of this PR on incremental compilation since the new query is declared as eval_always.** #### Status of this PR: * It is rebased against a much more recent `master` commit * It contains the original commits from rust-lang#125356 (in a rebased form) * It adds the missing implementation for retrying macro matching that provides (better) error diagnostics * This was done by refactoring `rustc_expand::mbe::diagnostics::failed_to_match_macro()` to only require a `ParseSess` instead of an `ExtCtxt`. Otherwise, `ExtCtxt` would need to be in the interface of `TcxMacroExpander`, which is not possible, because `ExtCtxt` is part of `rustc_expand`, which depends on the crate that contains `TcxMacroExpander`, `rustc_middle`, and thus would introduce a circular dependency. * This refactoring moved the retrying down into the `impl TcxMacroExpander for MacroRulesMacroExpander` (this is just a change compared to the original PR, otherwise not important to know). * This PR passes `./x test tests/ui`, which produced errors before that were all due to the missing implementation of retry macro matching. * This PR does **not** yet contain changes for the open discussions from rust-lang#125356. I wanted to fix the tests first before tackling them, and I also need to figure out what the best solutions for them are. I'd welcome any help/support with this, e.g., opening up a corresponding discussion on this PR with a summary/the final decided fix if available :) In general, I'm new to working on rustc, so would be thankful for a bit more background/explanations in discussions and comments :) Thanks! :) (tangentially relevant: rust-lang#99515)
2 parents 60d1465 + 6134b01 commit 3866917

File tree

19 files changed

+310
-43
lines changed

19 files changed

+310
-43
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3690,6 +3690,7 @@ dependencies = [
36903690
"rustc_lexer",
36913691
"rustc_lint_defs",
36923692
"rustc_macros",
3693+
"rustc_middle",
36933694
"rustc_parse",
36943695
"rustc_serialize",
36953696
"rustc_session",

compiler/rustc_ast/src/token.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::borrow::Cow;
22
use std::fmt;
3+
use std::hash::Hash;
34

45
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
56
use rustc_data_structures::sync::Lrc;
@@ -21,7 +22,7 @@ use crate::ast;
2122
use crate::ptr::P;
2223
use crate::util::case::Case;
2324

24-
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
25+
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Hash)]
2526
pub enum CommentKind {
2627
Line,
2728
Block,

compiler/rustc_ast/src/tokenstream.rs

-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ where
105105
}
106106
}
107107
}
108-
109108
pub trait ToAttrTokenStream: sync::DynSend + sync::DynSync {
110109
fn to_attr_token_stream(&self) -> AttrTokenStream;
111110
}

compiler/rustc_expand/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" }
2020
rustc_lexer = { path = "../rustc_lexer" }
2121
rustc_lint_defs = { path = "../rustc_lint_defs" }
2222
rustc_macros = { path = "../rustc_macros" }
23+
rustc_middle = { path = "../rustc_middle" }
2324
rustc_parse = { path = "../rustc_parse" }
2425
rustc_serialize = { path = "../rustc_serialize" }
2526
rustc_session = { path = "../rustc_session" }

compiler/rustc_expand/src/base.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_data_structures::sync::{self, Lrc};
1515
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
1616
use rustc_feature::Features;
1717
use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools};
18+
use rustc_middle::expand::TcxMacroExpander;
1819
use rustc_parse::parser::Parser;
1920
use rustc_parse::MACRO_ARGUMENTS;
2021
use rustc_session::config::CollapseMacroDebuginfo;
@@ -676,6 +677,11 @@ pub enum SyntaxExtensionKind {
676677
Box<dyn TTMacroExpander + sync::DynSync + sync::DynSend>,
677678
),
678679

680+
TcxLegacyBang(
681+
/// An expander with signature TokenStream -> AST.
682+
Lrc<dyn TcxMacroExpander + sync::DynSync + sync::DynSend>,
683+
),
684+
679685
/// A token-based attribute macro.
680686
Attr(
681687
/// An expander with signature (TokenStream, TokenStream) -> TokenStream.
@@ -754,7 +760,8 @@ impl SyntaxExtension {
754760
match self.kind {
755761
SyntaxExtensionKind::Bang(..)
756762
| SyntaxExtensionKind::LegacyBang(..)
757-
| SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang,
763+
| SyntaxExtensionKind::GlobDelegation(..)
764+
| SyntaxExtensionKind::TcxLegacyBang(..) => MacroKind::Bang,
758765
SyntaxExtensionKind::Attr(..)
759766
| SyntaxExtensionKind::LegacyAttr(..)
760767
| SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
@@ -1072,6 +1079,12 @@ pub trait ResolverExpand {
10721079
trait_def_id: DefId,
10731080
impl_def_id: LocalDefId,
10741081
) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate>;
1082+
1083+
fn expand_legacy_bang(
1084+
&self,
1085+
invoc_id: LocalExpnId,
1086+
current_expansion: LocalExpnId,
1087+
) -> Result<(TokenStream, usize), (Span, ErrorGuaranteed)>;
10751088
}
10761089

10771090
pub trait LintStoreExpand {

compiler/rustc_expand/src/expand.rs

+72-1
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ use rustc_ast::visit::{self, try_visit, walk_list, AssocCtxt, Visitor, VisitorRe
1212
use rustc_ast::{
1313
AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind, ForeignItemKind,
1414
HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem,
15-
NodeId, PatKind, StmtKind, TyKind,
15+
NodeId, PatKind, StmtKind, TyKind, DUMMY_NODE_ID,
1616
};
1717
use rustc_ast_pretty::pprust;
1818
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
1919
use rustc_data_structures::sync::Lrc;
2020
use rustc_errors::PResult;
2121
use rustc_feature::Features;
22+
use rustc_middle::ty::TyCtxt;
2223
use rustc_parse::parser::{
2324
AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
2425
};
@@ -40,6 +41,7 @@ use crate::errors::{
4041
WrongFragmentKind,
4142
};
4243
use crate::mbe::diagnostics::annotate_err_with_kind;
44+
use crate::mbe::macro_rules::{trace_macros_note, ParserAnyMacro};
4345
use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
4446
use crate::placeholders::{placeholder, PlaceholderExpander};
4547

@@ -394,6 +396,18 @@ pub struct MacroExpander<'a, 'b> {
394396
monotonic: bool, // cf. `cx.monotonic_expander()`
395397
}
396398

399+
pub fn expand_legacy_bang<'tcx>(
400+
tcx: TyCtxt<'tcx>,
401+
key: (LocalExpnId, LocalExpnId),
402+
) -> Result<(&'tcx TokenStream, usize), (Span, ErrorGuaranteed)> {
403+
let (invoc_id, current_expansion) = key;
404+
let map = tcx.macro_map.borrow();
405+
let (arg, span, expander) = map.get(&invoc_id).as_ref().unwrap();
406+
expander
407+
.expand(&tcx.sess, *span, arg.clone(), current_expansion)
408+
.map(|(tts, i)| (tcx.arena.alloc(tts) as &TokenStream, i))
409+
}
410+
397411
impl<'a, 'b> MacroExpander<'a, 'b> {
398412
pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
399413
MacroExpander { cx, monotonic }
@@ -679,6 +693,63 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
679693
Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
680694
}
681695
}
696+
SyntaxExtensionKind::TcxLegacyBang(expander) => {
697+
// Macros defined in the current crate have a real node id,
698+
// whereas macros from an external crate have a dummy id.
699+
if self.cx.trace_macros() {
700+
let msg = format!(
701+
"expanding `{}! {{ {} }}`",
702+
expander.name(),
703+
pprust::tts_to_string(&mac.args.tokens)
704+
);
705+
trace_macros_note(&mut self.cx.expansions, span, msg);
706+
}
707+
708+
// Macros defined in the current crate have a real node id,
709+
// whereas macros from an external crate have a dummy id.\
710+
let tok_result: Box<dyn MacResult> = match self
711+
.cx
712+
.resolver
713+
.expand_legacy_bang(invoc.expansion_data.id, self.cx.current_expansion.id)
714+
{
715+
Ok((tts, i)) => {
716+
if self.cx.trace_macros() {
717+
let msg = format!("to `{}`", pprust::tts_to_string(&tts));
718+
trace_macros_note(&mut self.cx.expansions, span, msg);
719+
}
720+
let is_local = expander.node_id() != DUMMY_NODE_ID;
721+
if is_local {
722+
self.cx.resolver.record_macro_rule_usage(expander.node_id(), i);
723+
}
724+
725+
// Let the context choose how to interpret the result.
726+
// Weird, but useful for X-macros.
727+
Box::new(ParserAnyMacro::new(
728+
Parser::new(&self.cx.sess.psess, tts.clone(), None),
729+
// Pass along the original expansion site and the name of the macro,
730+
// so we can print a useful error message if the parse of the expanded
731+
// macro leaves unparsed tokens.
732+
span,
733+
expander.name(),
734+
self.cx.current_expansion.lint_node_id,
735+
self.cx.current_expansion.is_trailing_mac,
736+
expander.arm_span(i),
737+
is_local,
738+
))
739+
}
740+
Err((span, guar)) => {
741+
self.cx.trace_macros_diag();
742+
DummyResult::any(span, guar)
743+
}
744+
};
745+
let result = if let Some(result) = fragment_kind.make_from(tok_result) {
746+
result
747+
} else {
748+
let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span);
749+
fragment_kind.dummy(span, guar)
750+
};
751+
result
752+
}
682753
SyntaxExtensionKind::LegacyBang(expander) => {
683754
let tok_result = match expander.expand(self.cx, span, mac.args.tokens.clone()) {
684755
ExpandResult::Ready(tok_result) => tok_result,

compiler/rustc_expand/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ mod placeholders;
2626
mod proc_macro_server;
2727

2828
pub use mbe::macro_rules::compile_declarative_macro;
29+
use rustc_middle::query::Providers;
2930
pub mod base;
3031
pub mod config;
3132
pub mod expand;
@@ -34,4 +35,8 @@ pub mod module;
3435
#[allow(rustc::untranslatable_diagnostic)]
3536
pub mod proc_macro;
3637

38+
pub fn provide(providers: &mut Providers) {
39+
providers.expand_legacy_bang = expand::expand_legacy_bang;
40+
}
41+
3742
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

compiler/rustc_expand/src/mbe/diagnostics.rs

+24-27
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,40 @@ use std::borrow::Cow;
33
use rustc_ast::token::{self, Token, TokenKind};
44
use rustc_ast::tokenstream::TokenStream;
55
use rustc_ast_pretty::pprust;
6-
use rustc_errors::{Applicability, Diag, DiagMessage};
6+
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
77
use rustc_macros::Subdiagnostic;
88
use rustc_parse::parser::{Parser, Recovery};
9+
use rustc_session::parse::ParseSess;
910
use rustc_span::source_map::SourceMap;
1011
use rustc_span::symbol::Ident;
1112
use rustc_span::{ErrorGuaranteed, Span};
1213
use tracing::debug;
1314

1415
use super::macro_rules::{parser_from_cx, NoopTracker};
15-
use crate::base::{DummyResult, ExtCtxt, MacResult};
1616
use crate::expand::{parse_ast_fragment, AstFragmentKind};
1717
use crate::mbe::macro_parser::ParseResult::*;
1818
use crate::mbe::macro_parser::{MatcherLoc, NamedParseResult, TtParser};
1919
use crate::mbe::macro_rules::{try_match_macro, Tracker};
2020

21-
pub(super) fn failed_to_match_macro<'cx>(
22-
cx: &'cx mut ExtCtxt<'_>,
21+
pub(crate) fn failed_to_match_macro(
22+
psess: &ParseSess,
2323
sp: Span,
2424
def_span: Span,
2525
name: Ident,
2626
arg: TokenStream,
2727
lhses: &[Vec<MatcherLoc>],
28-
) -> Box<dyn MacResult + 'cx> {
29-
let psess = &cx.sess.psess;
30-
28+
) -> (Span, ErrorGuaranteed) {
3129
// An error occurred, try the expansion again, tracking the expansion closely for better
3230
// diagnostics.
33-
let mut tracker = CollectTrackerAndEmitter::new(cx, sp);
31+
let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp);
3432

3533
let try_success_result = try_match_macro(psess, name, &arg, lhses, &mut tracker);
3634

3735
if try_success_result.is_ok() {
3836
// Nonterminal parser recovery might turn failed matches into successful ones,
3937
// but for that it must have emitted an error already
4038
assert!(
41-
tracker.cx.dcx().has_errors().is_some(),
39+
tracker.dcx.has_errors().is_some(),
4240
"Macro matching returned a success on the second try"
4341
);
4442
}
@@ -50,15 +48,15 @@ pub(super) fn failed_to_match_macro<'cx>(
5048

5149
let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure
5250
else {
53-
return DummyResult::any(sp, cx.dcx().span_delayed_bug(sp, "failed to match a macro"));
51+
return (sp, psess.dcx().span_delayed_bug(sp, "failed to match a macro"));
5452
};
5553

5654
let span = token.span.substitute_dummy(sp);
5755

58-
let mut err = cx.dcx().struct_span_err(span, parse_failure_msg(&token, None));
56+
let mut err = psess.dcx().struct_span_err(span, parse_failure_msg(&token, None));
5957
err.span_label(span, label);
60-
if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
61-
err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
58+
if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) {
59+
err.span_label(psess.source_map().guess_head_span(def_span), "when calling this macro");
6260
}
6361

6462
annotate_doc_comment(&mut err, psess.source_map(), span);
@@ -76,7 +74,7 @@ pub(super) fn failed_to_match_macro<'cx>(
7674
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
7775
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
7876

79-
if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
77+
if !def_span.is_dummy() && !psess.source_map().is_imported(def_span) {
8078
err.help("try using `:tt` instead in the macro definition");
8179
}
8280
}
@@ -104,18 +102,17 @@ pub(super) fn failed_to_match_macro<'cx>(
104102
}
105103
}
106104
let guar = err.emit();
107-
cx.trace_macros_diag();
108-
DummyResult::any(sp, guar)
105+
(sp, guar)
109106
}
110107

111108
/// The tracker used for the slow error path that collects useful info for diagnostics.
112-
struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
113-
cx: &'a mut ExtCtxt<'cx>,
109+
struct CollectTrackerAndEmitter<'dcx, 'matcher> {
110+
dcx: DiagCtxtHandle<'dcx>,
114111
remaining_matcher: Option<&'matcher MatcherLoc>,
115112
/// Which arm's failure should we report? (the one furthest along)
116113
best_failure: Option<BestFailure>,
117114
root_span: Span,
118-
result: Option<Box<dyn MacResult + 'cx>>,
115+
result: Option<(Span, ErrorGuaranteed)>,
119116
}
120117

121118
struct BestFailure {
@@ -131,7 +128,7 @@ impl BestFailure {
131128
}
132129
}
133130

134-
impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
131+
impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'matcher> {
135132
type Failure = (Token, u32, &'static str);
136133

137134
fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure {
@@ -151,7 +148,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
151148
Success(_) => {
152149
// Nonterminal parser recovery might turn failed matches into successful ones,
153150
// but for that it must have emitted an error already
154-
self.cx.dcx().span_delayed_bug(
151+
self.dcx.span_delayed_bug(
155152
self.root_span,
156153
"should not collect detailed info for successful macro match",
157154
);
@@ -177,10 +174,10 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
177174
}
178175
Error(err_sp, msg) => {
179176
let span = err_sp.substitute_dummy(self.root_span);
180-
let guar = self.cx.dcx().span_err(span, msg.clone());
181-
self.result = Some(DummyResult::any(span, guar));
177+
let guar = self.dcx.span_err(span, msg.clone());
178+
self.result = Some((span, guar));
182179
}
183-
ErrorReported(guar) => self.result = Some(DummyResult::any(self.root_span, *guar)),
180+
ErrorReported(guar) => self.result = Some((self.root_span, *guar)),
184181
}
185182
}
186183

@@ -193,9 +190,9 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
193190
}
194191
}
195192

196-
impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx, '_> {
197-
fn new(cx: &'a mut ExtCtxt<'cx>, root_span: Span) -> Self {
198-
Self { cx, remaining_matcher: None, best_failure: None, root_span, result: None }
193+
impl<'dcx> CollectTrackerAndEmitter<'dcx, '_> {
194+
fn new(dcx: DiagCtxtHandle<'dcx>, root_span: Span) -> Self {
195+
Self { dcx, remaining_matcher: None, best_failure: None, root_span, result: None }
199196
}
200197
}
201198

0 commit comments

Comments
 (0)