From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 2FB623858292 for ; Tue, 5 Jul 2022 20:44:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2FB623858292 Received: from mail-qk1-f200.google.com (mail-qk1-f200.google.com [209.85.222.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-226-t10-n4k4NK--0GhWw-Tu1g-1; Tue, 05 Jul 2022 16:44:43 -0400 X-MC-Unique: t10-n4k4NK--0GhWw-Tu1g-1 Received: by mail-qk1-f200.google.com with SMTP id 194-20020a3704cb000000b006af069d1e0aso12587837qke.15 for ; Tue, 05 Jul 2022 13:44:43 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:date:mime-version:user-agent:subject :content-language:to:references:from:in-reply-to :content-transfer-encoding; bh=J6hM41NVuh2hgSyBxpdEO+yiDl9Y3rrUEXfYN/9UBv4=; b=cmZZQEcX4a+NifbLZdjQKtGQ8KebFqZJdpx2O/ldnVtktQFKgj6zDtNHV2HSkSkdRA 1bM8UiBscsEGoe1wD+puMhbZXeavm+TfjJikygLrkRjJHVJVDK2F5InDGy76411v/unn ucAjaXvGIlP0hocajU8iuF+WmBFIag5fnk6ZR0YmZ+9r5yB9G5oR4LihjmKgkTt5yEgi KU2YkaB8yUpvsQyvVBZUPhc3acK01+zwhcUuAhvRcKiwunleR4BYDwuQuk7H3smA4aJN eBZ8D5EbA2xGDEwJ5GHv9BHuRzCdSoKup7+2sQqjxT0G0bOhceJuVcMLWmz4pmSHlmdp Wg1g== X-Gm-Message-State: AJIora/gOdUSVA6ltpe6Emjl6k9mlPK+aBfaoft4iV9zlOXOR5UPwZL3 kcngGuwAAuLu3q/i2VjwNpdsoeDWYJmq8Ryu66z7PxG5Ht8f50OSZnDmUGNb2FJx67C8HeL4Vtl aFKwAHs9USvd3UKZ5Wg== X-Received: by 2002:ac8:5f4e:0:b0:31b:f6eb:d109 with SMTP id y14-20020ac85f4e000000b0031bf6ebd109mr30013270qta.150.1657053883352; Tue, 05 Jul 2022 13:44:43 -0700 (PDT) X-Google-Smtp-Source: AGRyM1sPNolFIJih8xfvlPhjc8pR71JCb9UpyuLsKIgYgI0mzcuOk4l9pN9gGf6mT15tq/oz60PbyQ== X-Received: by 2002:ac8:5f4e:0:b0:31b:f6eb:d109 with SMTP id y14-20020ac85f4e000000b0031bf6ebd109mr30013246qta.150.1657053882981; Tue, 05 Jul 2022 13:44:42 -0700 (PDT) Received: from [192.168.1.100] (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id s11-20020a05622a1a8b00b003196e8eda26sm17886240qtc.69.2022.07.05.13.44.42 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 05 Jul 2022 13:44:42 -0700 (PDT) Message-ID: Date: Tue, 5 Jul 2022 16:44:41 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.11.0 Subject: Re: [PATCH] c++, v3: Add support for __real__/__imag__ modifications in constant expressions [PR88174] To: Jakub Jelinek , gcc-patches@gcc.gnu.org References: <4d9319d5-1890-7c99-6c1b-d940f873a590@redhat.com> <38ccc92a-6772-75d9-1ac9-fc3252734291@redhat.com> From: Jason Merrill In-Reply-To: X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 05 Jul 2022 20:45:04 -0000 On 7/4/22 11:50, Jakub Jelinek wrote: > On Mon, Jun 27, 2022 at 06:31:18PM +0200, Jakub Jelinek via Gcc-patches wrote: >>> Hmm, why do we need to handle complex in the !preeval case? I'd think we >>> want to preevaluate all complex values or components thereof. >> Because the late evaluation of the initializer could have touched >> the destination, so we need to reevaluate it. >> Same reason why we call get_or_insert_ctor_field again in the second >> loop as we call it in the first loop. But preeval should always be true, so we'd never reach the new handling in the if (!preeval) block. Certainly the new testcase doesn't exercise this code. >> If it would help, I could move that repeated part into: > >>> This seems like it needs to come before the ctors loop, so that these flags >>> can be propagated out to enclosing constructors. >> >> I could indeed move this in between >> bool c = TREE_CONSTANT (init); >> bool s = TREE_SIDE_EFFECTS (init); >> and >> if (!c || s || activated_union_member_p) >> and update c and s from *cexpr flags. > > Here is it in patch form, so far lightly tested, ok for trunk if it passes > full bootstrap/regtest? > > 2022-07-04 Jakub Jelinek > > PR c++/88174 > * constexpr.cc (canonicalize_complex_to_complex_expr): New function. > (cxx_eval_store_expression): Handle REALPART_EXPR and IMAGPART_EXPR. > Change ctors from releasing_vec to auto_vec, adjust all uses. > > * g++.dg/cpp1y/constexpr-complex1.C: New test. > > --- gcc/cp/constexpr.cc.jj 2022-07-04 12:26:18.147053851 +0200 > +++ gcc/cp/constexpr.cc 2022-07-04 17:35:53.100556949 +0200 > @@ -5640,6 +5640,26 @@ modifying_const_object_p (tree_code code > return false; > } > > +/* Helper of cxx_eval_store_expression, turn a COMPLEX_CST or > + empty no clearing CONSTRUCTOR into a COMPLEX_EXPR. */ > + > +static tree > +canonicalize_complex_to_complex_expr (tree t) > +{ > + if (TREE_CODE (t) == COMPLEX_CST) > + t = build2 (COMPLEX_EXPR, TREE_TYPE (t), > + TREE_REALPART (t), TREE_IMAGPART (t)); > + else if (TREE_CODE (t) == CONSTRUCTOR > + && CONSTRUCTOR_NELTS (t) == 0 > + && CONSTRUCTOR_NO_CLEARING (t)) > + { > + tree r = build_constructor (TREE_TYPE (TREE_TYPE (t)), NULL); > + CONSTRUCTOR_NO_CLEARING (r) = 1; > + t = build2 (COMPLEX_EXPR, TREE_TYPE (t), r, r); > + } > + return t; > +} > + > /* Evaluate an INIT_EXPR or MODIFY_EXPR. */ > > static tree > @@ -5726,6 +5746,20 @@ cxx_eval_store_expression (const constex > } > break; > > + case REALPART_EXPR: > + gcc_assert (probe == target); > + vec_safe_push (refs, probe); > + vec_safe_push (refs, TREE_TYPE (probe)); > + probe = TREE_OPERAND (probe, 0); > + break; > + > + case IMAGPART_EXPR: > + gcc_assert (probe == target); > + vec_safe_push (refs, probe); > + vec_safe_push (refs, TREE_TYPE (probe)); > + probe = TREE_OPERAND (probe, 0); > + break; > + > default: > if (evaluated) > object = probe; > @@ -5764,7 +5798,8 @@ cxx_eval_store_expression (const constex > type = TREE_TYPE (object); > bool no_zero_init = true; > > - releasing_vec ctors, indexes; > + auto_vec ctors; > + releasing_vec indexes; > auto_vec index_pos_hints; > bool activated_union_member_p = false; > bool empty_base = false; > @@ -5804,14 +5839,26 @@ cxx_eval_store_expression (const constex > *valp = ary_ctor; > } > > - /* If the value of object is already zero-initialized, any new ctors for > - subobjects will also be zero-initialized. */ > - no_zero_init = CONSTRUCTOR_NO_CLEARING (*valp); > - > enum tree_code code = TREE_CODE (type); > tree reftype = refs->pop(); > tree index = refs->pop(); > > + if (code == COMPLEX_TYPE) > + { > + *valp = canonicalize_complex_to_complex_expr (*valp); > + gcc_assert (TREE_CODE (*valp) == COMPLEX_EXPR); > + ctors.safe_push (valp); > + vec_safe_push (indexes, index); > + valp = &TREE_OPERAND (*valp, TREE_CODE (index) == IMAGPART_EXPR); > + gcc_checking_assert (refs->is_empty ()); > + type = reftype; > + break; > + } > + > + /* If the value of object is already zero-initialized, any new ctors for > + subobjects will also be zero-initialized. */ > + no_zero_init = CONSTRUCTOR_NO_CLEARING (*valp); > + > if (code == RECORD_TYPE && is_empty_field (index)) > /* Don't build a sub-CONSTRUCTOR for an empty base or field, as they > have no data and might have an offset lower than previously declared > @@ -5854,7 +5901,7 @@ cxx_eval_store_expression (const constex > no_zero_init = true; > } > > - vec_safe_push (ctors, *valp); > + ctors.safe_push (valp); > vec_safe_push (indexes, index); > > constructor_elt *cep > @@ -5916,11 +5963,11 @@ cxx_eval_store_expression (const constex > semantics are not applied on an object under construction. > They come into effect when the constructor for the most > derived object ends." */ > - for (tree elt : *ctors) > + for (tree *elt : ctors) > if (same_type_ignoring_top_level_qualifiers_p > - (TREE_TYPE (const_object_being_modified), TREE_TYPE (elt))) > + (TREE_TYPE (const_object_being_modified), TREE_TYPE (*elt))) > { > - fail = TREE_READONLY (elt); > + fail = TREE_READONLY (*elt); > break; > } > } > @@ -5961,6 +6008,16 @@ cxx_eval_store_expression (const constex > valp = ctx->global->values.get (object); > for (unsigned i = 0; i < vec_safe_length (indexes); i++) > { > + ctors[i] = valp; > + if (TREE_CODE (indexes[i]) == REALPART_EXPR > + || TREE_CODE (indexes[i]) == IMAGPART_EXPR) > + { > + *valp = canonicalize_complex_to_complex_expr (*valp); > + gcc_assert (TREE_CODE (*valp) == COMPLEX_EXPR); > + valp = &TREE_OPERAND (*valp, > + TREE_CODE (indexes[i]) == IMAGPART_EXPR); > + break; > + } > constructor_elt *cep > = get_or_insert_ctor_field (*valp, indexes[i], index_pos_hints[i]); > valp = &cep->value; > @@ -6023,17 +6080,45 @@ cxx_eval_store_expression (const constex > CONSTRUCTORs, if any. */ > bool c = TREE_CONSTANT (init); > bool s = TREE_SIDE_EFFECTS (init); > + if (!indexes->is_empty ()) > + { > + tree last = indexes->last (); > + if (TREE_CODE (last) == REALPART_EXPR > + || TREE_CODE (last) == IMAGPART_EXPR) > + { > + /* And canonicalize COMPLEX_EXPR into COMPLEX_CST if > + possible. */ > + tree *cexpr = ctors.last (); > + if (tree c = const_binop (COMPLEX_EXPR, TREE_TYPE (*cexpr), > + TREE_OPERAND (*cexpr, 0), > + TREE_OPERAND (*cexpr, 1))) > + *cexpr = c; > + else > + { > + TREE_CONSTANT (*cexpr) > + = (TREE_CONSTANT (TREE_OPERAND (*cexpr, 0)) > + & TREE_CONSTANT (TREE_OPERAND (*cexpr, 1))); > + TREE_SIDE_EFFECTS (*cexpr) > + = (TREE_SIDE_EFFECTS (TREE_OPERAND (*cexpr, 0)) > + | TREE_SIDE_EFFECTS (TREE_OPERAND (*cexpr, 1))); > + } > + c = TREE_CONSTANT (*cexpr); > + s = TREE_SIDE_EFFECTS (*cexpr); > + } > + } > if (!c || s || activated_union_member_p) > - for (tree elt : *ctors) > + for (tree *elt : ctors) > { > + if (TREE_CODE (*elt) != CONSTRUCTOR) > + continue; > if (!c) > - TREE_CONSTANT (elt) = false; > + TREE_CONSTANT (*elt) = false; > if (s) > - TREE_SIDE_EFFECTS (elt) = true; > + TREE_SIDE_EFFECTS (*elt) = true; > /* Clear CONSTRUCTOR_NO_CLEARING since we've activated a member of > this union. */ > - if (TREE_CODE (TREE_TYPE (elt)) == UNION_TYPE) > - CONSTRUCTOR_NO_CLEARING (elt) = false; > + if (TREE_CODE (TREE_TYPE (*elt)) == UNION_TYPE) > + CONSTRUCTOR_NO_CLEARING (*elt) = false; > } > > if (lval) > --- gcc/testsuite/g++.dg/cpp1y/constexpr-complex1.C.jj 2022-07-04 17:30:47.884580998 +0200 > +++ gcc/testsuite/g++.dg/cpp1y/constexpr-complex1.C 2022-07-04 17:30:47.884580998 +0200 > @@ -0,0 +1,24 @@ > +// PR c++/88174 > +// { dg-do compile { target c++14 } } > + > +constexpr bool > +foo (double x, double y, double z, double w) > +{ > + __complex__ double a = 0; > + __real__ a = x; > + __imag__ a = y; > +#if __cpp_constexpr >= 201907L > + __complex__ double b; > + __real__ b = z; > +#else > + __complex__ double b = z; > +#endif > + __imag__ b = w; > + a += b; > + a -= b; > + a *= b; > + a /= b; > + return __real__ a == x && __imag__ a == y; > +} > + > +static_assert (foo (1.0, 2.0, 3.0, 4.0), ""); > > > Jakub >