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.
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. */
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))
}
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:
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))
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);
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
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.
--- /dev/null
+// 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;
+}