Commit 77a30e9a by Jason Merrill Committed by Jason Merrill

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
parent e79a6b40
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.
......
......@@ -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:
......
......@@ -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);
......
......@@ -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
......
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.
......
// 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment