Skip to content

Commit

Permalink
rust: Add checking for union patterns
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
tamaroning authored and P-E-P committed Aug 27, 2024
1 parent 084789e commit af7e8fd
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 25 deletions.
82 changes: 57 additions & 25 deletions gcc/rust/typecheck/rust-hir-type-check-pattern.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 ())
Expand Down Expand Up @@ -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 ());
}
}

Expand Down
19 changes: 19 additions & 0 deletions gcc/testsuite/rust/compile/match8.rs
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit af7e8fd

Please sign in to comment.