aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorArthur Cohen <arthur.cohen@embecosm.com>2023-04-18 16:22:22 +0200
committerArthur Cohen <arthur.cohen@embecosm.com>2024-01-16 18:37:14 +0100
commit12dd77c19fbcf2446a895804848ffb498e0d3688 (patch)
tree4dd11febfcf3f1b1210939b7b03a4f53c02eef73 /gcc
parentebbb3d2d5f74f4c00132df085fe7829abba4fe1c (diff)
downloadgcc-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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver.cc101
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver.h12
-rw-r--r--gcc/testsuite/rust/compile/macro_use1.rs15
-rw-r--r--gcc/testsuite/rust/compile/nested_macro_use1.rs19
-rw-r--r--gcc/testsuite/rust/compile/nested_macro_use2.rs12
-rw-r--r--gcc/testsuite/rust/execute/torture/macro_use1.rs18
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
+}