From 77a30e9a5f8ffbf06702de86d9b58e075d1ddc71 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 27 Apr 2011 21:53:53 -0400 Subject: [PATCH] re PR libstdc++/48760 (std::complex constructor buggy in the face of NaN's) PR libstdc++/48760 Implement list-initialization of _Complex. * decl.c (reshape_init_r): Allow {real,imag} for _Complex. (check_initializer): Likewise. * call.c (build_complex_conv): New. (implicit_conversion): Call it. (convert_like_real): Handle it. * typeck2.c (check_narrowing): Handle it. From-SVN: r173058 --- gcc/cp/ChangeLog | 9 ++++ gcc/cp/call.c | 62 ++++++++++++++++++++++++++ gcc/cp/decl.c | 23 +++++++++- gcc/cp/typeck2.c | 10 +++++ gcc/testsuite/ChangeLog | 2 + gcc/testsuite/g++.dg/ext/complex8.C | 67 +++++++++++++++++++++++++++++ 6 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/ext/complex8.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0f1816709c5..e1afe47ecea 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,14 @@ 2011-04-27 Jason Merrill + PR libstdc++/48760 + Implement list-initialization of _Complex. + * decl.c (reshape_init_r): Allow {real,imag} for _Complex. + (check_initializer): Likewise. + * call.c (build_complex_conv): New. + (implicit_conversion): Call it. + (convert_like_real): Handle it. + * typeck2.c (check_narrowing): Handle it. + * init.c (build_vec_delete_1): Look for sfk_deleting_destructor to decide whether to delete. (build_vec_init): Pass sfk_complete_destructor. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 10efd1cdfdc..dcc38595a10 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -847,6 +847,49 @@ build_array_conv (tree type, tree ctor, int flags) return c; } +/* Represent a conversion from CTOR, a braced-init-list, to TYPE, a + complex type, if such a conversion is possible. */ + +static conversion * +build_complex_conv (tree type, tree ctor, int flags) +{ + conversion *c; + unsigned HOST_WIDE_INT len = CONSTRUCTOR_NELTS (ctor); + tree elttype = TREE_TYPE (type); + unsigned i; + tree val; + bool bad = false; + bool user = false; + enum conversion_rank rank = cr_exact; + + if (len != 2) + return NULL; + + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), i, val) + { + conversion *sub + = implicit_conversion (elttype, TREE_TYPE (val), val, + false, flags); + if (sub == NULL) + return NULL; + + if (sub->rank > rank) + rank = sub->rank; + if (sub->user_conv_p) + user = true; + if (sub->bad_p) + bad = true; + } + + c = alloc_conversion (ck_aggr); + c->type = type; + c->rank = rank; + c->user_conv_p = user; + c->bad_p = bad; + c->u.next = NULL; + return c; +} + /* Build a representation of the identity conversion from EXPR to itself. The TYPE should match the type of EXPR, if EXPR is non-NULL. */ @@ -1646,6 +1689,14 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p, if (is_std_init_list (to)) return build_list_conv (to, expr, flags); + /* As an extension, allow list-initialization of _Complex. */ + if (TREE_CODE (to) == COMPLEX_TYPE) + { + conv = build_complex_conv (to, expr, flags); + if (conv) + return conv; + } + /* Allow conversion from an initializer-list with one element to a scalar type. */ if (SCALAR_TYPE_P (to)) @@ -5516,6 +5567,17 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, } case ck_aggr: + if (TREE_CODE (totype) == COMPLEX_TYPE) + { + tree real = CONSTRUCTOR_ELT (expr, 0)->value; + tree imag = CONSTRUCTOR_ELT (expr, 1)->value; + real = perform_implicit_conversion (TREE_TYPE (totype), + real, complain); + imag = perform_implicit_conversion (TREE_TYPE (totype), + imag, complain); + expr = build2 (COMPLEX_EXPR, totype, real, imag); + return fold_if_not_in_template (expr); + } return get_target_expr (digest_init (totype, expr)); default: diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index ccc5fd018c9..5bf637e507d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5058,6 +5058,27 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p) if (error_operand_p (init)) return error_mark_node; + if (TREE_CODE (type) == COMPLEX_TYPE) + { + /* A complex type can be initialized from one or two initializers, + but braces are not elided. */ + d->cur++; + if (BRACE_ENCLOSED_INITIALIZER_P (init)) + { + if (CONSTRUCTOR_NELTS (init) > 2) + error ("too many initializers for %qT", type); + } + else if (first_initializer_p && d->cur != d->end) + { + VEC(constructor_elt, gc) *v = 0; + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, d->cur->value); + d->cur++; + init = build_constructor (init_list_type_node, v); + } + return init; + } + /* A non-aggregate type is always initialized with a single initializer. */ if (!CP_AGGREGATE_TYPE_P (type)) @@ -5325,7 +5346,7 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); init = build_zero_init (type, NULL_TREE, false); } - else if (init_len != 1) + else if (init_len != 1 && TREE_CODE (type) != COMPLEX_TYPE) { error ("scalar object %qD requires one element in initializer", decl); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 5522868df9c..aec54f9d07f 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -728,6 +728,16 @@ check_narrowing (tree type, tree init) if (!ARITHMETIC_TYPE_P (type)) return; + if (BRACE_ENCLOSED_INITIALIZER_P (init) + && TREE_CODE (type) == COMPLEX_TYPE) + { + tree elttype = TREE_TYPE (type); + check_narrowing (elttype, CONSTRUCTOR_ELT (init, 0)->value); + if (CONSTRUCTOR_NELTS (init) > 1) + check_narrowing (elttype, CONSTRUCTOR_ELT (init, 1)->value); + return; + } + init = maybe_constant_value (init); if (TREE_CODE (type) == INTEGER_TYPE diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 73060c0a9b4..9604518f190 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,7 @@ 2011-04-27 Jason Merrill + * g++.dg/ext/complex8.C: New. + * g++.dg/cpp0x/initlist49.C: New. * g++.dg/init/new30.C: New. diff --git a/gcc/testsuite/g++.dg/ext/complex8.C b/gcc/testsuite/g++.dg/ext/complex8.C new file mode 100644 index 00000000000..9b8ac1b186f --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/complex8.C @@ -0,0 +1,67 @@ +// PR libstdc++/48760 +// { dg-options -std=c++0x } +// { dg-do run } + +constexpr _Complex int i{1,2}; +constexpr _Complex int j{3}; + +#define SA(X) static_assert((X),#X) + +SA(__real i == 1); +SA(__imag i == 2); +SA(__real j == 3); +SA(__imag j == 0); + +struct A +{ + _Complex int c; + constexpr A(int i, int j): c{i,j} { } + constexpr A(int i): c{i} { } +}; + +constexpr A a1(1,2); +constexpr A a2(3); + +SA(__real a1.c == 1); +SA(__imag a1.c == 2); +SA(__real a2.c == 3); +SA(__imag a2.c == 0); + +typedef _Complex int ci; + +SA((__real ci{1,2} == 1)); +SA((__imag ci{1,2} == 2)); +SA((__real ci{3} == 3)); +SA((__imag ci{3} == 0)); + +struct B +{ + _Complex int c; + int i; +}; + +constexpr B b1 = { { 1,2 }, 42 }; +constexpr B b2 = { { 3 }, 24 }; +// No brace elision for complex. +constexpr B b3 = { 5, 6 }; + +SA(__real b1.c == 1); +SA(__imag b1.c == 2); +SA(b1.i == 42); +SA(__real b2.c == 3); +SA(__imag b2.c == 0); +SA(b2.i == 24); +SA(__real b3.c == 5); +SA(__imag b3.c == 0); +SA(b3.i == 6); + +int main() +{ + ci* p = new ci{1,2}; + if (__real *p != 1 || __imag *p != 2) + return 1; + delete p; + p = new ci{3}; + if (__real *p != 3 || __imag *p != 0) + return 1; +} -- 2.30.2