https://gcc.gnu.org/g:b7e79e38fe97e9f41008f0a48bd41ffdd7a2895c

commit r15-8330-gb7e79e38fe97e9f41008f0a48bd41ffdd7a2895c
Author: Raiki Tamura <tamaron1...@gmail.com>
Date:   Wed Jul 31 16:09:30 2024 +0900

    rust: Add checking for union patterns
    
    gcc/rust/ChangeLog:
    
            * typecheck/rust-hir-type-check-pattern.cc 
(TypeCheckPattern::visit):
                    Add check for union patterns.
    
    gcc/testsuite/ChangeLog:
    
            * rust/compile/match8.rs: New test.
    
    Signed-off-by: Raiki Tamura <tamaron1...@gmail.com>

Diff:
---
 gcc/rust/typecheck/rust-hir-type-check-pattern.cc | 82 ++++++++++++++++-------
 gcc/testsuite/rust/compile/match8.rs              | 19 ++++++
 2 files changed, 76 insertions(+), 25 deletions(-)

diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc 
b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
index 1a3d0ecd1859..2b0b02ad5ef0 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
@@ -222,10 +222,6 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern)
       return;
     }
 
-  // check the elements
-  // error[E0027]: pattern does not mention fields `x`, `y`
-  // error[E0026]: variant `Foo::D` does not have a field named `b`
-
   std::vector<std::string> named_fields;
   auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
   for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
@@ -279,31 +275,67 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern)
        }
     }
 
-  if (named_fields.size () != variant->num_fields ())
+  // check the elements
+  if (adt->is_union ())
     {
-      std::map<std::string, bool> missing_names;
+      auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
+      if (struct_pattern_elems.get_struct_pattern_fields ().size () != 1)
+       rust_error_at (pattern.get_locus (),
+                      "union patterns should have exactly one field");
 
-      // populate with all fields
-      for (auto &field : variant->get_fields ())
-       missing_names[field->get_name ()] = true;
-
-      // then eliminate with named_fields
-      for (auto &named : named_fields)
-       missing_names.erase (named);
-
-      // then get the list of missing names
-      size_t i = 0;
-      std::string missing_fields_str;
-      for (auto it = missing_names.begin (); it != missing_names.end (); it++)
+      else
+       {
+         switch (struct_pattern_elems.get_struct_pattern_fields ()
+                   .at (0)
+                   ->get_item_type ())
+           {
+           case HIR::StructPatternField::ItemType::IDENT:
+           case HIR::StructPatternField::ItemType::IDENT_PAT:
+             break;
+             default: {
+               auto first_elem
+                 = struct_pattern_elems.get_struct_pattern_fields ()
+                     .at (0)
+                     ->as_string ();
+               rust_error_at (pattern.get_locus (),
+                              "%qs cannot be used in union patterns",
+                              first_elem.c_str ());
+             }
+           }
+       }
+    }
+  else
+    {
+      // Expects enum struct or struct struct.
+      // error[E0027]: pattern does not mention fields `x`, `y`
+      // error[E0026]: variant `Foo::D` does not have a field named `b`
+      if (named_fields.size () != variant->num_fields ())
        {
-         bool has_next = (i + 1) < missing_names.size ();
-         missing_fields_str += it->first + (has_next ? ", " : "");
-         i++;
+         std::map<std::string, bool> missing_names;
+
+         // populate with all fields
+         for (auto &field : variant->get_fields ())
+           missing_names[field->get_name ()] = true;
+
+         // then eliminate with named_fields
+         for (auto &named : named_fields)
+           missing_names.erase (named);
+
+         // then get the list of missing names
+         size_t i = 0;
+         std::string missing_fields_str;
+         for (auto it = missing_names.begin (); it != missing_names.end ();
+              it++)
+           {
+             bool has_next = (i + 1) < missing_names.size ();
+             missing_fields_str += it->first + (has_next ? ", " : "");
+             i++;
+           }
+
+         rust_error_at (pattern.get_locus (), ErrorCode::E0027,
+                        "pattern does not mention fields %s",
+                        missing_fields_str.c_str ());
        }
-
-      rust_error_at (pattern.get_locus (), ErrorCode::E0027,
-                    "pattern does not mention fields %s",
-                    missing_fields_str.c_str ());
     }
 }
 
diff --git a/gcc/testsuite/rust/compile/match8.rs 
b/gcc/testsuite/rust/compile/match8.rs
new file mode 100644
index 000000000000..336b313cde3e
--- /dev/null
+++ b/gcc/testsuite/rust/compile/match8.rs
@@ -0,0 +1,19 @@
+union MyUnion {
+    f1: u32,
+    f2: f32,
+}
+
+fn f(u: MyUnion) -> i32 {
+    unsafe {
+        match u {
+            MyUnion { f1: 10 } => 0,
+            MyUnion { f2 } => 0,
+            MyUnion { f1: 10, f2: 10.0 } => 0, // { dg-error "union patterns 
should have exactly one field" "" }
+            MyUnion {} => 0, // { dg-error "union patterns should have exactly 
one field" "" }
+            MyUnion { f1: () } => 0, // { dg-error "expected u32, found tuple" 
"" }
+            _ => 1,
+        }
+    }
+}
+
+fn main() {}

Reply via email to