https://gcc.gnu.org/g:7b203f66c1302c8783cf76b2b7604377073d0541

commit 7b203f66c1302c8783cf76b2b7604377073d0541
Author: Robert Goss <goss.rob...@gmail.com>
Date:   Sun Jan 14 17:34:22 2024 +0000

    Add improved error when no fields in initializer
    
    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 <goss.rob...@gmail.com>

Diff:
---
 gcc/rust/typecheck/rust-hir-type-check-expr.cc     | 18 ++++++++
 .../typecheck/rust-hir-type-check-struct-field.h   |  9 ++++
 gcc/rust/typecheck/rust-hir-type-check-struct.cc   | 48 ++++++++++++++++++++--
 .../rust/compile/missing_constructor_fields.rs     |  6 ++-
 4 files changed, 76 insertions(+), 5 deletions(-)

diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc 
b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index 563cecbf606a..b4a8b0943a01 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -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;
 }
 
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 c1d722978f47..df7f142df310 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h
@@ -25,6 +25,9 @@
 #include "rust-tyty.h"
 
 namespace Rust {
+
+struct Error;
+
 namespace Resolver {
 
 class TypeCheckStructExpr : public TypeCheckBase
@@ -32,6 +35,12 @@ 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);
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct.cc 
b/gcc/rust/typecheck/rust-hir-type-check-struct.cc
index 06b655184c15..4ebcd5f3a755 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-struct.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-struct.cc
@@ -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 ())
        {
@@ -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
@@ -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
diff --git a/gcc/testsuite/rust/compile/missing_constructor_fields.rs 
b/gcc/testsuite/rust/compile/missing_constructor_fields.rs
index 9d492101fbd5..6e3965b56870 100644
--- a/gcc/testsuite/rust/compile/missing_constructor_fields.rs
+++ b/gcc/testsuite/rust/compile/missing_constructor_fields.rs
@@ -6,5 +6,7 @@ struct Foo {
 }
 
 fn main() {
-    let x = Foo { x: 0 , y:1 }; // { dg-error "constructor is missing fields" }
-}
\ No newline at end of file
+    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'" }
+}

Reply via email to