https://gcc.gnu.org/g:f88af6176e24e62670f33f3d119db02850c11af2

commit f88af6176e24e62670f33f3d119db02850c11af2
Author: Arthur Cohen <arthur.co...@embecosm.com>
Date:   Mon Feb 24 13:09:17 2025 +0100

    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.

Diff:
---
 gcc/rust/expand/rust-macro-expand.cc         | 10 +++---
 gcc/rust/expand/rust-macro-expand.h          |  3 +-
 gcc/rust/expand/rust-macro-substitute-ctx.cc | 51 ++++++++++++++++++++++++----
 gcc/rust/expand/rust-macro-substitute-ctx.h  | 25 ++++++++++++--
 gcc/rust/util/rust-hir-map.cc                | 14 ++++++--
 gcc/rust/util/rust-hir-map.h                 |  4 ++-
 gcc/testsuite/rust/compile/crate-metavar1.rs | 14 ++++++++
 gcc/testsuite/rust/execute/crate-metavar1.rs | 11 ++++++
 8 files changed, 115 insertions(+), 17 deletions(-)

diff --git a/gcc/rust/expand/rust-macro-expand.cc 
b/gcc/rust/expand/rust-macro-expand.cc
index 0b01ede7e9e0..78297570791b 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -23,6 +23,7 @@
 #include "rust-ast-full.h"
 #include "rust-ast-visitor.h"
 #include "rust-diagnostics.h"
+#include "rust-macro.h"
 #include "rust-parse.h"
 #include "rust-cfg-strip.h"
 #include "rust-early-name-resolver.h"
