]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Fix empty struct constructors causing ICE during type checking
authorYap Zhi Heng <yapzhhg@gmail.com>
Sun, 28 Dec 2025 13:03:13 +0000 (21:03 +0800)
committerArthur Cohen <arthur.cohen@embecosm.com>
Fri, 16 Jan 2026 16:32:08 +0000 (17:32 +0100)
gcc/rust/ChangeLog:

* typecheck/rust-hir-type-check-expr.cc (visit(StructExprStruct)): Update to properly
unwrap enum variants for type checking.
* typecheck/rust-tyty.cc (VariantDef::get_fields) : Remove NUM assert.
* backend/rust-compile-expr.cc: Update to properly unwrap enum variants for type
resolution checking.

Signed-off-by: Yap Zhi Heng <yapzhhg@gmail.com>
gcc/rust/backend/rust-compile-expr.cc
gcc/rust/typecheck/rust-hir-type-check-expr.cc
gcc/rust/typecheck/rust-tyty.cc
gcc/testsuite/rust/compile/issue-4163-2.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/issue-4163.rs [new file with mode: 0644]

index 7c4cc4a1d213710fc08ab9add33d211f61e08bea..40bd2829f6501bca66c750926fe8627571f0ec87 100644 (file)
@@ -499,7 +499,25 @@ CompileExpr::visit (HIR::StructExprStruct &struct_expr)
       return;
     }
 
-  rust_assert (tyty->is_unit ());
+  TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
+  TyTy::VariantDef *variant = nullptr;
+  if (adt->is_enum ())
+    {
+      // unwrap variant and ensure that it can be resolved
+      HirId variant_id;
+      bool ok = ctx->get_tyctx ()->lookup_variant_definition (
+       struct_expr.get_struct_name ().get_mappings ().get_hirid (),
+       &variant_id);
+      rust_assert (ok);
+
+      ok = adt->lookup_variant_by_id (variant_id, &variant);
+      rust_assert (ok);
+    }
+  else
+    {
+      rust_assert (tyty->is_unit ());
+    }
+
   translated = unit_expression (struct_expr.get_locus ());
 }
 
index 089a406273216fba944c67c8a4521a169134b587..327144f3f9f197ce5918d4f859c0656862b1b72e 100644 (file)
@@ -1187,31 +1187,56 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr)
 void
 TypeCheckExpr::visit (HIR::StructExprStruct &struct_expr)
 {
-  TyTy::BaseType *struct_path_ty
-    = TypeCheckExpr::Resolve (struct_expr.get_struct_name ());
+  HIR::PathInExpression &path = struct_expr.get_struct_name ();
+
+  TyTy::BaseType *struct_path_ty = TypeCheckExpr::Resolve (path);
   if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
     {
-      rust_error_at (struct_expr.get_struct_name ().get_locus (),
-                    "expected an ADT type for constructor");
+      rust_error_at (path.get_locus (), "expected an ADT type for constructor");
       return;
     }
 
   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_path_ty);
-  for (auto variant : adt->get_variants ())
+  TyTy::VariantDef *variant;
+
+  // unwrap and type check the variant if it's an enum
+  if (adt->is_enum ())
     {
-      if (!variant->get_fields ().empty ())
+      HirId variant_id;
+      bool ok = context->lookup_variant_definition (
+       struct_expr.get_struct_name ().get_mappings ().get_hirid (),
+       &variant_id);
+      if (!ok)
        {
-         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 ();
+         rich_location r (line_table, struct_expr.get_locus ());
+         r.add_range (struct_expr.get_struct_name ().get_locus ());
+         rust_error_at (
+           struct_expr.get_struct_name ().get_locus (), ErrorCode::E0574,
+           "expected a struct, variant or union type, found enum %qs",
+           adt->get_name ().c_str ());
          return;
        }
+
+      ok = adt->lookup_variant_by_id (variant_id, &variant);
+      rust_assert (ok);
+    }
+  else
+    {
+      rust_assert (adt->number_of_variants () == 1);
+      variant = adt->get_variants ().at (0);
+    }
+
+  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 4f7beb70c5b8a66f3e68d3fcaa45cb549bd7cd39..161c15e7896044c06133ec250ad99403b010d47c 100644 (file)
@@ -1604,7 +1604,6 @@ VariantDef::get_field_at_index (size_t index)
 std::vector<StructFieldType *> &
 VariantDef::get_fields ()
 {
-  rust_assert (type != NUM);
   return fields;
 }
 
diff --git a/gcc/testsuite/rust/compile/issue-4163-2.rs b/gcc/testsuite/rust/compile/issue-4163-2.rs
new file mode 100644 (file)
index 0000000..c36b669
--- /dev/null
@@ -0,0 +1,10 @@
+enum Enum {
+    NotEmpty {x: i32},
+    Struct {},
+    Tuple (),
+}
+
+fn main() {
+    Enum::Struct {};
+    Enum::Tuple {};
+}
\ No newline at end of file
diff --git a/gcc/testsuite/rust/compile/issue-4163.rs b/gcc/testsuite/rust/compile/issue-4163.rs
new file mode 100644 (file)
index 0000000..fde5bcc
--- /dev/null
@@ -0,0 +1,9 @@
+enum Enum {
+    Unit,
+    Tuple(i32),
+    Struct { x: i32 },
+}
+
+fn main() {
+    Enum::Unit {};
+}
\ No newline at end of file