diff --git a/gcc/rust/ast/rust-ast-collector.cc b/gcc/rust/ast/rust-ast-collector.cc index 842f35f288d..721d274a838 100644 --- a/gcc/rust/ast/rust-ast-collector.cc +++ b/gcc/rust/ast/rust-ast-collector.cc @@ -2620,7 +2620,7 @@ TokenCollector::visit (StructPattern &pattern) if (elems.has_struct_pattern_fields ()) { visit_items_joined_by_separator (elems.get_struct_pattern_fields ()); - if (elems.has_etc ()) + if (elems.has_rest ()) { push (Rust::Token::make (COMMA, UNDEF_LOCATION)); visit_items_as_lines (elems.get_etc_outer_attrs ()); diff --git a/gcc/rust/ast/rust-pattern.cc b/gcc/rust/ast/rust-pattern.cc index ebe872402ea..a2fe5d59081 100644 --- a/gcc/rust/ast/rust-pattern.cc +++ b/gcc/rust/ast/rust-pattern.cc @@ -186,8 +186,8 @@ StructPatternElements::as_string () const str += "\n " + field->as_string (); } - str += "\n Etc: "; - if (has_struct_pattern_etc) + str += "\n Has rest: "; + if (has_rest_pattern) str += "true"; else str += "false"; diff --git a/gcc/rust/ast/rust-pattern.h b/gcc/rust/ast/rust-pattern.h index 51986763fad..0da1981928f 100644 --- a/gcc/rust/ast/rust-pattern.h +++ b/gcc/rust/ast/rust-pattern.h @@ -843,7 +843,7 @@ class StructPatternElements // bool has_struct_pattern_fields; std::vector> fields; - bool has_struct_pattern_etc; + bool has_rest_pattern; std::vector struct_pattern_etc_attrs; // StructPatternEtc etc; @@ -859,29 +859,29 @@ class StructPatternElements * no etc). */ bool is_empty () const { - return !has_struct_pattern_fields () && !has_struct_pattern_etc; + return !has_struct_pattern_fields () && !has_rest_pattern; } - bool has_etc () const { return has_struct_pattern_etc; } + bool has_rest () const { return has_rest_pattern; } // Constructor for StructPatternElements with both (potentially) StructPatternElements ( std::vector> fields, std::vector etc_attrs) - : fields (std::move (fields)), has_struct_pattern_etc (true), + : fields (std::move (fields)), has_rest_pattern (true), struct_pattern_etc_attrs (std::move (etc_attrs)) {} // Constructor for StructPatternElements with no StructPatternEtc StructPatternElements ( std::vector> fields) - : fields (std::move (fields)), has_struct_pattern_etc (false), + : fields (std::move (fields)), has_rest_pattern (false), struct_pattern_etc_attrs () {} // Copy constructor with vector clone StructPatternElements (StructPatternElements const &other) - : has_struct_pattern_etc (other.has_struct_pattern_etc), + : has_rest_pattern (other.has_rest_pattern), struct_pattern_etc_attrs (other.struct_pattern_etc_attrs) { fields.reserve (other.fields.size ()); @@ -893,7 +893,7 @@ class StructPatternElements StructPatternElements &operator= (StructPatternElements const &other) { struct_pattern_etc_attrs = other.struct_pattern_etc_attrs; - has_struct_pattern_etc = other.has_struct_pattern_etc; + has_rest_pattern = other.has_rest_pattern; fields.clear (); fields.reserve (other.fields.size ()); @@ -938,7 +938,7 @@ class StructPatternElements void strip_etc () { - has_struct_pattern_etc = false; + has_rest_pattern = false; struct_pattern_etc_attrs.clear (); struct_pattern_etc_attrs.shrink_to_fit (); } diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index 149f6b07411..9ebb4d1dd63 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -885,8 +885,9 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern) rust_assert (ok); } - rust_assert (variant->get_variant_type () - == TyTy::VariantDef::VariantType::STRUCT); + rust_assert ( + variant->get_variant_type () == TyTy::VariantDef::VariantType::STRUCT + || variant->get_variant_type () == TyTy::VariantDef::VariantType::TUPLE); auto &struct_pattern_elems = pattern.get_struct_pattern_elems (); for (auto &field : struct_pattern_elems.get_struct_pattern_fields ()) diff --git a/gcc/rust/expand/rust-cfg-strip.cc b/gcc/rust/expand/rust-cfg-strip.cc index 3bc8461c4ff..3c5e74e7aae 100644 --- a/gcc/rust/expand/rust-cfg-strip.cc +++ b/gcc/rust/expand/rust-cfg-strip.cc @@ -2349,7 +2349,7 @@ CfgStrip::visit (AST::StructPattern &pattern) maybe_strip_pointer_allow_strip (elems.get_struct_pattern_fields ()); // assuming you can strip the ".." part - if (elems.has_etc ()) + if (elems.has_rest ()) { expand_cfg_attrs (elems.get_etc_outer_attrs ()); if (fails_cfg_with_expand (elems.get_etc_outer_attrs ())) diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc b/gcc/rust/hir/rust-ast-lower-pattern.cc index a209f80f4da..00d1bc8c33e 100644 --- a/gcc/rust/hir/rust-ast-lower-pattern.cc +++ b/gcc/rust/hir/rust-ast-lower-pattern.cc @@ -121,7 +121,6 @@ ASTLoweringPattern::visit (AST::StructPattern &pattern) = ASTLowerPathInExpression::translate (pattern.get_path ()); auto &raw_elems = pattern.get_struct_pattern_elems (); - rust_assert (!raw_elems.has_etc ()); std::vector> fields; for (auto &field : raw_elems.get_struct_pattern_fields ()) @@ -204,7 +203,8 @@ ASTLoweringPattern::visit (AST::StructPattern &pattern) mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); - HIR::StructPatternElements elems (std::move (fields)); + HIR::StructPatternElements elems ( + std::move (fields), pattern.get_struct_pattern_elems ().has_rest ()); translated = new HIR::StructPattern (mapping, *path, std::move (elems)); } diff --git a/gcc/rust/hir/tree/rust-hir-pattern.h b/gcc/rust/hir/tree/rust-hir-pattern.h index e954aec309f..89b9cc6a06c 100644 --- a/gcc/rust/hir/tree/rust-hir-pattern.h +++ b/gcc/rust/hir/tree/rust-hir-pattern.h @@ -683,6 +683,7 @@ class StructPatternFieldIdent : public StructPatternField class StructPatternElements { std::vector> fields; + bool has_rest_pattern; public: // Returns whether there are any struct pattern fields @@ -692,10 +693,18 @@ class StructPatternElements * no etc). */ bool is_empty () const { return !has_struct_pattern_fields (); } + bool has_rest () const { return has_rest_pattern; } + // Constructor for StructPatternElements with both (potentially) StructPatternElements ( std::vector> fields) - : fields (std::move (fields)) + : fields (std::move (fields)), has_rest_pattern (false) + {} + + StructPatternElements ( + std::vector> fields, + bool has_rest_pattern) + : fields (std::move (fields)), has_rest_pattern (has_rest_pattern) {} // Copy constructor with vector clone @@ -703,7 +712,8 @@ class StructPatternElements { fields.reserve (other.fields.size ()); for (const auto &e : other.fields) - fields.push_back (e->clone_struct_pattern_field ()); + fields.emplace_back (e->clone_struct_pattern_field ()); + has_rest_pattern = other.has_rest_pattern; } // Overloaded assignment operator with vector clone @@ -712,8 +722,8 @@ class StructPatternElements fields.clear (); fields.reserve (other.fields.size ()); for (const auto &e : other.fields) - fields.push_back (e->clone_struct_pattern_field ()); - + fields.emplace_back (e->clone_struct_pattern_field ()); + has_rest_pattern = other.has_rest_pattern; return *this; } diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc index 7aad4ef2730..ce10b02303c 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -2519,10 +2519,29 @@ StructPatternField::as_string () const * just the body */ for (const auto &attr : outer_attrs) { - str += "\n " + attr.as_string (); + str += "\n " + attr.as_string (); } } + str += "\n item type: "; + switch (get_item_type ()) + { + case ItemType::TUPLE_PAT: + str += "TUPLE_PAT"; + break; + case ItemType::IDENT_PAT: + str += "IDENT_PAT"; + break; + case ItemType::IDENT: + str += "IDENT"; + break; + default: + str += "UNKNOWN"; + break; + } + + str += "\n mapping: " + mappings.as_string (); + return str; } diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index c54685d44ba..ec4c1c1d6c7 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -11430,7 +11430,7 @@ Parser::parse_struct_pattern_elems () std::vector> fields; AST::AttrVec etc_attrs; - bool has_etc = false; + bool has_rest = false; // try parsing struct pattern fields const_TokenPtr t = lexer.peek_token (); @@ -11443,7 +11443,7 @@ Parser::parse_struct_pattern_elems () { lexer.skip_token (); etc_attrs = std::move (outer_attrs); - has_etc = true; + has_rest = true; break; } @@ -11468,7 +11468,7 @@ Parser::parse_struct_pattern_elems () t = lexer.peek_token (); } - if (has_etc) + if (has_rest) return AST::StructPatternElements (std::move (fields), std::move (etc_attrs)); else diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc index 5a2dde85e18..e964318bf7c 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc @@ -299,7 +299,30 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) // error[E0532]: expected tuple struct or tuple variant, found struct // variant `Foo::D` - if (variant->get_variant_type () != TyTy::VariantDef::VariantType::STRUCT) + bool error_E0532 = false; + if (variant->get_variant_type () == TyTy::VariantDef::VariantType::TUPLE) + { + // Tuple structs can still be matched with struct patterns via index + // numbers e.g. Foo {0: a, .., 3: b}, so check whether the fields are of + // type TUPLE_PAT. Throw E0532 if not. + auto &struct_pattern_elems = pattern.get_struct_pattern_elems (); + for (auto &field : struct_pattern_elems.get_struct_pattern_fields ()) + { + if (field->get_item_type () + != HIR::StructPatternField::ItemType::TUPLE_PAT) + { + error_E0532 = true; + break; + } + } + } + else if (variant->get_variant_type () + != TyTy::VariantDef::VariantType::STRUCT) + { + error_E0532 = true; + } + + if (error_E0532) { std::string variant_type = TyTy::VariantDef::variant_type_string (variant->get_variant_type ()); @@ -407,7 +430,8 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) // 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 ()) + if (!pattern.get_struct_pattern_elems ().has_rest () + && named_fields.size () != variant->num_fields ()) { std::map missing_names; @@ -507,7 +531,8 @@ TypeCheckPattern::visit (HIR::TuplePattern &pattern) { emit_pattern_size_error (pattern, par.get_fields ().size (), min_size_required); - // TODO attempt to continue to do typechecking even after wrong size + // TODO attempt to continue to do typechecking even after wrong + // size break; } @@ -679,10 +704,11 @@ TypeCheckPattern::visit (HIR::SlicePattern &pattern) if (cap_wi < pattern_min_cap) { - rust_error_at ( - pattern.get_locus (), ErrorCode::E0528, - "pattern requires at least %lu elements but array has %lu", - (unsigned long) pattern_min_cap, (unsigned long) cap_wi); + rust_error_at (pattern.get_locus (), ErrorCode::E0528, + "pattern requires at least %lu elements but " + "array has %lu", + (unsigned long) pattern_min_cap, + (unsigned long) cap_wi); break; } } diff --git a/gcc/testsuite/rust/compile/issue-3929-1.rs b/gcc/testsuite/rust/compile/issue-3929-1.rs new file mode 100644 index 00000000000..3d7b0568b55 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3929-1.rs @@ -0,0 +1,9 @@ +// { dg-options "-w" } +struct S(); + +fn main() { + let s = S{}; + match s { + S{..} => {} + } +} diff --git a/gcc/testsuite/rust/compile/issue-3929-2.rs b/gcc/testsuite/rust/compile/issue-3929-2.rs new file mode 100644 index 00000000000..5f45a7c050a --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3929-2.rs @@ -0,0 +1,12 @@ +// { dg-options "-w" } +struct S { + x: i32, + y: i32, +} + +fn main() { + let s = S{x: 1, y: 2}; + match s { + S{x: 1, ..} => {} + } +}