Skip to content

Commit

Permalink
Add improved error when no fields in initializer
Browse files Browse the repository at this point in the history
If a struct type with a variant that has fields is initialized with some fields the expression  HIR StructExprStructFields is checked that all the fields are assigned. However, if no fields are initialized the HIR StructExprStruct is generated. This doesn't check if the struct is a unit during typechekc and only fails at the compile stage with a ICE.

Add a check at the typecheck stage that makes sure the struct does not have a variant with fields and give an error message based on the rustc one.

We have also updated the message given in the case where one field was present to list the missing fields and match more closely the new message.

gcc/rust/ChangeLog:

	* typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit) Add additional check
	* typecheck/rust-hir-type-check-struct-field.h: A helper method to make error added
	* typecheck/rust-hir-type-check-struct.cc (TypeCheckStructExpr::resolve) Update message

gcc/testsuite/ChangeLog:

	* rust/compile/missing_constructor_fields.rs: Added case with no initializers

Signed-off-by: Robert Goss <[email protected]>
  • Loading branch information
robertgoss authored and CohenArthur committed Jan 23, 2024
1 parent 1586de8 commit 7b203f6
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 5 deletions.
18 changes: 18 additions & 0 deletions gcc/rust/typecheck/rust-hir-type-check-expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,24 @@ TypeCheckExpr::visit (HIR::StructExprStruct &struct_expr)
return;
}

TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_path_ty);
for (auto variant : adt->get_variants ())
{
if (!variant->get_fields ().empty ())
{
std::vector<std::string> field_names;
for (auto &field : variant->get_fields ())
field_names.push_back (field->get_name ());
Error missing_fields_error
= TypeCheckStructExpr::make_missing_field_error (
struct_expr.get_locus (), field_names,
struct_path_ty->get_name ());
// We might want to return or handle these in the future emit for now.
missing_fields_error.emit ();
return;
}
}

infered = struct_path_ty;
}

Expand Down
9 changes: 9 additions & 0 deletions gcc/rust/typecheck/rust-hir-type-check-struct-field.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,22 @@
#include "rust-tyty.h"

namespace Rust {

struct Error;

namespace Resolver {

class TypeCheckStructExpr : public TypeCheckBase
{
public:
static TyTy::BaseType *Resolve (HIR::StructExprStructFields *expr);

// Helper for making any errors
static Error
make_missing_field_error (location_t locus,
const std::vector<std::string> &missing_field_names,
const std::string &struct_name);

protected:
void resolve (HIR::StructExprStructFields &struct_expr);

Expand Down
48 changes: 45 additions & 3 deletions gcc/rust/typecheck/rust-hir-type-check-struct.cc
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,16 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr)
}

// check the arguments are all assigned and fix up the ordering
if (fields_assigned.size () != variant->num_fields ())
std::vector<std::string> missing_field_names;
for (auto &field : variant->get_fields ())
{
auto it = fields_assigned.find (field->get_name ());
if (it == fields_assigned.end ())
{
missing_field_names.push_back (field->get_name ());
}
}
if (!missing_field_names.empty ())
{
if (struct_def->is_union ())
{
Expand All @@ -156,8 +165,12 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr)
}
else if (!struct_expr.has_struct_base ())
{
rust_error_at (struct_expr.get_locus (), ErrorCode::E0063,
"constructor is missing fields");
Error missing_fields_error
= make_missing_field_error (struct_expr.get_locus (),
missing_field_names,
struct_path_ty->get_name ());
// We might want to return or handle these in the future emit for now.
missing_fields_error.emit ();
return;
}
else
Expand Down Expand Up @@ -392,5 +405,34 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field)
return true;
}

Error
TypeCheckStructExpr::make_missing_field_error (
location_t locus, const std::vector<std::string> &missing_field_names,
const std::string &struct_name)
{
// Message plurality depends on size
if (missing_field_names.size () == 1)
{
return Error (locus, ErrorCode::E0063,
"missing field %s in initializer of %qs",
missing_field_names[0].c_str (), struct_name.c_str ());
}
// Make comma separated string for display
std::stringstream display_field_names;
bool first = true;
for (auto &name : missing_field_names)
{
if (!first)
{
display_field_names << ", ";
}
first = false;
display_field_names << name;
}
return Error (locus, ErrorCode::E0063,
"missing fields %s in initializer of %qs",
display_field_names.str ().c_str (), struct_name.c_str ());
}

} // namespace Resolver
} // namespace Rust
6 changes: 4 additions & 2 deletions gcc/testsuite/rust/compile/missing_constructor_fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ struct Foo {
}

fn main() {
let x = Foo { x: 0 , y:1 }; // { dg-error "constructor is missing fields" }
}
let z = Foo { x: 0 , y:1 }; // { dg-error "missing field z in initializer of 'Foo'" }
let xz = Foo { y:1 }; // { dg-error "missing fields x, z in initializer of 'Foo'" }
let xyz = Foo { }; // { dg-error "missing fields x, y, z in initializer of 'Foo'" }
}

0 comments on commit 7b203f6

Please sign in to comment.