[COMMITTED 3/9] gccrs: Fix rebinding imports

arthur.cohen@embecosm.com arthur.cohen@embecosm.com
Wed Feb 21 13:15:21 GMT 2024


From: Owen Avery <powerboat9.gamer@gmail.com>

gcc/rust/ChangeLog:

	* resolve/rust-ast-resolve-item.cc
	(flatten_glob): Use Import class.
	(flatten_rebind): Likewise.
	(flatten_list): Likewise.
	(flatten): Likewise.
	(flatten_use_dec_to_paths): Likewise.
	(flatten_use_dec_to_imports): Likewise.
	(ResolveItem::visit): Likewise.
	(Import::add_prefix): New.
	(rust_flatten_nested_glob): Adjust test.
	(rust_flatten_glob): Likewise.
	(rust_flatten_rebind_none): Likewise.
	(rust_flatten_rebind): Likewise.
	(rust_flatten_rebind_nested): Likewise.
	(rust_flatten_list): Likewise.
	* resolve/rust-ast-resolve-item.h
	(class Import): New.

gcc/testsuite/ChangeLog:

	* rust/compile/use_2.rs: New test.

Signed-off-by: Owen Avery <powerboat9.gamer@gmail.com>
---
 gcc/rust/resolve/rust-ast-resolve-item.cc | 179 +++++++++++-----------
 gcc/rust/resolve/rust-ast-resolve-item.h  |  23 +++
 gcc/testsuite/rust/compile/use_2.rs       |   7 +
 3 files changed, 116 insertions(+), 93 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/use_2.rs

diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc
index e69b945407c..743657bc421 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-item.cc
@@ -824,33 +824,30 @@ ResolveItem::resolve_extern_item (AST::ExternalItem *item)
 }
 
 static void
-flatten_glob (const AST::UseTreeGlob &glob,
-	      std::vector<AST::SimplePath> &paths);
+flatten_glob (const AST::UseTreeGlob &glob, std::vector<Import> &imports);
 static void
-flatten_rebind (const AST::UseTreeRebind &glob,
-		std::vector<AST::SimplePath> &paths);
+flatten_rebind (const AST::UseTreeRebind &glob, std::vector<Import> &imports);
 static void
-flatten_list (const AST::UseTreeList &glob,
-	      std::vector<AST::SimplePath> &paths);
+flatten_list (const AST::UseTreeList &glob, std::vector<Import> &imports);
 
 static void
-flatten (const AST::UseTree *tree, std::vector<AST::SimplePath> &paths)
+flatten (const AST::UseTree *tree, std::vector<Import> &imports)
 {
   switch (tree->get_kind ())
     {
       case AST::UseTree::Glob: {
 	auto glob = static_cast<const AST::UseTreeGlob *> (tree);
-	flatten_glob (*glob, paths);
+	flatten_glob (*glob, imports);
 	break;
       }
       case AST::UseTree::Rebind: {
 	auto rebind = static_cast<const AST::UseTreeRebind *> (tree);
-	flatten_rebind (*rebind, paths);
+	flatten_rebind (*rebind, imports);
 	break;
       }
       case AST::UseTree::List: {
 	auto list = static_cast<const AST::UseTreeList *> (tree);
-	flatten_list (*list, paths);
+	flatten_list (*list, imports);
 	break;
       }
       break;
@@ -858,36 +855,28 @@ flatten (const AST::UseTree *tree, std::vector<AST::SimplePath> &paths)
 }
 
 static void
-flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths)
+flatten_glob (const AST::UseTreeGlob &glob, std::vector<Import> &imports)
 {
   if (glob.has_path ())
-    paths.emplace_back (glob.get_path ());
+    imports.emplace_back (glob.get_path (), true, std::string ());
 }
 
 static void
