From af7e8fda83d8b34170f4fdf3371b67cd6b4e72f1 Mon Sep 17 00:00:00 2001 From: Raiki Tamura Date: Wed, 31 Jul 2024 16:09:30 +0900 Subject: [PATCH] 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 --- .../typecheck/rust-hir-type-check-pattern.cc | 82 +++++++++++++------ gcc/testsuite/rust/compile/match8.rs | 19 +++++ 2 files changed, 76 insertions(+), 25 deletions(-) create mode 100644 gcc/testsuite/rust/compile/match8.rs diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc index 438c3bf5381c..811e329ba2b4 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 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 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 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() {}