https://gcc.gnu.org/g:5dc8451b867d996d1685cb96f3d1ea7c57c4bcbd

commit r17-4104-g5dc8451b867d996d1685cb96f3d1ea7c57c4bcbd
Author: Utkarsh Bahuguna <[email protected]>
Date:   Tue Aug 11 15:38:32 2026 +0530

    gccrs: error on duplicate extern crate names
    
    Extern crate declarations did not insert their bound name into any
    namespace. Because nothing was inserted, the existing duplicate-name
    check could never fire for extern crates. As a result, both
    extern crate foo; extern crate foo; and extern crate foo; mod foo {}
    compiled silently.
    
    Insert the bound name, using the alias when one is present, into the
    type namespace. Record extern crate node ids in Mappings so the check
    can determine what kind of declaration each side represents. Select
    E0259 when both sides are extern crates and E0260 when only one side is
    an extern crate. E0428 remains unchanged for every other item kind.
    
    Record the extern crate node in Mappings before calling
    insert_or_error_out because check_multiple_insertion_error runs inside
    that call and needs to know whether the new node is an extern crate.
    This differs from visit (AST::Module&), which records the node after the
    insertion call.
    
    Fixes Rust-GCC/gccrs#4679
    
    gcc/rust/ChangeLog:
    
            * util/rust-hir-map.h (Mappings::insert_extern_crate_id)
            (Mappings::is_extern_crate): New declaration.
            (Mappings::extern_crate_ids): New member.
            * util/rust-hir-map.cc (Mappings::insert_extern_crate_id)
            (Mappings::is_extern_crate): New function.
            * resolve/rust-toplevel-name-resolver-2.0.h
            (TopLevel::visit (ExternCrate)): New declaration.
            * resolve/rust-toplevel-name-resolver-2.0.cc
            (TopLevel::check_multiple_insertion_error): Select E0259, E0260 or
            E0428 based on the colliding declarations.
            (TopLevel::visit (ExternCrate)): New function definition.
    
    gcc/testsuite/ChangeLog:
    
            * rust/link/extern_crate_alias_0.rs: New test.
            * rust/link/extern_crate_alias_1.rs: New test.
            * rust/link/extern_crate_dup_0.rs: New test.
            * rust/link/extern_crate_dup_1.rs: New test.
            * rust/link/extern_crate_item_conflict_0.rs: New test.
            * rust/link/extern_crate_item_conflict_1.rs: New test.
    
    Signed-off-by: Utkarsh Bahuguna <[email protected]>

Diff:
---
 .../resolve/rust-toplevel-name-resolver-2.0.cc     | 25 ++++++++++++++++++++--
 gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h |  1 +
 gcc/rust/util/rust-hir-map.cc                      | 12 +++++++++++
 gcc/rust/util/rust-hir-map.h                       |  4 ++++
 gcc/testsuite/rust/link/extern_crate_alias_0.rs    |  9 ++++++++
 gcc/testsuite/rust/link/extern_crate_alias_1.rs    |  2 ++
 gcc/testsuite/rust/link/extern_crate_dup_0.rs      |  5 +++++
 gcc/testsuite/rust/link/extern_crate_dup_1.rs      |  2 ++
 .../rust/link/extern_crate_item_conflict_0.rs      |  5 +++++
 .../rust/link/extern_crate_item_conflict_1.rs      |  2 ++
 10 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc 
b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
index 117bb32fb0f5..c7f35b62859e 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
@@ -50,8 +50,18 @@ TopLevel::check_multiple_insertion_error (
     {
       rich_location rich_loc (line_table, locus);
       rich_loc.add_range (node_locations[result.error ().existing]);
-
-      rust_error_at (rich_loc, ErrorCode::E0428, "%qs defined multiple times",
+      auto &mappings = Analysis::Mappings::get ();
+      ErrorCode code;
+      if (mappings.is_extern_crate (node_id)
+         && mappings.is_extern_crate (result.error ().existing))
+       code = ErrorCode::E0259;
+      else if (mappings.is_extern_crate (node_id)
+              || mappings.is_extern_crate (result.error ().existing))
+       code = ErrorCode::E0260;
+      else
+       code = ErrorCode::E0428;
+
+      rust_error_at (rich_loc, code, "%qs defined multiple times",
                     identifier.as_string ().c_str ());
     }
 }
@@ -127,6 +137,17 @@ TopLevel::visit (AST::Trait &trait)
   DefaultResolver::visit (trait);
 }
 
