https://gcc.gnu.org/g:1181104e1ffd8c8e963b59d206d9168d470e68f6
commit r15-8837-g1181104e1ffd8c8e963b59d206d9168d470e68f6 Author: Arthur Cohen <arthur.co...@embecosm.com> Date: Mon Feb 24 13:09:17 2025 +0100 gccrs: 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 3822dc296c89..cd17a3f9ba12 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 5e127906bb76..360294c6bf9f 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 a06f831d7dd2..02e4e3b1c5ae 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 e3100a3a7d44..c5c4956bc8e8 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>> ¯o; 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>> ¯o, - 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 e58f1a2a715c..1a2a1bc97095 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 d654a1dfadce..44a8c0d52afe 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() +}