diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h index df084f470ce9..c1d722978f47 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h +++ b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h @@ -35,9 +35,9 @@ class TypeCheckStructExpr : public TypeCheckBase protected: void resolve (HIR::StructExprStructFields &struct_expr); - void visit (HIR::StructExprFieldIdentifierValue &field); - void visit (HIR::StructExprFieldIndexValue &field); - void visit (HIR::StructExprFieldIdentifier &field); + bool visit (HIR::StructExprFieldIdentifierValue &field); + bool visit (HIR::StructExprFieldIndexValue &field); + bool visit (HIR::StructExprFieldIdentifier &field); private: TypeCheckStructExpr (HIR::Expr *e); diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct.cc b/gcc/rust/typecheck/rust-hir-type-check-struct.cc index 7a7c5cf4108c..50239b3527e7 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-struct.cc @@ -102,16 +102,23 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr) switch (field->get_kind ()) { case HIR::StructExprField::StructExprFieldKind::IDENTIFIER: - visit (static_cast (*field.get ())); + ok = visit ( + static_cast (*field.get ())); break; case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE: - visit ( + ok = visit ( static_cast (*field.get ())); break; case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE: - visit (static_cast (*field.get ())); + ok = visit ( + static_cast (*field.get ())); + break; + } + + if (!ok) + { break; } @@ -238,16 +245,9 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr) resolved = struct_def; } -void +bool TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field) { - auto it = fields_assigned.find (field.field_name.as_string ()); - if (it != fields_assigned.end ()) - { - rust_fatal_error (field.get_locus (), "used more than once"); - return; - } - size_t field_index; TyTy::StructFieldType *field_type; bool ok = variant->lookup_field (field.field_name.as_string (), &field_type, @@ -255,7 +255,20 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field) if (!ok) { rust_error_at (field.get_locus (), "unknown field"); - return; + return false; + } + + auto it = adtFieldIndexToField.find (field_index); + if (it != adtFieldIndexToField.end ()) + { + rich_location repeat_location (line_table, field.get_locus ()); + auto prev_field_locus = it->second->get_locus (); + repeat_location.add_range (prev_field_locus); + + rust_error_at (repeat_location, ErrorCode::E0062, + "field %<%s%> specified more than once", + field.field_name.as_string ().c_str ()); + return false; } TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ().get ()); @@ -273,18 +286,14 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field) fields_assigned.insert (field.field_name.as_string ()); adtFieldIndexToField[field_index] = &field; } + + return true; } -void +bool TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field) { std::string field_name (std::to_string (field.get_tuple_index ())); - auto it = fields_assigned.find (field_name); - if (it != fields_assigned.end ()) - { - rust_fatal_error (field.get_locus (), "used more than once"); - return; - } size_t field_index; TyTy::StructFieldType *field_type; @@ -292,7 +301,20 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field) if (!ok) { rust_error_at (field.get_locus (), "unknown field"); - return; + return false; + } + + auto it = adtFieldIndexToField.find (field_index); + if (it != adtFieldIndexToField.end ()) + { + rich_location repeat_location (line_table, field.get_locus ()); + auto prev_field_locus = it->second->get_locus (); + repeat_location.add_range (prev_field_locus); + + rust_error_at (repeat_location, ErrorCode::E0062, + "field %<%s%> specified more than once", + field_name.c_str ()); + return false; } TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ().get ()); @@ -310,18 +332,13 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field) fields_assigned.insert (field_name); adtFieldIndexToField[field_index] = &field; } + + return true; } -void +bool TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field) { - auto it = fields_assigned.find (field.get_field_name ().as_string ()); - if (it != fields_assigned.end ()) - { - rust_fatal_error (field.get_locus (), "used more than once"); - return; - } - size_t field_index; TyTy::StructFieldType *field_type; bool ok = variant->lookup_field (field.get_field_name ().as_string (), @@ -329,7 +346,20 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field) if (!ok) { rust_error_at (field.get_locus (), "unknown field"); - return; + return false; + } + + auto it = adtFieldIndexToField.find (field_index); + if (it != adtFieldIndexToField.end ()) + { + rich_location repeat_location (line_table, field.get_locus ()); + auto prev_field_locus = it->second->get_locus (); + repeat_location.add_range (prev_field_locus); + + rust_error_at (repeat_location, ErrorCode::E0062, + "field %<%s%> specified more than once", + field.get_field_name ().as_string ().c_str ()); + return false; } // we can make the field look like a path expr to take advantage of existing @@ -358,6 +388,8 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field) fields_assigned.insert (field.get_field_name ().as_string ()); adtFieldIndexToField[field_index] = &field; } + + return true; } } // namespace Resolver diff --git a/gcc/testsuite/rust/compile/repeated_constructor_fields.rs b/gcc/testsuite/rust/compile/repeated_constructor_fields.rs new file mode 100644 index 000000000000..729001b6e3cd --- /dev/null +++ b/gcc/testsuite/rust/compile/repeated_constructor_fields.rs @@ -0,0 +1,10 @@ +struct Foo { + x: i32, +} + +fn main() { + let x = Foo { + x: 0, + x: 0, // { dg-error "field 'x' specified more than once" } + }; +}