[gcc r15-8330] rust: Add checking for union patterns

Arthur Cohen cohenarthur@gcc.gnu.org
Wed Mar 19 14:39:39 GMT 2025


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

commit r15-8330-gb7e79e38fe97e9f41008f0a48bd41ffdd7a2895c
Author: Raiki Tamura <tamaron1203@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 <tamaron1203@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() {}


More information about the Gcc-cvs mailing list