From: Utkarsh Bahuguna <[email protected]>

is_refutable looked path patterns up by the last segment's hir id, which
doesn't point at the item, so let and fn param paths hit
rust_unreachable. Go through name resolution instead, consts count as
refutable and anything else falls back to the scrutinee type.

Fixes Rust-GCC/gccrs#4732

Assisted-by: Claude Opus (Anthropic)

gcc/rust/ChangeLog:

        * hir/tree/rust-hir-pattern-abstract.cc (PathPattern::is_refutable):
        Resolve the path through name resolution instead of its final
        segment, and handle associated constants and const generics.

gcc/testsuite/ChangeLog:

        * rust/compile/refutable-path.rs: Remove dg-ice and add associated
        const and const generic cases.
        * rust/compile/irrefutable-path-single-variant.rs: New test.

Signed-off-by: Utkarsh Bahuguna <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/cd47eb1fd1c94e316693b6300d1f8282905c6553

The commit has been mentioned in the following issue(s):
 - Rust-GCC/gccrs#4732: https://github.com/Rust-GCC/gccrs/issues/4732

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4808

 .../hir/tree/rust-hir-pattern-abstract.cc     | 54 ++++++++++++-------
 .../irrefutable-path-single-variant.rs        | 16 ++++++
 gcc/testsuite/rust/compile/refutable-path.rs  | 25 +++++++--
 3 files changed, 70 insertions(+), 25 deletions(-)
 create mode 100644 
gcc/testsuite/rust/compile/irrefutable-path-single-variant.rs

diff --git a/gcc/rust/hir/tree/rust-hir-pattern-abstract.cc 
b/gcc/rust/hir/tree/rust-hir-pattern-abstract.cc
index 146208c47..eac09e2d5 100644
--- a/gcc/rust/hir/tree/rust-hir-pattern-abstract.cc
+++ b/gcc/rust/hir/tree/rust-hir-pattern-abstract.cc
@@ -22,6 +22,7 @@
 #include "optional.h"
 #include "rust-tyty.h"
 #include "rust-hir-type-check.h"
+#include "rust-finalized-name-resolution-context.h"
 namespace Rust {
 namespace HIR {
 
@@ -55,34 +56,47 @@ PathPattern::is_refutable (const TyTy::BaseType &scrutinee) 
const
   rust_assert (kind != Kind::LangItem);
 
   auto &mappings = Analysis::Mappings::get ();
-  HirId hir_id = get_final_segment ().get_mappings ().get_hirid ();
-  if (hir_id)
+  auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
+  // Resolve the path through name resolution because its final segment's
+  // HirId does not necessarily identify the referenced item directly.
+  if (auto def = nr_ctx.lookup (get_mappings ().get_nodeid (),
+                               Resolver2_0::Namespace::Values,
+                               Resolver2_0::Namespace::Types))
     {
-      auto item = mappings.hir.items.lookup (hir_id);
-      if (item && item.value ()->get_item_kind () == Item::ItemKind::Constant)
-       {
-         return true;
-       }
-      else
+      if (auto def_hir_id = mappings.lookup_node_to_hir (def->id))
        {
-         rust_internal_error_at (
-           get_locus (),
-           "failed to lookup hir item during refutability checks");
-         return true;
+         auto item = mappings.hir.items.lookup (*def_hir_id);
+         if (item
+             && item.value ()->get_item_kind () == Item::ItemKind::Constant)
+           return true;
+
+         // Associated constants live in the impl-item and trait-item maps,
+         // not the item map, so they need their own lookups.
+         if (auto implitem = mappings.lookup_hir_implitem (*def_hir_id))
+           if (implitem->first->get_impl_item_type ()
+               == ImplItem::ImplItemType::CONSTANT)
+             return true;
+
+         if (auto traititem = mappings.hir.trait_items.lookup (*def_hir_id))
+           if (traititem.value ()->get_item_kind ()
+               == TraitItem::TraitItemKind::CONST)
+             return true;
        }
     }
 
-  // A path pattern is irrefutable if it corresponds to an enum with one 
variant
-  if (scrutinee.get_kind () == TyTy::TypeKind::ADT)
+  // A failed item lookup is fine since refutability can still be checked
+  // from the scrutinee's ADT type.
+  const auto *inner = scrutinee.destructure ();
+  if (inner->get_kind () == TyTy::TypeKind::ADT)
     {
-      const auto &adt = static_cast<const TyTy::ADTType &> (scrutinee);
+      const auto &adt = static_cast<const TyTy::ADTType &> (*inner);
       if (adt.is_enum ())
-       {
-         return adt.number_of_variants () > 1;
-       }
+       return adt.number_of_variants () > 1;
+      return false;
     }
-  // cannot have a Path that is neither a constant or an enum-like ADT
-  rust_unreachable ();
+
+  // A failed lookup is fine since a non-ADT constant matches one value.
+  return true;
 }
 
 bool
diff --git a/gcc/testsuite/rust/compile/irrefutable-path-single-variant.rs 
b/gcc/testsuite/rust/compile/irrefutable-path-single-variant.rs
new file mode 100644
index 000000000..1b7ab9554
--- /dev/null
+++ b/gcc/testsuite/rust/compile/irrefutable-path-single-variant.rs
@@ -0,0 +1,16 @@
+// { dg-additional-options "-w" }
+#![feature(no_core)]
+#![no_core]
+
+enum E {
+    A,
+}
+
+struct S;
+
+fn main() {
+    // A single-variant enum's unit variant is irrefutable.
+    let E::A: E;
+    // A unit struct is irrefutable.
+    let S: S;
+}
diff --git a/gcc/testsuite/rust/compile/refutable-path.rs 
b/gcc/testsuite/rust/compile/refutable-path.rs
index 89da0453a..08f2676b1 100644
--- a/gcc/testsuite/rust/compile/refutable-path.rs
+++ b/gcc/testsuite/rust/compile/refutable-path.rs
@@ -1,14 +1,29 @@
 #![feature(no_core)]
 #![no_core]
-// { dg-ice "" }
 enum E {
     A,
     B,
 }
 const A: u32 = 0;
-fn a(E::A: E) {}
-fn b(A: u32) {}
+struct S;
+impl S {
+    const C: u32 = 0;
+}
+fn a(E::A: E) {} // { dg-error "refutable pattern in function parameter" }
+fn b(A: u32) {} // { dg-error "refutable pattern in function parameter" }
 fn main() {
-    let A: u32;
-    let E::A: E;
+    let A: u32; // { dg-error "refutable pattern in local binding" }
+    let E::A: E; // { dg-error "refutable pattern in local binding" }
+    let S::C: u32; // { dg-error "refutable pattern in local binding" }
+}
+fn f<const N: usize>(x: usize) {
+    let N = x; // { dg-error "refutable pattern in local binding" }
+}
+
+struct U;
+impl U {
+    const K: U = U;
+}
+fn g() {
+    let U::K: U; // { dg-error "refutable pattern in local binding" }
 }

base-commit: 5f761a8444bee30c342b6d02283d862d9aa462d3
-- 
2.56.0

Reply via email to