diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index d02da1f81e356a6f2bedcf72b1be1f7ea7058aec..aa6bc9e53e499206247db5a431decf6a5bcaf413 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 c3e95e4d2d2cdd43cfc762b89b5f0776802c5519..809a242ea93db2dc7c2a34e54cf0c9803c0fcfd6 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 40c2689a3b9f66d5b6775a8d583d60fc8f9c51d9..140df7ee41d762995c66a73309b2d7a9721724b9 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 0000000000000000000000000000000000000000..d782b236861917b35935cf763eb4689715773cd4 --- /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); +}