Hi,

This patch fixes an ICE in the middle-end caused by the D front-end's
code generation for the special enum representing native complex types.

Because complex types are deprecated in the language, the new way to
expose native complex types is by defining an enum with a basetype of a
library-defined struct that is implicitly treated as-if it is native.
As casts are not implicitly added by the front-end when downcasting from
enum to its underlying type, we must insert an explicit cast during the
code generation pass.

Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32,
committed to mainline and backported to the releases/gcc-12 branch.

Regards,
Iain.

---
        PR d/106623

gcc/d/ChangeLog:

        * d-codegen.cc (underlying_complex_expr): New function.
        (d_build_call): Handle passing native complex objects as the
        library-defined equivalent.
        * d-tree.h (underlying_complex_expr): Declare.
        * expr.cc (ExprVisitor::visit (DotVarExp *)): Call
        underlying_complex_expr instead of build_vconvert.

gcc/testsuite/ChangeLog:

        * gdc.dg/torture/pr106623.d: New test.
---
 gcc/d/d-codegen.cc                      | 34 +++++++++++++++++++++++++
 gcc/d/d-tree.h                          |  1 +
 gcc/d/expr.cc                           |  2 +-
 gcc/testsuite/gdc.dg/torture/pr106623.d | 28 ++++++++++++++++++++
 4 files changed, 64 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gdc.dg/torture/pr106623.d

diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index d02da1f81e3..aa6bc9e53e4 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -1588,6 +1588,32 @@ complex_expr (tree type, tree re, tree im)
                          type, re, im);
 }
 
+/* Build a two-field record TYPE representing the complex expression EXPR.  */
+
+tree
+underlying_complex_expr (tree type, tree expr)
+{
+  gcc_assert (list_length (TYPE_FIELDS (type)) == 2);
+
+  expr = d_save_expr (expr);
+
+  /* Build a constructor from the real and imaginary parts.  */
+  if (COMPLEX_FLOAT_TYPE_P (TREE_TYPE (expr)) &&
+      (!INDIRECT_REF_P (expr)
+       || !CONVERT_EXPR_CODE_P (TREE_CODE (TREE_OPERAND (expr, 0)))))
+    {
+      vec <constructor_elt, va_gc> *ve = NULL;
+      CONSTRUCTOR_APPEND_ELT (ve, TYPE_FIELDS (type),
+                    real_part (expr));
+      CONSTRUCTOR_APPEND_ELT (ve, TREE_CHAIN (TYPE_FIELDS (type)),
+                    imaginary_part (expr));
+      return build_constructor (type, ve);
+    }
+
+  /* Replace type in the reinterpret cast with a cast to the record type.  */
+  return build_vconvert (type, expr);
+}
+
 /* Cast EXP (which should be a pointer) to TYPE* and then indirect.
    The back-end requires this cast in many cases.  */
 
@@ -2214,6 +2240,14 @@ d_build_call (TypeFunction *tf, tree callable, tree 
object,
                              build_address (targ));
            }
 
+         /* Complex types are exposed as special types with an underlying
+            struct representation, if we are passing the native type to a
+            function that accepts the library-defined version, then ensure
+            it is properly reinterpreted as the underlying struct type.  */
+         if (COMPLEX_FLOAT_TYPE_P (TREE_TYPE (targ))
+             && arg->type->isTypeStruct ())
+           targ = underlying_complex_expr (build_ctype (arg->type), targ);
+
          /* Type `noreturn` is a terminator, as no other arguments can possibly
             be evaluated after it.  */
          if (TREE_TYPE (targ) == noreturn_type_node)
diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h
index c3e95e4d2d2..809a242ea93 100644
--- a/gcc/d/d-tree.h
+++ b/gcc/d/d-tree.h
@@ -576,6 +576,7 @@ extern tree size_mult_expr (tree, tree);
 extern tree real_part (tree);
 extern tree imaginary_part (tree);
 extern tree complex_expr (tree, tree, tree);
+extern tree underlying_complex_expr (tree, tree);
 extern tree indirect_ref (tree, tree);
 extern tree build_deref (tree);
 extern tree build_pointer_index (tree, tree);
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 40c2689a3b9..140df7ee41d 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -1892,7 +1892,7 @@ public:
               underlying is really a complex type.  */
            if (e->e1->type->ty == TY::Tenum
                && e->e1->type->isTypeEnum ()->sym->isSpecial ())
-             object = build_vconvert (build_ctype (tb), object);
+             object = underlying_complex_expr (build_ctype (tb), object);
 
            this->result_ = component_ref (object, get_symbol_decl (vd));
          }
diff --git a/gcc/testsuite/gdc.dg/torture/pr106623.d 
b/gcc/testsuite/gdc.dg/torture/pr106623.d
new file mode 100644
index 00000000000..d782b236861
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/torture/pr106623.d
@@ -0,0 +1,28 @@
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106623
+// { dg-do compile }
+private struct _Complex(T) { T re; T im; }
+enum __c_complex_double : _Complex!double;
+
+pragma(inline, true)
+ulong hashOf()(scope const double val)
+{
+    return *cast(ulong*)&val;
+}
+
+pragma(inline, true)
+ulong hashOf()(scope const _Complex!double val, ulong seed = 0)
+{
+    return hashOf(val.re) + hashOf(val.im);
+}
+
+pragma(inline, true)
+ulong hashOf()(__c_complex_double val, ulong seed = 0)
+{
+    return hashOf(cast(_Complex!double) val, seed);
+}
+
+ulong test106623()
+{
+    __c_complex_double val;
+    return hashOf(val);
+}
-- 
2.34.1

Reply via email to