]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
d: Fix ICE in must_pass_in_stack_var_size_or_pad with D enums [PR123411] master trunk
authorIain Buclaw <ibuclaw@gdcproject.org>
Mon, 20 Apr 2026 17:54:02 +0000 (19:54 +0200)
committerIain Buclaw <ibuclaw@gdcproject.org>
Mon, 20 Apr 2026 18:34:13 +0000 (20:34 +0200)
An `enum : enum A` type caused the already computed underlying type size
of `enum A` to be overwritten with NULL_TREE.  To fix, don't finish the
enum with layout_type unless we're handling the main variant type.

PR d/123411

gcc/d/ChangeLog:

* types.cc (TypeVisitor::visit (TypeEnum *)): Only call layout_type on
the TYPE_MAIN_VARIANT of the enum.

gcc/testsuite/ChangeLog:

* gdc.dg/pr123411.d: New test.

gcc/d/types.cc
gcc/testsuite/gdc.dg/pr123411.d [new file with mode: 0644]

index 81d02eb7c6bde584bb186240a381fbdc0fbee0fe..b5658b6e8f405d4434dd05cf2794d2faf75cf64e 100644 (file)
@@ -1181,33 +1181,35 @@ public:
     /* Finish the enumeration type.  */
     if (TREE_CODE (t->ctype) == ENUMERAL_TYPE)
       {
-       TYPE_MIN_VALUE (t->ctype) = TYPE_MIN_VALUE (basetype);
-       TYPE_MAX_VALUE (t->ctype) = TYPE_MAX_VALUE (basetype);
-       TYPE_UNSIGNED (t->ctype) = TYPE_UNSIGNED (basetype);
-       SET_TYPE_ALIGN (t->ctype, TYPE_ALIGN (basetype));
-       TYPE_SIZE (t->ctype) = NULL_TREE;
-       TYPE_PRECISION (t->ctype) = dmd::size (t, t->sym->loc) * 8;
+       tree type = TYPE_MAIN_VARIANT (t->ctype);
 
-       layout_type (t->ctype);
+       if (type == t->ctype)
+         {
+           TYPE_MIN_VALUE (type) = TYPE_MIN_VALUE (basetype);
+           TYPE_MAX_VALUE (type) = TYPE_MAX_VALUE (basetype);
+           TYPE_UNSIGNED (type) = TYPE_UNSIGNED (basetype);
+           SET_TYPE_ALIGN (type, TYPE_ALIGN (basetype));
+           TYPE_SIZE (type) = NULL_TREE;
+           TYPE_PRECISION (type) = dmd::size (t, t->sym->loc) * 8;
+
+           layout_type (type);
+         }
 
        /* Fix up all forward-referenced variants of this enum type.  */
-       for (tree v = TYPE_MAIN_VARIANT (t->ctype); v;
-            v = TYPE_NEXT_VARIANT (v))
+       for (tree variant = TYPE_NEXT_VARIANT (type); variant;
+            variant = TYPE_NEXT_VARIANT (variant))
          {
-           if (v == t->ctype)
-             continue;
-
-           TYPE_VALUES (v) = TYPE_VALUES (t->ctype);
-           TYPE_LANG_SPECIFIC (v) = TYPE_LANG_SPECIFIC (t->ctype);
-           TYPE_MIN_VALUE (v) = TYPE_MIN_VALUE (t->ctype);
-           TYPE_MAX_VALUE (v) = TYPE_MAX_VALUE (t->ctype);
-           TYPE_UNSIGNED (v) = TYPE_UNSIGNED (t->ctype);
-           TYPE_SIZE (v) = TYPE_SIZE (t->ctype);
-           TYPE_SIZE_UNIT (v) = TYPE_SIZE_UNIT (t->ctype);
-           SET_TYPE_MODE (v, TYPE_MODE (t->ctype));
-           TYPE_PRECISION (v) = TYPE_PRECISION (t->ctype);
-           SET_TYPE_ALIGN (v, TYPE_ALIGN (t->ctype));
-           TYPE_USER_ALIGN (v) = TYPE_USER_ALIGN (t->ctype);
+           TYPE_VALUES (variant) = TYPE_VALUES (type);
+           TYPE_LANG_SPECIFIC (variant) = TYPE_LANG_SPECIFIC (type);
+           TYPE_MIN_VALUE (variant) = TYPE_MIN_VALUE (type);
+           TYPE_MAX_VALUE (variant) = TYPE_MAX_VALUE (type);
+           TYPE_UNSIGNED (variant) = TYPE_UNSIGNED (type);
+           TYPE_SIZE (variant) = TYPE_SIZE (type);
+           TYPE_SIZE_UNIT (variant) = TYPE_SIZE_UNIT (type);
+           SET_TYPE_MODE (variant, TYPE_MODE (type));
+           TYPE_PRECISION (variant) = TYPE_PRECISION (type);
+           SET_TYPE_ALIGN (variant, TYPE_ALIGN (type));
+           TYPE_USER_ALIGN (variant) = TYPE_USER_ALIGN (type);
          }
 
        /* Complete forward-referenced fields of this enum type.  */
diff --git a/gcc/testsuite/gdc.dg/pr123411.d b/gcc/testsuite/gdc.dg/pr123411.d
new file mode 100644 (file)
index 0000000..4ff25fd
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile }
+module object;
+enum E
+{
+    unknown
+}
+enum : E
+{
+    E_UNKNOWN
+}
+
+E test()
+{
+    return E.unknown;
+}