-flatten_rebind (const AST::UseTreeRebind &rebind,
-		std::vector<AST::SimplePath> &paths)
+flatten_rebind (const AST::UseTreeRebind &rebind, std::vector<Import> &imports)
 {
   auto path = rebind.get_path ();
-  if (rebind.has_path ())
-    paths.emplace_back (path);
 
-  // FIXME: Do we want to emplace the rebind here as well?
+  std::string label;
   if (rebind.has_identifier ())
-    {
-      auto rebind_path = path;
-      auto new_seg = rebind.get_identifier ();
-
-      // Add the identifier as a new path
-      rebind_path.get_segments ().back ()
-	= AST::SimplePathSegment (new_seg.as_string (), UNDEF_LOCATION);
+    label = rebind.get_identifier ().as_string ();
+  else
+    label = path.get_final_segment ().as_string ();
 
-      paths.emplace_back (rebind_path);
-    }
+  imports.emplace_back (path, false, label);
 }
 
 static void
-flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths)
+flatten_list (const AST::UseTreeList &list, std::vector<Import> &imports)
 {
   auto prefix = AST::SimplePath::create_empty ();
   if (list.has_path ())
@@ -895,21 +884,25 @@ flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths)
 
   for (const auto &tree : list.get_trees ())
     {
-      auto sub_paths = std::vector<AST::SimplePath> ();
-      flatten (tree.get (), sub_paths);
+      // append imports to the main list, then modify them in-place
+      auto start_idx = imports.size ();
+      flatten (tree.get (), imports);
 
-      for (auto &sub_path : sub_paths)
-	{
-	  auto new_path = prefix;
-	  std::copy (sub_path.get_segments ().begin (),
-		     sub_path.get_segments ().end (),
-		     std::back_inserter (new_path.get_segments ()));
-
-	  paths.emplace_back (new_path);
-	}
+      for (auto import = imports.begin () + start_idx; import != imports.end ();
+	   import++)
+	import->add_prefix (prefix);
     }
 }
 
+void
+Import::add_prefix (AST::SimplePath prefix)
+{
+  AST::SimplePath old_path (std::move (path));
+  path = std::move (prefix);
+  std::move (old_path.get_segments ().begin (), old_path.get_segments ().end (),
+	     std::back_inserter (path.get_segments ()));
+}
+
 /**
  * Flatten a UseDeclaration's UseTree into multiple simple paths to resolve.
  *
@@ -930,21 +923,21 @@ flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths)
  * Finally in the third case, we want to create two SimplePaths to resolve:
  * [some::path::one, some::path::two]
  */
