re PR libstdc++/48760 (std::complex constructor buggy in the face of NaN's)
authorJason Merrill <jason@redhat.com>
Thu, 28 Apr 2011 01:53:53 +0000 (21:53 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 28 Apr 2011 01:53:53 +0000 (21:53 -0400)
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
gcc/cp/call.c
gcc/cp/decl.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/complex8.C [new file with mode: 0644]

index 0f18167..e1afe47 100644 (file)
@@ -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.
index 10efd1c..dcc3859 100644 (file)
@@ -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:
index ccc5fd0..5bf637e 100644 (file)
@@ -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);
index 5522868..aec54f9 100644 (file)
@@ -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
index 73060c0..9604518 100644 (file)
@@ -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 (file)
index 0000000..9b8ac1b
--- /dev/null
@@ -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;
+}