aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2011-04-27 21:53:53 -0400
committerJason Merrill <jason@gcc.gnu.org>2011-04-27 21:53:53 -0400
commit77a30e9a5f8ffbf06702de86d9b58e075d1ddc71 (patch)
tree6d7ca1938e69e3ced048dc0b648f5f15cbe83eba
parente79a6b402a7485aa214fc82be04bc5163951aba3 (diff)
downloadgcc-77a30e9a5f8ffbf06702de86d9b58e075d1ddc71.zip
gcc-77a30e9a5f8ffbf06702de86d9b58e075d1ddc71.tar.gz
gcc-77a30e9a5f8ffbf06702de86d9b58e075d1ddc71.tar.bz2
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
-rw-r--r--gcc/cp/ChangeLog9
-rw-r--r--gcc/cp/call.c62
-rw-r--r--gcc/cp/decl.c23
-rw-r--r--gcc/cp/typeck2.c10
-rw-r--r--gcc/testsuite/ChangeLog2
-rw-r--r--gcc/testsuite/g++.dg/ext/complex8.C67
6 files changed, 172 insertions, 1 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 0f18167..e1afe47 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,14 @@
2011-04-27 Jason Merrill <jason@redhat.com>
+ 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 10efd1c..dcc3859 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 ccc5fd0..5bf637e 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 5522868..aec54f9 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 73060c0..9604518 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,7 @@
2011-04-27 Jason Merrill <jason@redhat.com>
+ * 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 0000000..9b8ac1b
--- /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;
+}