]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: enr: Accumulate nested escaped macros properly.
authorArthur Cohen <arthur.cohen@embecosm.com>
Tue, 18 Apr 2023 14:22:22 +0000 (16:22 +0200)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 16 Jan 2024 17:37:14 +0000 (18:37 +0100)
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.

gcc/rust/resolve/rust-early-name-resolver.cc
gcc/rust/resolve/rust-early-name-resolver.h
gcc/testsuite/rust/compile/macro_use1.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/nested_macro_use1.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/nested_macro_use2.rs [new file with mode: 0644]
gcc/testsuite/rust/execute/torture/macro_use1.rs [new file with mode: 0644]

index 145b39311882cc13949f3a740e166d4407cfed6b..f3e4b198f09fa281d500910732e48d1b895e3c0b 100644 (file)
 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);
index 07281378c5bb202200b5e378c676d1742c9f7b31..dfdab817d00c77cdc1e479b1ed18700070706b06 100644 (file)
@@ -53,6 +53,18 @@ private:
     current_scope = old_scope;
   }
 
+  /**
+   * 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.
    *
diff --git a/gcc/testsuite/rust/compile/macro_use1.rs b/gcc/testsuite/rust/compile/macro_use1.rs
new file mode 100644 (file)
index 0000000..e98eadf
--- /dev/null
@@ -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 (file)
index 0000000..8a2fd2a
--- /dev/null
@@ -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 (file)
index 0000000..4659500
--- /dev/null
@@ -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 (file)
index 0000000..fdf5530
--- /dev/null
@@ -0,0 +1,18 @@
+#[macro_use]
+mod foo {
+    macro_rules! a {
+        () => {
+            15
+        };
+    }
+
+    macro_rules! b {
+        () => {
+            14
+        };
+    }
+}
+
+fn main() -> i32 {
+    a!() + b!() - 29
+}