Skip to content

Commit f88af61

Browse files
committed
expansion: Correctly expand $crate metavar
gcc/rust/ChangeLog: * expand/rust-macro-expand.cc: Use new SubstituteCtx API. * expand/rust-macro-expand.h: Likewise. * expand/rust-macro-substitute-ctx.cc: Implement proper expansion of $crate. * expand/rust-macro-substitute-ctx.h: Adapt APIs to take macro definition when substituting. * util/rust-hir-map.cc (Mappings::insert_macro_def): Store crate information when inserting macro definition in mappings. (Mappings::lookup_macro_def_crate): New. * util/rust-hir-map.h: Adapt mappings to store crate in which macros were defined. gcc/testsuite/ChangeLog: * rust/execute/crate-metavar1.rs: New test. * rust/compile/crate-metavar1.rs: New test.
1 parent 912ebb6 commit f88af61

8 files changed

+115
-17
lines changed

gcc/rust/expand/rust-macro-expand.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "rust-ast-full.h"
2424
#include "rust-ast-visitor.h"
2525
#include "rust-diagnostics.h"
26+
#include "rust-macro.h"
2627
#include "rust-parse.h"
2728
#include "rust-cfg-strip.h"
2829
#include "rust-early-name-resolver.h"
@@ -118,7 +119,7 @@ MacroExpander::expand_decl_macro (location_t invoc_locus,
118119
for (auto &ent : matched_fragments)
119120
matched_fragments_ptr.emplace (ent.first, ent.second.get ());
120121

121-
return transcribe_rule (*matched_rule, invoc_token_tree,
122+
return transcribe_rule (rules_def, *matched_rule, invoc_token_tree,
122123
matched_fragments_ptr, semicolon, peek_context ());
123124
}
124125

@@ -1023,7 +1024,8 @@ tokens_to_str (std::vector<std::unique_ptr<AST::Token>> &tokens)
10231024

10241025
AST::Fragment
10251026
MacroExpander::transcribe_rule (
1026-
AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree,
1027+
AST::MacroRulesDefinition &definition, AST::MacroRule &match_rule,
1028+
AST::DelimTokenTree &invoc_token_tree,
10271029
std::map<std::string, MatchedFragmentContainer *> &matched_fragments,
10281030
AST::InvocKind invoc_kind, ContextType ctx)
10291031
{
@@ -1037,8 +1039,8 @@ MacroExpander::transcribe_rule (
10371039
auto invoc_stream = invoc_token_tree.to_token_stream ();
10381040
auto macro_rule_tokens = transcribe_tree.to_token_stream ();
10391041

1040-
auto substitute_context
1041-
= SubstituteCtx (invoc_stream, macro_rule_tokens, matched_fragments);
1042+
auto substitute_context = SubstituteCtx (invoc_stream, macro_rule_tokens,
1043+
matched_fragments, definition);
10421044
std::vector<std::unique_ptr<AST::Token>> substituted_tokens
10431045
= substitute_context.substitute_tokens ();
10441046

gcc/rust/expand/rust-macro-expand.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,8 @@ struct MacroExpander
331331
AST::DelimTokenTree &invoc_token_tree);
332332

333333
AST::Fragment transcribe_rule (
334-
AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree,
334+
AST::MacroRulesDefinition &definition, AST::MacroRule &match_rule,
335+
AST::DelimTokenTree &invoc_token_tree,
335336
std::map<std::string, MatchedFragmentContainer *> &matched_fragments,
336337
AST::InvocKind invoc_kind, ContextType ctx);
337338

gcc/rust/expand/rust-macro-substitute-ctx.cc

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,46 @@
1717
// <http://www.gnu.org/licenses/>.
1818

1919
#include "rust-macro-substitute-ctx.h"
20+
#include "input.h"
21+
#include "rust-hir-map.h"
22+
#include "rust-token.h"
2023

2124
namespace Rust {
2225

26+
bool
27+
SubstituteCtx::substitute_dollar_crate (
28+
std::vector<std::unique_ptr<AST::Token>> &expanded)
29+
{
30+
auto &mappings = Analysis::Mappings::get ();
31+
32+
auto def_crate = mappings.lookup_macro_def_crate (definition.get_node_id ());
33+
auto current_crate = mappings.get_current_crate ();
34+
35+
rust_assert (def_crate);
36+
37+
// If we're expanding a macro defined in the current crate which uses $crate,
38+
// we can just replace the metavar with the `crate` path segment. Otherwise,
39+
// use the fully qualified extern-crate lookup path `::<crate_name>`
40+
if (*def_crate == current_crate)
41+
{
42+
expanded.push_back (std::make_unique<AST::Token> (
43+
Rust::Token::make_identifier (UNKNOWN_LOCATION, "crate")));
44+
}
45+
else
46+
{
47+
auto name = mappings.get_crate_name (*def_crate);
48+
49+
rust_assert (name);
50+
51+
expanded.push_back (std::make_unique<AST::Token> (
52+
Rust::Token::make (SCOPE_RESOLUTION, UNKNOWN_LOCATION)));
53+
expanded.push_back (std::make_unique<AST::Token> (
54+
Rust::Token::make_identifier (UNKNOWN_LOCATION, std::string (*name))));
55+
}
56+
57+
return true;
58+
}
59+
2360
bool
2461
SubstituteCtx::substitute_metavar (
2562
std::unique_ptr<AST::Token> &metavar,
@@ -30,14 +67,15 @@ SubstituteCtx::substitute_metavar (
3067
auto it = fragments.find (metavar_name);
3168
if (it == fragments.end ())
3269
{
33-
// fail to substitute
70+
// fail to substitute, unless we are dealing with a special-case metavar
71+
// like $crate
3472

35-
// HACK: substitute ($ crate) => (crate)
36-
if (metavar->get_id () != CRATE)
37-
return false;
73+
if (metavar->get_id () == CRATE)
74+
return substitute_dollar_crate (expanded);
3875

3976
expanded.push_back (metavar->clone_token ());
40-
return true;
77+
78+
return false;
4179
}
4280
else
4381
{
@@ -187,7 +225,8 @@ SubstituteCtx::substitute_repetition (
187225
kv_match.second->get_fragments ().at (i).get ());
188226
}
189227

190-
auto substitute_context = SubstituteCtx (input, new_macro, sub_map);
228+
auto substitute_context
229+
= SubstituteCtx (input, new_macro, sub_map, definition);
191230
auto new_tokens = substitute_context.substitute_tokens ();
192231

193232
// Skip the first repetition, but add the separator to the expanded

gcc/rust/expand/rust-macro-substitute-ctx.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818

1919
#include "rust-ast.h"
2020
#include "rust-macro-expand.h"
21+
#include "rust-macro.h"
2122

2223
namespace Rust {
2324
class SubstituteCtx
2425
{
2526
std::vector<std::unique_ptr<AST::Token>> &input;
2627
std::vector<std::unique_ptr<AST::Token>> &macro;
2728
std::map<std::string, MatchedFragmentContainer *> &fragments;
29+
AST::MacroRulesDefinition &definition;
2830

2931
/**
3032
* Find the repetition amount to use when expanding a repetition, and
@@ -40,10 +42,27 @@ class SubstituteCtx
4042
public:
4143
SubstituteCtx (std::vector<std::unique_ptr<AST::Token>> &input,
4244
std::vector<std::unique_ptr<AST::Token>> &macro,
43-
std::map<std::string, MatchedFragmentContainer *> &fragments)
44-
: input (input), macro (macro), fragments (fragments)
45+
std::map<std::string, MatchedFragmentContainer *> &fragments,
46+
AST::MacroRulesDefinition &definition)
47+
: input (input), macro (macro), fragments (fragments),
48+
definition (definition)
4549
{}
4650

51+
/**
52+
* Special-case the $crate metavar to expand to the name of the crate in which
53+
* the macro was defined.
54+
*
55+
* https://doc.rust-lang.org/reference/macros-by-example.html#r-macro.decl.hygiene.crate
56+
*
57+
*
58+
* @param expanded Reference to a vector upon which expanded tokens will be
59+
* pushed
60+
*
61+
* @return True if the substitution succeeded
62+
*/
63+
bool
64+
substitute_dollar_crate (std::vector<std::unique_ptr<AST::Token>> &expanded);
65+
4766
/**
4867
* Substitute a metavariable by its given fragment in a transcribing context,
4968
* i.e. replacing $var with the associated fragment.
@@ -52,7 +71,7 @@ class SubstituteCtx
5271
* @param expanded Reference to a vector upon which expanded tokens will be
5372
* pushed
5473
*
55-
* @return True iff the substitution succeeded
74+
* @return True if the substitution succeeded
5675
*/
5776
bool substitute_metavar (std::unique_ptr<AST::Token> &metavar,
5877
std::vector<std::unique_ptr<AST::Token>> &expanded);

gcc/rust/util/rust-hir-map.cc

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -874,7 +874,7 @@ Mappings::insert_macro_def (AST::MacroRulesDefinition *macro)
874874
auto it = macroMappings.find (macro->get_node_id ());
875875
rust_assert (it == macroMappings.end ());
876876

877-
macroMappings[macro->get_node_id ()] = macro;
877+
macroMappings[macro->get_node_id ()] = {macro, currentCrateNum};
878878
}
879879

880880
tl::optional<AST::MacroRulesDefinition *>
@@ -884,7 +884,17 @@ Mappings::lookup_macro_def (NodeId id)
884884
if (it == macroMappings.end ())
885885
return tl::nullopt;
886886

887-
return it->second;
887+
return it->second.first;
888+
}
889+
890+
tl::optional<CrateNum>
891+
Mappings::lookup_macro_def_crate (NodeId id)
892+
{
893+
auto it = macroMappings.find (id);
894+
if (it == macroMappings.end ())
895+
return tl::nullopt;
896+
897+
return it->second.second;
888898
}
889899

890900
void

gcc/rust/util/rust-hir-map.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ class Mappings
269269
void insert_macro_def (AST::MacroRulesDefinition *macro);
270270

271271
tl::optional<AST::MacroRulesDefinition *> lookup_macro_def (NodeId id);
272+
tl::optional<CrateNum> lookup_macro_def_crate (NodeId id);
272273

273274
void insert_macro_invocation (AST::MacroInvocation &invoc,
274275
AST::MacroRulesDefinition *def);
@@ -402,7 +403,8 @@ class Mappings
402403
std::map<CrateNum, std::set<HirId>> hirNodesWithinCrate;
403404

404405
// MBE macros
405-
std::map<NodeId, AST::MacroRulesDefinition *> macroMappings;
406+
std::map<NodeId, std::pair<AST::MacroRulesDefinition *, CrateNum>>
407+
macroMappings;
406408
std::map<NodeId, AST::MacroRulesDefinition *> macroInvocations;
407409
std::vector<NodeId> exportedMacros;
408410

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
macro_rules! foo {
2+
() => {
3+
$crate::inner::bar()
4+
}
5+
}
6+
7+
pub mod inner {
8+
pub fn bar() { }
9+
}
10+
11+
fn main() {
12+
foo!();
13+
crate::inner::bar();
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
macro_rules! foo {
2+
() => {
3+
$crate::bar()
4+
}
5+
}
6+
7+
pub fn bar() -> i32 { 1 }
8+
9+
fn main() -> i32 {
10+
foo!() - crate::bar()
11+
}

0 commit comments

Comments
 (0)