+void
+TopLevel::visit (AST::ExternCrate &crate)
+{
+  auto &name = crate.has_as_clause () ? crate.get_as_clause ()
+                                     : crate.get_referenced_crate ();
+  Analysis::Mappings::get ().insert_extern_crate_id (crate.get_node_id ());
+  insert_or_error_out (name, crate, Namespace::Types);
+
+  DefaultResolver::visit (crate);
+}
+
 void
 TopLevel::maybe_insert_big_self (AST::Impl &impl)
 {
diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h 
b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
index 897c54158e58..28c340b1cc03 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
@@ -167,6 +167,7 @@ private:
 
   void visit (AST::Module &module) override;
   void visit (AST::Trait &trait) override;
+  void visit (AST::ExternCrate &crate) override;
   void maybe_insert_big_self (AST::Impl &impl) override;
   void visit (AST::TraitItemType &trait_item) override;
   void visit (AST::MacroRulesDefinition &macro) override;
diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc
index 10ee87e1bc8c..58427b98631d 100644
--- a/gcc/rust/util/rust-hir-map.cc
+++ b/gcc/rust/util/rust-hir-map.cc
@@ -1180,6 +1180,18 @@ Mappings::is_module (NodeId id)
   return module_ids.find (id) != module_ids.end ();
 }
 
+void
+Mappings::insert_extern_crate_id (NodeId id)
+{
+  extern_crate_ids.insert (id);
+}
+
+bool
+Mappings::is_extern_crate (NodeId id)
+{
+  return extern_crate_ids.find (id) != extern_crate_ids.end ();
+}
+
 tl::optional<AST::GlobContainer *>
 Mappings::lookup_glob_container (NodeId id)
 {
diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h
index 3212083b3769..dfbec3c88a70 100644
--- a/gcc/rust/util/rust-hir-map.h
+++ b/gcc/rust/util/rust-hir-map.h
@@ -328,6 +328,9 @@ public:
   void insert_module_id (NodeId);
   bool is_module (NodeId id);
 
+  void insert_extern_crate_id (NodeId);
+  bool is_extern_crate (NodeId id);
+
   void insert_module_child (NodeId module, NodeId child);
   tl::optional<std::vector<NodeId> &> lookup_module_children (NodeId module);
 
@@ -453,6 +456,7 @@ private:
 
   std::map<NodeId, AST::GlobContainer *> glob_containers;
   std::set<NodeId> module_ids;
+  std::set<NodeId> extern_crate_ids;
 
   // AST mappings
   std::map<NodeId, AST::Item *> ast_item_mappings;
diff --git a/gcc/testsuite/rust/link/extern_crate_alias_0.rs 
b/gcc/testsuite/rust/link/extern_crate_alias_0.rs
new file mode 100644
index 000000000000..b47e53572bda
--- /dev/null
+++ b/gcc/testsuite/rust/link/extern_crate_alias_0.rs
@@ -0,0 +1,9 @@
+// TODO: this should compile cleanly. It currently ICEs because the same crate
+// gets lowered twice, see Rust-GCC/gccrs#4724.
+// { dg-ice "" }
+
+#![feature(no_core)]
+#![no_core]
+
+extern crate extern_crate_alias_1;
+extern crate extern_crate_alias_1 as other;
diff --git a/gcc/testsuite/rust/link/extern_crate_alias_1.rs 
b/gcc/testsuite/rust/link/extern_crate_alias_1.rs
new file mode 100644
index 000000000000..da27b7f3463d
--- /dev/null
+++ b/gcc/testsuite/rust/link/extern_crate_alias_1.rs
@@ -0,0 +1,2 @@
+#![feature(no_core)]
+#![no_core]
diff --git a/gcc/testsuite/rust/link/extern_crate_dup_0.rs 
b/gcc/testsuite/rust/link/extern_crate_dup_0.rs
new file mode 100644
index 000000000000..8fec4d7c0254
--- /dev/null
+++ b/gcc/testsuite/rust/link/extern_crate_dup_0.rs
@@ -0,0 +1,5 @@
+#![feature(no_core)]
+#![no_core]
+
+extern crate extern_crate_dup_1;
+extern crate extern_crate_dup_1; // { dg-error ".extern_crate_dup_1. defined 
multiple times" }
diff --git a/gcc/testsuite/rust/link/extern_crate_dup_1.rs 
b/gcc/testsuite/rust/link/extern_crate_dup_1.rs
new file mode 100644
index 000000000000..da27b7f3463d
--- /dev/null
+++ b/gcc/testsuite/rust/link/extern_crate_dup_1.rs
@@ -0,0 +1,2 @@
+#![feature(no_core)]
+#![no_core]
diff --git a/gcc/testsuite/rust/link/extern_crate_item_conflict_0.rs 
b/gcc/testsuite/rust/link/extern_crate_item_conflict_0.rs
new file mode 100644
index 000000000000..034c2405d61a
--- /dev/null
+++ b/gcc/testsuite/rust/link/extern_crate_item_conflict_0.rs
@@ -0,0 +1,5 @@
+#![feature(no_core)]
+#![no_core]
+
+extern crate extern_crate_item_conflict_1;
+mod extern_crate_item_conflict_1 {} // { dg-error 
".extern_crate_item_conflict_1. defined multiple times" }
diff --git a/gcc/testsuite/rust/link/extern_crate_item_conflict_1.rs 
b/gcc/testsuite/rust/link/extern_crate_item_conflict_1.rs
new file mode 100644
index 000000000000..da27b7f3463d
--- /dev/null
+++ b/gcc/testsuite/rust/link/extern_crate_item_conflict_1.rs
@@ -0,0 +1,2 @@
+#![feature(no_core)]
+#![no_core]

Reply via email to