diff options
author | Arthur Cohen <arthur.cohen@embecosm.com> | 2023-04-18 16:22:22 +0200 |
---|---|---|
committer | Arthur Cohen <arthur.cohen@embecosm.com> | 2024-01-16 18:37:14 +0100 |
commit | 12dd77c19fbcf2446a895804848ffb498e0d3688 (patch) | |
tree | 4dd11febfcf3f1b1210939b7b03a4f53c02eef73 | |
parent | ebbb3d2d5f74f4c00132df085fe7829abba4fe1c (diff) | |
download | gcc-12dd77c19fbcf2446a895804848ffb498e0d3688.zip gcc-12dd77c19fbcf2446a895804848ffb498e0d3688.tar.gz gcc-12dd77c19fbcf2446a895804848ffb498e0d3688.tar.bz2 |
gccrs: enr: Accumulate nested escaped macros properly.
gcc/rust/ChangeLog:
* resolve/rust-early-name-resolver.cc (is_macro_use_module): New function.
(EarlyNameResolver::accumulate_escaped_macros): New function.
(EarlyNameResolver::go): Use `accumulate_escaped_macros`.
(EarlyNameResolver::visit): Likewise.
* resolve/rust-early-name-resolver.h: Declare `accumulate_escaped_macros`.
gcc/testsuite/ChangeLog:
* rust/compile/macro_use1.rs: New test.
* rust/execute/torture/macro_use1.rs: New test.
* rust/compile/nested_macro_use1.rs: New test.
* rust/compile/nested_macro_use2.rs: New test.
-rw-r--r-- | gcc/rust/resolve/rust-early-name-resolver.cc | 101 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-early-name-resolver.h | 12 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/macro_use1.rs | 15 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/nested_macro_use1.rs | 19 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/nested_macro_use2.rs | 12 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/macro_use1.rs | 18 |
6 files changed, 174 insertions, 3 deletions
diff --git a/gcc/rust/resolve/rust-early-name-resolver.cc b/gcc/rust/resolve/rust-early-name-resolver.cc index 145b393..f3e4b19 100644 --- a/gcc/rust/resolve/rust-early-name-resolver.cc +++ b/gcc/rust/resolve/rust-early-name-resolver.cc @@ -24,6 +24,55 @@ namespace Rust { namespace Resolver { +// Check if a module contains the `#[macro_use]` attribute +static bool +is_macro_use_module (const AST::Module &mod) +{ + for (const auto &attr : mod.get_outer_attrs ()) + if (attr.get_path ().as_string () == "macro_use") + return true; + + return false; +} + +std::vector<std::unique_ptr<AST::Item>> +EarlyNameResolver::accumulate_escaped_macros (AST::Module &module) +{ + if (!is_macro_use_module (module)) + return {}; + + // Parse the module's items if they haven't been expanded and the file + // should be parsed (i.e isn't hidden behind an untrue or impossible cfg + // directive) + if (module.get_kind () == AST::Module::UNLOADED) + module.load_items (); + + std::vector<std::unique_ptr<AST::Item>> escaped_macros; + + scoped (module.get_node_id (), [&module, &escaped_macros, this] { + for (auto &item : module.get_items ()) + { + if (item->get_ast_kind () == AST::Kind::MODULE) + { + auto &module = *static_cast<AST::Module *> (item.get ()); + auto new_macros = accumulate_escaped_macros (module); + + std::move (new_macros.begin (), new_macros.end (), + std::back_inserter (escaped_macros)); + + continue; + } + + item->accept_vis (*this); + + if (item->get_ast_kind () == AST::Kind::MACRO_RULES_DEFINITION) + escaped_macros.emplace_back (item->clone_item ()); + } + }); + + return escaped_macros; +} + EarlyNameResolver::EarlyNameResolver () : current_scope (UNKNOWN_NODEID), resolver (*Resolver::get ()), mappings (*Analysis::Mappings::get ()) @@ -32,6 +81,29 @@ EarlyNameResolver::EarlyNameResolver () void EarlyNameResolver::go (AST::Crate &crate) { + std::vector<std::unique_ptr<AST::Item>> new_items; + auto items = crate.take_items (); + + scoped (crate.get_node_id (), [&items, &new_items, this] { + for (auto &&item : items) + { + if (item->get_ast_kind () == AST::Kind::MODULE) + { + auto macros = accumulate_escaped_macros ( + *static_cast<AST::Module *> (item.get ())); + new_items.emplace_back (std::move (item)); + std::move (macros.begin (), macros.end (), + std::back_inserter (new_items)); + } + else + { + new_items.emplace_back (std::move (item)); + } + } + }); + + crate.set_items (std::move (new_items)); + scoped (crate.get_node_id (), [&crate, this] () { for (auto &item : crate.items) item->accept_vis (*this); @@ -550,12 +622,35 @@ EarlyNameResolver::visit (AST::Method &method) void EarlyNameResolver::visit (AST::Module &module) { - // Parse the module's items if they haven't been expanded and the file - // should be parsed (i.e isn't hidden behind an untrue or impossible cfg - // directive) if (module.get_kind () == AST::Module::UNLOADED) module.load_items (); + // so we need to only go "one scope down" for fetching macros. Macros within + // functions are still scoped only within that function. But we have to be + // careful because nested modules with #[macro_use] actually works! + std::vector<std::unique_ptr<AST::Item>> new_items; + auto items = module.take_items (); + + scoped (module.get_node_id (), [&items, &new_items, this] { + for (auto &&item : items) + { + if (item->get_ast_kind () == AST::Kind::MODULE) + { + auto macros = accumulate_escaped_macros ( + *static_cast<AST::Module *> (item.get ())); + new_items.emplace_back (std::move (item)); + std::move (macros.begin (), macros.end (), + std::back_inserter (new_items)); + } + else + { + new_items.emplace_back (std::move (item)); + } + } + }); + + module.set_items (std::move (new_items)); + scoped (module.get_node_id (), [&module, this] () { for (auto &item : module.get_items ()) item->accept_vis (*this); diff --git a/gcc/rust/resolve/rust-early-name-resolver.h b/gcc/rust/resolve/rust-early-name-resolver.h index 0728137..dfdab81 100644 --- a/gcc/rust/resolve/rust-early-name-resolver.h +++ b/gcc/rust/resolve/rust-early-name-resolver.h @@ -54,6 +54,18 @@ private: } /** + * Accumulate all of the nested macros which escape their module through the + * use of the #[macro_use] attribute. + * + * This function recursively accumulates macros in all of the nested modules + * of an item container (an AST::Crate or an AST::Module) and returns this new + * list of items. You can then use the `take_items` and `set_items` functions + * on these containers to replace their list of items. + */ + std::vector<std::unique_ptr<AST::Item>> + accumulate_escaped_macros (AST::Module &module); + + /** * The "scope" we are currently in. * * This involves lexical scopes: diff --git a/gcc/testsuite/rust/compile/macro_use1.rs b/gcc/testsuite/rust/compile/macro_use1.rs new file mode 100644 index 0000000..e98eadf --- /dev/null +++ b/gcc/testsuite/rust/compile/macro_use1.rs @@ -0,0 +1,15 @@ +#[macro_use] +mod foo { + macro_rules! a { + () => {}; + } + + macro_rules! b { + () => {}; + } +} + +fn main() { + a!(); + b!(); +} diff --git a/gcc/testsuite/rust/compile/nested_macro_use1.rs b/gcc/testsuite/rust/compile/nested_macro_use1.rs new file mode 100644 index 0000000..8a2fd2a --- /dev/null +++ b/gcc/testsuite/rust/compile/nested_macro_use1.rs @@ -0,0 +1,19 @@ +#[macro_use] +mod foo { + #[macro_use] + mod zim { + #[macro_use] + mod zoom { + #[macro_use] + mod zum { + macro_rules! qux { + () => {}; + } + } + } + } +} + +fn main() { + qux!(); // OK +} diff --git a/gcc/testsuite/rust/compile/nested_macro_use2.rs b/gcc/testsuite/rust/compile/nested_macro_use2.rs new file mode 100644 index 0000000..4659500 --- /dev/null +++ b/gcc/testsuite/rust/compile/nested_macro_use2.rs @@ -0,0 +1,12 @@ +#[macro_use] +mod foo { + fn bar() { + macro_rules! baz { + () => {{}}; + } + } +} + +fn main() { + baz!(); // { dg-error "unknown macro: .baz." } +} diff --git a/gcc/testsuite/rust/execute/torture/macro_use1.rs b/gcc/testsuite/rust/execute/torture/macro_use1.rs new file mode 100644 index 0000000..fdf5530 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macro_use1.rs @@ -0,0 +1,18 @@ +#[macro_use] +mod foo { + macro_rules! a { + () => { + 15 + }; + } + + macro_rules! b { + () => { + 14 + }; + } +} + +fn main() -> i32 { + a!() + b!() - 29 +} |