-static std::vector<AST::SimplePath>
-flatten_use_dec_to_paths (const AST::UseDeclaration &use_item)
+static std::vector<Import>
+flatten_use_dec_to_imports (const AST::UseDeclaration &use_item)
 {
-  auto paths = std::vector<AST::SimplePath> ();
+  auto imports = std::vector<Import> ();
 
   const auto &tree = use_item.get_tree ();
-  flatten (tree.get (), paths);
+  flatten (tree.get (), imports);
 
-  return paths;
+  return imports;
 }
 
 void
 ResolveItem::visit (AST::UseDeclaration &use_item)
 {
-  std::vector<AST::SimplePath> to_resolve = flatten_use_dec_to_paths (use_item);
+  std::vector<Import> to_resolve = flatten_use_dec_to_imports (use_item);
 
   // FIXME: I think this does not actually resolve glob use-decls and is going
   // the wrong way about it. RFC #1560 specifies the following:
@@ -956,18 +949,20 @@ ResolveItem::visit (AST::UseDeclaration &use_item)
   // Which is the opposite of what we're doing if I understand correctly?
 
   NodeId current_module = resolver->peek_current_module_scope ();
-  for (auto &path : to_resolve)
+  for (auto &import : to_resolve)
     {
+      auto &path = import.get_path ();
+
       rust_debug ("resolving use-decl path: [%s]", path.as_string ().c_str ());
       NodeId resolved_node_id = ResolvePath::go (&path);
       bool ok = resolved_node_id != UNKNOWN_NODEID;
       if (!ok)
 	continue;
 
-      const AST::SimplePathSegment &final_seg = path.get_segments ().back ();
+      if (import.is_glob ())
+	continue;
 
-      auto decl
-	= CanonicalPath::new_seg (resolved_node_id, final_seg.as_string ());
+      auto decl = CanonicalPath::new_seg (resolved_node_id, import.get_name ());
       mappings->insert_module_child_item (current_module, decl);
 
       resolver->get_type_scope ().insert (decl, resolved_node_id,
@@ -1079,13 +1074,13 @@ rust_flatten_nested_glob (void)
     = Rust::AST::UseTreeGlob (Rust::AST::UseTreeGlob::PathType::PATH_PREFIXED,
 			      foobar, UNDEF_LOCATION);
 
-  auto paths = std::vector<Rust::AST::SimplePath> ();
-  Rust::Resolver::flatten_glob (glob, paths);
+  auto imports = std::vector<Rust::Resolver::Import> ();
+  Rust::Resolver::flatten_glob (glob, imports);
 
-  ASSERT_TRUE (!paths.empty ());
-  ASSERT_EQ (paths.size (), 1);
-  ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
-  ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+  ASSERT_TRUE (!imports.empty ());
+  ASSERT_EQ (imports.size (), 1);
+  ASSERT_EQ (imports[0].get_path ().get_segments ()[0].as_string (), "foo");
+  ASSERT_EQ (imports[0].get_path ().get_segments ()[1].as_string (), "bar");
 }
 
 static void
@@ -1097,12 +1092,12 @@ rust_flatten_glob (void)
     = Rust::AST::UseTreeGlob (Rust::AST::UseTreeGlob::PathType::PATH_PREFIXED,
 			      frob, UNDEF_LOCATION);
 
-  auto paths = std::vector<Rust::AST::SimplePath> ();
-  Rust::Resolver::flatten_glob (glob, paths);
+  auto imports = std::vector<Rust::Resolver::Import> ();
+  Rust::Resolver::flatten_glob (glob, imports);
 
-  ASSERT_TRUE (!paths.empty ());
-  ASSERT_EQ (paths.size (), 1);
-  ASSERT_EQ (paths[0], "frobulator");
+  ASSERT_TRUE (!imports.empty ());
+  ASSERT_EQ (imports.size (), 1);
+  ASSERT_EQ (imports[0].get_path (), "frobulator");
 }
 
 static void
@@ -1115,13 +1110,13 @@ rust_flatten_rebind_none (void)
   auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE,
 					  foobar, UNDEF_LOCATION);
 
-  auto paths = std::vector<Rust::AST::SimplePath> ();
-  Rust::Resolver::flatten_rebind (rebind, paths);
+  auto imports = std::vector<Rust::Resolver::Import> ();
+  Rust::Resolver::flatten_rebind (rebind, imports);
 
-  ASSERT_TRUE (!paths.empty ());
-  ASSERT_EQ (paths.size (), 1);
-  ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
-  ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+  ASSERT_TRUE (!imports.empty ());
+  ASSERT_EQ (imports.size (), 1);
+  ASSERT_EQ (imports[0].get_path ().get_segments ()[0].as_string (), "foo");
+  ASSERT_EQ (imports[0].get_path ().get_segments ()[1].as_string (), "bar");
 }
 
 static void
@@ -1132,13 +1127,13 @@ rust_flatten_rebind (void)
   auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::IDENTIFIER,
 					  frob, UNDEF_LOCATION, {"saindoux"});
 
-  auto paths = std::vector<Rust::AST::SimplePath> ();
-  Rust::Resolver::flatten_rebind (rebind, paths);
+  auto imports = std::vector<Rust::Resolver::Import> ();
+  Rust::Resolver::flatten_rebind (rebind, imports);
 
-  ASSERT_TRUE (!paths.empty ());
-  ASSERT_EQ (paths.size (), 2);
-  ASSERT_EQ (paths[0], "frobulator");
-  ASSERT_EQ (paths[1], "saindoux");
+  ASSERT_TRUE (!imports.empty ());
+  ASSERT_EQ (imports.size (), 1);
+  ASSERT_EQ (imports[0].get_path (), "frobulator");
+  ASSERT_EQ (imports[0].get_name (), "saindoux");
 }
 
 static void
@@ -1154,17 +1149,15 @@ rust_flatten_rebind_nested (void)
     = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::IDENTIFIER,
 				foo_bar_baz, UNDEF_LOCATION, {"saindoux"});
 
-  auto paths = std::vector<Rust::AST::SimplePath> ();
-  Rust::Resolver::flatten_rebind (rebind, paths);
-
-  ASSERT_TRUE (!paths.empty ());
-  ASSERT_EQ (paths.size (), 2);
-  ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
-  ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
-  ASSERT_EQ (paths[0].get_segments ()[2].as_string (), "baz");
-  ASSERT_EQ (paths[1].get_segments ()[0].as_string (), "foo");
-  ASSERT_EQ (paths[1].get_segments ()[1].as_string (), "bar");
-  ASSERT_EQ (paths[1].get_segments ()[2].as_string (), "saindoux");
+  auto imports = std::vector<Rust::Resolver::Import> ();
+  Rust::Resolver::flatten_rebind (rebind, imports);
+
+  ASSERT_TRUE (!imports.empty ());
+  ASSERT_EQ (imports.size (), 1);
+  ASSERT_EQ (imports[0].get_path ().get_segments ()[0].as_string (), "foo");
+  ASSERT_EQ (imports[0].get_path ().get_segments ()[1].as_string (), "bar");
+  ASSERT_EQ (imports[0].get_path ().get_segments ()[2].as_string (), "baz");
+  ASSERT_EQ (imports[0].get_name (), "saindoux");
 }
 
 static void
@@ -1194,17 +1187,17 @@ rust_flatten_list (void)
     = Rust::AST::UseTreeList (Rust::AST::UseTreeList::PATH_PREFIXED, foo_bar,
 			      std::move (uses), UNDEF_LOCATION);
 
-  auto paths = std::vector<Rust::AST::SimplePath> ();
-  Rust::Resolver::flatten_list (list, paths);
-
-  ASSERT_TRUE (!paths.empty ());
-  ASSERT_EQ (paths.size (), 2);
-  ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
-  ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
-  ASSERT_EQ (paths[0].get_segments ()[2].as_string (), "baz");
-  ASSERT_EQ (paths[1].get_segments ()[0].as_string (), "foo");
-  ASSERT_EQ (paths[1].get_segments ()[1].as_string (), "bar");
-  ASSERT_EQ (paths[1].get_segments ()[2].as_string (), "bul");
+  auto imports = std::vector<Rust::Resolver::Import> ();
+  Rust::Resolver::flatten_list (list, imports);
+
+  ASSERT_TRUE (!imports.empty ());
+  ASSERT_EQ (imports.size (), 2);
+  ASSERT_EQ (imports[0].get_path ().get_segments ()[0].as_string (), "foo");
+  ASSERT_EQ (imports[0].get_path ().get_segments ()[1].as_string (), "bar");
+  ASSERT_EQ (imports[0].get_path ().get_segments ()[2].as_string (), "baz");
+  ASSERT_EQ (imports[1].get_path ().get_segments ()[0].as_string (), "foo");
+  ASSERT_EQ (imports[1].get_path ().get_segments ()[1].as_string (), "bar");
+  ASSERT_EQ (imports[1].get_path ().get_segments ()[2].as_string (), "bul");
 }
 
 static void
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
index 0c7b7527c44..e397ffdfe8b 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -124,6 +124,29 @@ private:
   const CanonicalPath &canonical_prefix;
 };
 
+class Import
+{
+public:
+  Import (AST::SimplePath path, bool is_glob, std::string name)
+    : path (path), is_glob_f (is_glob), name (name)
+  {}
+
+  AST::SimplePath &get_path () { return path; }
+
+  const AST::SimplePath &get_path () const { return path; }
+
+  bool is_glob () const { return is_glob_f; }
+
+  const std::string &get_name () const { return name; }
+
+  void add_prefix (AST::SimplePath prefix);
+
+private:
+  AST::SimplePath path;
+  bool is_glob_f;
+  std::string name;
+};
+
 } // namespace Resolver
 } // namespace Rust
 
diff --git a/gcc/testsuite/rust/compile/use_2.rs b/gcc/testsuite/rust/compile/use_2.rs
new file mode 100644
index 00000000000..b89ff82caaa
--- /dev/null
+++ b/gcc/testsuite/rust/compile/use_2.rs
@@ -0,0 +1,7 @@
+mod foo {
+    pub struct S;
+}
+
+use foo::S as T;
+
+const V: T = T; // { dg-warning "unused name" }
-- 
2.42.1



More information about the Gcc-patches mailing list