Skip to content

Commit b60f245

Browse files
authored
Rollup merge of #63667 - petrochenkov:deriveholders, r=matthewjasper
resolve: Properly integrate derives and `macro_rules` scopes So, ```rust #[derive(A, B)] struct S; m!(); ``` turns into something like ```rust struct S; A_placeholder!( struct S; ); B_placeholder!( struct S; ); m!(); ``` during expansion. And for `m!()` its "`macro_rules` scope" (aka "legacy scope") should point to the `B_placeholder` call rather than to the derive container `#[derive(A, B)]`. `fn build_reduced_graph` now makes sure the legacy scope points to the right thing. (It's still a mystery for me why this worked before #63535.) Unfortunately, placeholders from derives are currently treated separately from placeholders from other macros and need to be passed as `extra_placeholders` rather than a part of the AST fragment. That's fixable, but I wanted to keep this PR more minimal to close the regression faster. Fixes #63651 r? @matthewjasper
2 parents a00b4f1 + 1064d41 commit b60f245

File tree

10 files changed

+82
-47
lines changed

10 files changed

+82
-47
lines changed

src/librustc/hir/map/def_collector.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl<'a> DefCollector<'a> {
7474
})
7575
}
7676

77-
fn visit_macro_invoc(&mut self, id: NodeId) {
77+
pub fn visit_macro_invoc(&mut self, id: NodeId) {
7878
self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
7979
}
8080
}

src/librustc_resolve/build_reduced_graph.rs

+18-5
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,25 @@ impl<'a> Resolver<'a> {
160160
Some(ext)
161161
}
162162

163+
// FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
163164
crate fn build_reduced_graph(
164-
&mut self, fragment: &AstFragment, parent_scope: ParentScope<'a>
165+
&mut self,
166+
fragment: &AstFragment,
167+
extra_placeholders: &[NodeId],
168+
parent_scope: ParentScope<'a>,
165169
) -> LegacyScope<'a> {
166-
fragment.visit_with(&mut DefCollector::new(&mut self.definitions, parent_scope.expansion));
170+
let mut def_collector = DefCollector::new(&mut self.definitions, parent_scope.expansion);
171+
fragment.visit_with(&mut def_collector);
172+
for placeholder in extra_placeholders {
173+
def_collector.visit_macro_invoc(*placeholder);
174+
}
175+
167176
let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope };
168177
fragment.visit_with(&mut visitor);
178+
for placeholder in extra_placeholders {
179+
visitor.parent_scope.legacy = visitor.visit_invoc(*placeholder);
180+
}
181+
169182
visitor.parent_scope.legacy
170183
}
171184

@@ -871,7 +884,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
871884
}
872885

873886
/// Builds the reduced graph for a single item in an external crate.
874-
fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<ast::NodeId>) {
887+
fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<NodeId>) {
875888
let parent = self.parent_scope.module;
876889
let Export { ident, res, vis, span } = child;
877890
// FIXME: We shouldn't create the gensym here, it should come from metadata,
@@ -1060,10 +1073,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
10601073
false
10611074
}
10621075

1063-
fn visit_invoc(&mut self, id: ast::NodeId) -> LegacyScope<'a> {
1076+
fn visit_invoc(&mut self, id: NodeId) -> LegacyScope<'a> {
10641077
let invoc_id = id.placeholder_to_expn_id();
10651078

1066-
self.parent_scope.module.unresolved_invocations.borrow_mut().insert(invoc_id);
1079+
self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id);
10671080

10681081
let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope);
10691082
assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation");

src/librustc_resolve/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ pub struct ModuleData<'a> {
448448
populate_on_access: Cell<bool>,
449449

450450
// Macro invocations that can expand into items in this module.
451-
unresolved_invocations: RefCell<FxHashSet<ExpnId>>,
451+
unexpanded_invocations: RefCell<FxHashSet<ExpnId>>,
452452

453453
no_implicit_prelude: bool,
454454

