From patchwork Thu Apr 28 01:36:03 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 93155 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 33A1EB6EF1 for ; Thu, 28 Apr 2011 11:36:27 +1000 (EST) Received: (qmail 22710 invoked by alias); 28 Apr 2011 01:36:25 -0000 Received: (qmail 22509 invoked by uid 22791); 28 Apr 2011 01:36:24 -0000 X-SWARE-Spam-Status: No, hits=-6.3 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 28 Apr 2011 01:36:07 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p3S1a4xa027208 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 27 Apr 2011 21:36:05 -0400 Received: from [127.0.0.1] (ovpn-113-53.phx2.redhat.com [10.3.113.53]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p3S1a3jM018331; Wed, 27 Apr 2011 21:36:04 -0400 Message-ID: <4DB8C483.8060108@redhat.com> Date: Wed, 27 Apr 2011 21:36:03 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.15) Gecko/20110307 Fedora/3.1.9-0.39.b3pre.fc14 Lightning/1.0b2 Thunderbird/3.1.9 MIME-Version: 1.0 To: gcc-patches List CC: Paolo Carlini , Gabriel Dos Reis Subject: C++ PATCH for libstdc++/48760 (list-initialization of complex) Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org In the discussion of 48760, Gaby suggested that we allow list-initialization of built-in complex numbers. This made a lot of sense to me, so I've gone ahead and implemented it. Basically it works as though complex were an aggregate except for one thing: for backwards compatibility, we never assume elided braces when initializing a complex number. So given struct A { _Complex int c; int i; }; A a = { 1, 2 }; a.c is initialized to 1+0i rather than 1+2i as it has been previously, and a.i is initialized to 2. Tested x86_64-pc-linux-gnu, applying to trunk. commit 0131da0c5a789fc9f952a05d9d06262b2c72b980 Author: Jason Merrill Date: Wed Apr 27 20:25:50 2011 -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. 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/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; +}