@@ -118,7 +119,7 @@ MacroExpander::expand_decl_macro (location_t invoc_locus,
   for (auto &ent : matched_fragments)
     matched_fragments_ptr.emplace (ent.first, ent.second.get ());
 
-  return transcribe_rule (*matched_rule, invoc_token_tree,
+  return transcribe_rule (rules_def, *matched_rule, invoc_token_tree,
                          matched_fragments_ptr, semicolon, peek_context ());
 }
 
@@ -1023,7 +1024,8 @@ tokens_to_str (std::vector<std::unique_ptr<AST::Token>> 
&tokens)
 
 AST::Fragment
 MacroExpander::transcribe_rule (
-  AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree,
+  AST::MacroRulesDefinition &definition, AST::MacroRule &match_rule,
+  AST::DelimTokenTree &invoc_token_tree,
   std::map<std::string, MatchedFragmentContainer *> &matched_fragments,
   AST::InvocKind invoc_kind, ContextType ctx)
 {
@@ -1037,8 +1039,8 @@ MacroExpander::transcribe_rule (
   auto invoc_stream = invoc_token_tree.to_token_stream ();
   auto macro_rule_tokens = transcribe_tree.to_token_stream ();
 
-  auto substitute_context
-    = SubstituteCtx (invoc_stream, macro_rule_tokens, matched_fragments);
+  auto substitute_context = SubstituteCtx (invoc_stream, macro_rule_tokens,
+                                          matched_fragments, definition);
   std::vector<std::unique_ptr<AST::Token>> substituted_tokens
     = substitute_context.substitute_tokens ();
 
diff --git a/gcc/rust/expand/rust-macro-expand.h 
b/gcc/rust/expand/rust-macro-expand.h
index c186f3d7c3c1..3948e441cbb2 100644
--- a/gcc/rust/expand/rust-macro-expand.h
+++ b/gcc/rust/expand/rust-macro-expand.h
@@ -331,7 +331,8 @@ struct MacroExpander
                       AST::DelimTokenTree &invoc_token_tree);
 
   AST::Fragment transcribe_rule (
-    AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree,
+    AST::MacroRulesDefinition &definition, AST::MacroRule &match_rule,
+    AST::DelimTokenTree &invoc_token_tree,
     std::map<std::string, MatchedFragmentContainer *> &matched_fragments,
     AST::InvocKind invoc_kind, ContextType ctx);
 
diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.cc 
b/gcc/rust/expand/rust-macro-substitute-ctx.cc
index 03709a1e9370..9eb2d920ebd6 100644
--- a/gcc/rust/expand/rust-macro-substitute-ctx.cc
+++ b/gcc/rust/expand/rust-macro-substitute-ctx.cc
@@ -17,9 +17,46 @@
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-macro-substitute-ctx.h"
+#include "input.h"
+#include "rust-hir-map.h"
+#include "rust-token.h"
 
 namespace Rust {
 
+bool
+SubstituteCtx::substitute_dollar_crate (
+  std::vector<std::unique_ptr<AST::Token>> &expanded)
+{
+  auto &mappings = Analysis::Mappings::get ();
+
+  auto def_crate = mappings.lookup_macro_def_crate (definition.get_node_id ());
+  auto current_crate = mappings.get_current_crate ();
+
+  rust_assert (def_crate);
+
+  // If we're expanding a macro defined in the current crate which uses $crate,
+  // we can just replace the metavar with the `crate` path segment. Otherwise,
+  // use the fully qualified extern-crate lookup path `::<crate_name>`
+  if (*def_crate == current_crate)
+    {
+      expanded.push_back (std::make_unique<AST::Token> (
+       Rust::Token::make_identifier (UNKNOWN_LOCATION, "crate")));
+    }
+  else
+    {
+      auto name = mappings.get_crate_name (*def_crate);
+
+      rust_assert (name);
+
+      expanded.push_back (std::make_unique<AST::Token> (
+       Rust::Token::make (SCOPE_RESOLUTION, UNKNOWN_LOCATION)));
+      expanded.push_back (std::make_unique<AST::Token> (
+       Rust::Token::make_identifier (UNKNOWN_LOCATION, std::string (*name))));
+    }
+
+  return true;
+}
+
 bool
 SubstituteCtx::substitute_metavar (
   std::unique_ptr<AST::Token> &metavar,
@@ -30,14 +67,15 @@ SubstituteCtx::substitute_metavar (
   auto it = fragments.find (metavar_name);
   if (it == fragments.end ())
     {
-      // fail to substitute
+      // fail to substitute, unless we are dealing with a special-case metavar
+      // like $crate
 
-      // HACK: substitute ($ crate) => (crate)
-      if (metavar->get_id () != CRATE)
-       return false;
+      if (metavar->get_id () == CRATE)
+       return substitute_dollar_crate (expanded);
 
       expanded.push_back (metavar->clone_token ());
-      return true;
+
+      return false;
     }
   else
     {
@@ -187,7 +225,8 @@ SubstituteCtx::substitute_repetition (
                             kv_match.second->get_fragments ().at (i).get ());
        }
 
-      auto substitute_context = SubstituteCtx (input, new_macro, sub_map);
+      auto substitute_context
+       = SubstituteCtx (input, new_macro, sub_map, definition);
       auto new_tokens = substitute_context.substitute_tokens ();
 
       // Skip the first repetition, but add the separator to the expanded
diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.h 
b/gcc/rust/expand/rust-macro-substitute-ctx.h
index 835f48a3d984..7e0175a02d47 100644
--- a/gcc/rust/expand/rust-macro-substitute-ctx.h
+++ b/gcc/rust/expand/rust-macro-substitute-ctx.h
@@ -18,6 +18,7 @@
 
 #include "rust-ast.h"
 #include "rust-macro-expand.h"
+#include "rust-macro.h"
 
 namespace Rust {
 class SubstituteCtx
@@ -25,6 +26,7 @@ class SubstituteCtx
   std::vector<std::unique_ptr<AST::Token>> &input;
   std::vector<std::unique_ptr<AST::Token>> &macro;
   std::map<std::string, MatchedFragmentContainer *> &fragments;
+  AST::MacroRulesDefinition &definition;
 
   /**
    * Find the repetition amount to use when expanding a repetition, and
@@ -40,10 +42,27 @@ class SubstituteCtx
 public:
   SubstituteCtx (std::vector<std::unique_ptr<AST::Token>> &input,
                 std::vector<std::unique_ptr<AST::Token>> &macro,
-                std::map<std::string, MatchedFragmentContainer *> &fragments)
-    : input (input), macro (macro), fragments (fragments)
+                std::map<std::string, MatchedFragmentContainer *> &fragments,
+                AST::MacroRulesDefinition &definition)
+    : input (input), macro (macro), fragments (fragments),
+      definition (definition)
   {}
 
+  /**
+   * Special-case the $crate metavar to expand to the name of the crate in 
which
+   * the macro was defined.
+   *
+   * 
https://doc.rust-lang.org/reference/macros-by-example.html#r-macro.decl.hygiene.crate
+   *
+   *
+   * @param expanded Reference to a vector upon which expanded tokens will be
+   * pushed
+   *
+   * @return True if the substitution succeeded
+   */
+  bool
+  substitute_dollar_crate (std::vector<std::unique_ptr<AST::Token>> &expanded);
+
   /**
    * Substitute a metavariable by its given fragment in a transcribing context,
    * i.e. replacing $var with the associated fragment.
@@ -52,7 +71,7 @@ public:
    * @param expanded Reference to a vector upon which expanded tokens will be
    * pushed
    *
-   * @return True iff the substitution succeeded
+   * @return True if the substitution succeeded
    */
   bool substitute_metavar (std::unique_ptr<AST::Token> &metavar,
                           std::vector<std::unique_ptr<AST::Token>> &expanded);
diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc
index 99839eb6701e..5483499b63ea 100644
--- a/gcc/rust/util/rust-hir-map.cc
+++ b/gcc/rust/util/rust-hir-map.cc
@@ -874,7 +874,7 @@ Mappings::insert_macro_def (AST::MacroRulesDefinition 
*macro)
   auto it = macroMappings.find (macro->get_node_id ());
   rust_assert (it == macroMappings.end ());
 
-  macroMappings[macro->get_node_id ()] = macro;
+  macroMappings[macro->get_node_id ()] = {macro, currentCrateNum};
 }
 
 tl::optional<AST::MacroRulesDefinition *>
@@ -884,7 +884,17 @@ Mappings::lookup_macro_def (NodeId id)
   if (it == macroMappings.end ())
     return tl::nullopt;
 
-  return it->second;
+  return it->second.first;
+}
+
+tl::optional<CrateNum>
+Mappings::lookup_macro_def_crate (NodeId id)
+{
+  auto it = macroMappings.find (id);
+  if (it == macroMappings.end ())
+    return tl::nullopt;
+
+  return it->second.second;
 }
 
 void
diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h
index 6f21f38b4491..9fcb3c673d7c 100644
--- a/gcc/rust/util/rust-hir-map.h
+++ b/gcc/rust/util/rust-hir-map.h
@@ -269,6 +269,7 @@ public:
   void insert_macro_def (AST::MacroRulesDefinition *macro);
 
   tl::optional<AST::MacroRulesDefinition *> lookup_macro_def (NodeId id);
+  tl::optional<CrateNum> lookup_macro_def_crate (NodeId id);
 
   void insert_macro_invocation (AST::MacroInvocation &invoc,
                                AST::MacroRulesDefinition *def);
@@ -402,7 +403,8 @@ private:
   std::map<CrateNum, std::set<HirId>> hirNodesWithinCrate;
 
   // MBE macros
-  std::map<NodeId, AST::MacroRulesDefinition *> macroMappings;
+  std::map<NodeId, std::pair<AST::MacroRulesDefinition *, CrateNum>>
+    macroMappings;
   std::map<NodeId, AST::MacroRulesDefinition *> macroInvocations;
   std::vector<NodeId> exportedMacros;
 
diff --git a/gcc/testsuite/rust/compile/crate-metavar1.rs 
b/gcc/testsuite/rust/compile/crate-metavar1.rs
new file mode 100644
index 000000000000..45384e1cfde6
--- /dev/null
+++ b/gcc/testsuite/rust/compile/crate-metavar1.rs
@@ -0,0 +1,14 @@
+macro_rules! foo {
+    () => {
+        $crate::inner::bar()
+    }
+}
+
+pub mod inner {
+    pub fn bar() { }
+}
+
+fn main() {
+    foo!();
+    crate::inner::bar();
+}
diff --git a/gcc/testsuite/rust/execute/crate-metavar1.rs 
b/gcc/testsuite/rust/execute/crate-metavar1.rs
new file mode 100644
index 000000000000..8418308afb7b
--- /dev/null
+++ b/gcc/testsuite/rust/execute/crate-metavar1.rs
@@ -0,0 +1,11 @@
+macro_rules! foo {
+    () => {
+        $crate::bar()
+    }
+}
+
+pub fn bar() -> i32 { 1 }
+
+fn main() -> i32 {
+    foo!() - crate::bar()
+}

Reply via email to