@@ -478,7 +478,7 @@ impl<'a> ModuleData<'a> {
478478
normal_ancestor_id,
479479
lazy_resolutions: Default::default(),
480480
populate_on_access: Cell::new(!normal_ancestor_id.is_local()),
481-
unresolved_invocations: Default::default(),
481+
unexpanded_invocations: Default::default(),
482482
no_implicit_prelude: false,
483483
glob_importers: RefCell::new(Vec::new()),
484484
globs: RefCell::new(Vec::new()),

src/librustc_resolve/macros.rs

+13-18
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::resolve_imports::ImportResolver;
1010
use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
1111
use rustc::middle::stability;
1212
use rustc::{ty, lint, span_bug};
13-
use syntax::ast::{self, Ident};
13+
use syntax::ast::{self, NodeId, Ident};
1414
use syntax::attr::StabilityLevel;
1515
use syntax::edition::Edition;
1616
use syntax::ext::base::{self, Indeterminate, SpecialDerives};
@@ -26,7 +26,7 @@ use syntax_pos::{Span, DUMMY_SP};
2626
use std::{mem, ptr};
2727
use rustc_data_structures::sync::Lrc;
2828

29-
type Res = def::Res<ast::NodeId>;
29+
type Res = def::Res<NodeId>;
3030

3131
/// Binding produced by a `macro_rules` item.
3232
/// Not modularized, can shadow previous legacy bindings, etc.
@@ -91,11 +91,11 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
9191
}
9292

9393
impl<'a> base::Resolver for Resolver<'a> {
94-
fn next_node_id(&mut self) -> ast::NodeId {
94+
fn next_node_id(&mut self) -> NodeId {
9595
self.session.next_node_id()
9696
}
9797

98-
fn get_module_scope(&mut self, id: ast::NodeId) -> ExpnId {
98+
fn get_module_scope(&mut self, id: NodeId) -> ExpnId {
9999
let expn_id = ExpnId::fresh(Some(ExpnData::default(
100100
ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, self.session.edition()
101101
)));
@@ -115,23 +115,18 @@ impl<'a> base::Resolver for Resolver<'a> {
115115
});
116116
}
117117

118+
// FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
118119
fn visit_ast_fragment_with_placeholders(
119-
&mut self, expansion: ExpnId, fragment: &AstFragment, derives: &[ExpnId]
120+
&mut self, expansion: ExpnId, fragment: &AstFragment, extra_placeholders: &[NodeId]
120121
) {
121-
// Fill in some data for derives if the fragment is from a derive container.
122+
// Integrate the new AST fragment into all the definition and module structures.
122123
// We are inside the `expansion` now, but other parent scope components are still the same.
123124
let parent_scope = ParentScope { expansion, ..self.invocation_parent_scopes[&expansion] };
124-
let parent_def = self.definitions.invocation_parent(expansion);
125-
self.invocation_parent_scopes.extend(derives.iter().map(|&derive| (derive, parent_scope)));
126-
for &derive_invoc_id in derives {
127-
self.definitions.set_invocation_parent(derive_invoc_id, parent_def);
128-
}
129-
parent_scope.module.unresolved_invocations.borrow_mut().remove(&expansion);
130-
parent_scope.module.unresolved_invocations.borrow_mut().extend(derives);
131-
132-
// Integrate the new AST fragment into all the definition and module structures.
133-
let output_legacy_scope = self.build_reduced_graph(fragment, parent_scope);
125+
let output_legacy_scope =
126+
self.build_reduced_graph(fragment, extra_placeholders, parent_scope);
134127
self.output_legacy_scopes.insert(expansion, output_legacy_scope);
128+
129+
parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
135130
}
136131

137132
fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension) {
@@ -485,7 +480,7 @@ impl<'a> Resolver<'a> {
485480
Scope::MacroUsePrelude => match this.macro_use_prelude.get(&ident.name).cloned() {
486481
Some(binding) => Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
487482
None => Err(Determinacy::determined(
488-
this.graph_root.unresolved_invocations.borrow().is_empty()
483+
this.graph_root.unexpanded_invocations.borrow().is_empty()
489484
))
490485
}
491486
Scope::BuiltinAttrs => if is_builtin_attr_name(ident.name) {
@@ -508,7 +503,7 @@ impl<'a> Resolver<'a> {
508503
Scope::ExternPrelude => match this.extern_prelude_get(ident, !record_used) {
509504
Some(binding) => Ok((binding, Flags::PRELUDE)),
510505
None => Err(Determinacy::determined(
511-
this.graph_root.unresolved_invocations.borrow().is_empty()
506+
this.graph_root.unexpanded_invocations.borrow().is_empty()
512507
)),
513508
}
514509
Scope::ToolPrelude => if KNOWN_TOOLS.contains(&ident.name) {

src/librustc_resolve/resolve_imports.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ impl<'a> Resolver<'a> {
202202
Err((Determined, Weak::No))
203203
} else if let Some(binding) = self.extern_prelude_get(ident, !record_used) {
204204
Ok(binding)
205-
} else if !self.graph_root.unresolved_invocations.borrow().is_empty() {
205+
} else if !self.graph_root.unexpanded_invocations.borrow().is_empty() {
206206
// Macro-expanded `extern crate` items can add names to extern prelude.
207207
Err((Undetermined, Weak::No))
208208
} else {
@@ -348,7 +348,7 @@ impl<'a> Resolver<'a> {
348348
// progress, we have to ignore those potential unresolved invocations from other modules
349349
// and prohibit access to macro-expanded `macro_export` macros instead (unless restricted
350350
// shadowing is enabled, see `macro_expanded_macro_export_errors`).
351-
let unexpanded_macros = !module.unresolved_invocations.borrow().is_empty();
351+
let unexpanded_macros = !module.unexpanded_invocations.borrow().is_empty();
352352
if let Some(binding) = resolution.binding {
353353
if !unexpanded_macros || ns == MacroNS || restricted_shadowing {
354354
return check_usable(self, binding);

src/libsyntax/ext/base.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::ast::{self, Attribute, Name, PatKind};
1+
use crate::ast::{self, NodeId, Attribute, Name, PatKind};
22
use crate::attr::{HasAttrs, Stability, Deprecation};
33
use crate::source_map::SourceMap;
44
use crate::edition::Edition;
@@ -671,13 +671,13 @@ bitflags::bitflags! {
671671
}
672672

673673
pub trait Resolver {
674-
fn next_node_id(&mut self) -> ast::NodeId;
674+
fn next_node_id(&mut self) -> NodeId;
675675

676-
fn get_module_scope(&mut self, id: ast::NodeId) -> ExpnId;
676+
fn get_module_scope(&mut self, id: NodeId) -> ExpnId;
677677

678678
fn resolve_dollar_crates(&mut self);
679679
fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment,
680-
derives: &[ExpnId]);
680+
extra_placeholders: &[NodeId]);
681681
fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension);
682682

683683
fn resolve_imports(&mut self);

src/libsyntax/ext/expand.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
291291
// Unresolved macros produce dummy outputs as a recovery measure.
292292
invocations.reverse();
293293
let mut expanded_fragments = Vec::new();
294-
let mut derives: FxHashMap<ExpnId, Vec<_>> = FxHashMap::default();
294+
let mut all_derive_placeholders: FxHashMap<ExpnId, Vec<_>> = FxHashMap::default();
295295
let mut undetermined_invocations = Vec::new();
296296
let (mut progress, mut force) = (false, !self.monotonic);
297297
loop {
@@ -347,13 +347,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
347347

348348
let mut item = self.fully_configure(item);
349349
item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive));
350-
let derives = derives.entry(invoc.expansion_data.id).or_default();
350+
let derive_placeholders =
351+
all_derive_placeholders.entry(invoc.expansion_data.id).or_default();
351352

352-
derives.reserve(traits.len());
353+
derive_placeholders.reserve(traits.len());
353354
invocations.reserve(traits.len());
354355
for path in traits {
355356
let expn_id = ExpnId::fresh(None);
356-
derives.push(expn_id);
357+
derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id));
357358
invocations.push(Invocation {
358359
kind: InvocationKind::Derive { path, item: item.clone() },
359360
fragment_kind: invoc.fragment_kind,
@@ -365,7 +366,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
365366
}
366367
let fragment = invoc.fragment_kind
367368
.expect_from_annotatables(::std::iter::once(item));
368-
self.collect_invocations(fragment, derives)
369+
self.collect_invocations(fragment, derive_placeholders)
369370
} else {
370371
unreachable!()
371372
};
@@ -384,10 +385,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
384385
// Finally incorporate all the expanded macros into the input AST fragment.
385386
let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
386387
while let Some(expanded_fragments) = expanded_fragments.pop() {
387-
for (mark, expanded_fragment) in expanded_fragments.into_iter().rev() {
388-
let derives = derives.remove(&mark).unwrap_or_else(Vec::new);
389-
placeholder_expander.add(NodeId::placeholder_from_expn_id(mark),
390-
expanded_fragment, derives);
388+
for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() {
389+
let derive_placeholders =
390+
all_derive_placeholders.remove(&expn_id).unwrap_or_else(Vec::new);
391+
placeholder_expander.add(NodeId::placeholder_from_expn_id(expn_id),
392+
expanded_fragment, derive_placeholders);
391393
}
392394
}
393395
fragment_with_placeholders.mut_visit_with(&mut placeholder_expander);
@@ -404,7 +406,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
404406
/// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s.
405407
/// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and
406408
/// prepares data for resolving paths of macro invocations.
407-
fn collect_invocations(&mut self, mut fragment: AstFragment, derives: &[ExpnId])
409+
fn collect_invocations(&mut self, mut fragment: AstFragment, extra_placeholders: &[NodeId])
408410
-> (AstFragment, Vec<Invocation>) {
409411
// Resolve `$crate`s in the fragment for pretty-printing.
410412
self.cx.resolver.resolve_dollar_crates();
@@ -423,9 +425,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
423425
collector.invocations
424426
};
425427

428+
// FIXME: Merge `extra_placeholders` into the `fragment` as regular placeholders.
426429
if self.monotonic {
427430
self.cx.resolver.visit_ast_fragment_with_placeholders(
428-
self.cx.current_expansion.id, &fragment, derives);
431+
self.cx.current_expansion.id, &fragment, extra_placeholders);
429432
}
430433

431434
(fragment, invocations)

src/libsyntax/ext/placeholders.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::ast::{self, NodeId};
22
use crate::source_map::{DUMMY_SP, dummy_spanned};
33
use crate::ext::base::ExtCtxt;
44
use crate::ext::expand::{AstFragment, AstFragmentKind};
5-
use crate::ext::hygiene::ExpnId;
65
use crate::tokenstream::TokenStream;
76
use crate::mut_visit::*;
87
use crate::ptr::P;
@@ -86,11 +85,11 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
8685
}
8786
}
8887

89-
pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, derives: Vec<ExpnId>) {
88+
pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, placeholders: Vec<NodeId>) {
9089
fragment.mut_visit_with(self);
9190
if let AstFragment::Items(mut items) = fragment {
92-
for derive in derives {
93-
match self.remove(NodeId::placeholder_from_expn_id(derive)) {
91+
for placeholder in placeholders {
92+
match self.remove(placeholder) {
9493
AstFragment::Items(derived_items) => items.extend(derived_items),
9594
_ => unreachable!(),
9695
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// force-host
2+
// no-prefer-dynamic
3+
4+
#![crate_type = "proc-macro"]
5+
6+
extern crate proc_macro;
7+
use proc_macro::TokenStream;
8+
9+
#[proc_macro_derive(repro)]
10+
pub fn proc_macro_hack_expr(_input: TokenStream) -> TokenStream {
11+
"macro_rules! m {()=>{}}".parse().unwrap()
12+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Derive macros can generate `macro_rules` items, regression test for issue #63651.
2+
3+
// check-pass
4+
// aux-build:gen-macro-rules.rs
5+
6+
extern crate gen_macro_rules as repro;
7+
8+
#[derive(repro::repro)]
9+
pub struct S;
10+
11+
m!(); // OK
12+
13+
fn main() {}

0 commit comments

Comments
 (0)