]> gcc.gnu.org Git - gcc.git/commitdiff
Add improved error when no fields in initializer
authorRobert Goss <goss.robert@gmail.com>
Sun, 14 Jan 2024 17:34:22 +0000 (17:34 +0000)
committerCohenArthur <arthur.cohen@embecosm.com>
Tue, 23 Jan 2024 16:13:10 +0000 (16:13 +0000)
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.robert@gmail.com>
gcc/rust/typecheck/rust-hir-type-check-expr.cc
gcc/rust/typecheck/rust-hir-type-check-struct-field.h
gcc/rust/typecheck/rust-hir-type-check-struct.cc
gcc/testsuite/rust/compile/missing_constructor_fields.rs

index 563cecbf606a66f3fe88a4bd644d9cf6bc1c4ca8..b4a8b0943a019511cbde0f7a328c2e9bfcf37816 100644 (file)
@@ -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;
 }
 
index c1d722978f47e6f600bc8802e950b8d50a6bf9fe..df7f142df3102f90becb9a1cc25e6ea5eeade640 100644 (file)
@@ -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);
 
index 06b655184c152e5be2adc468a68183dcc09ec448..4ebcd5f3a75530583c41d9d97f9aaa7a47f97f12 100644 (file)
@@ -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
index 9d492101fbd58e56f369df7a5869e441a6a30ee2..6e3965b56870a953895a66c98f5ae60efad6fb30 100644 (file)
@@ -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'" }
+}
This page took 0.067945 seconds and 5 git commands to generate.