From patchwork Mon May 16 15:36:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 54041 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CAB273835C27 for ; Mon, 16 May 2022 15:37:04 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CAB273835C27 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1652715424; bh=bgVbnEGSBB0FolC1NgIrPFXCit2lp4ZvhCGoU2QrVGw=; h=Date:To:Subject:References:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=hNW0fvP6i3nPxnj1qzTj/5fA7YZF+OQudyFOT/o2a9cR/Gu1IVkEDvcvidR3KQrrl PXpOdmpI2R+tQEeL2Y9HW88rV0OmMj9ndgW9lYbnQfvYMzKJo38qOdM1JcDSOCOVAC o7+GVb/LDhCXQvevf0QwNVvUhdYerHIteyYsad+U= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id D1E0C3839C5F for ; Mon, 16 May 2022 15:36:32 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D1E0C3839C5F Received: from mail-qk1-f197.google.com (mail-qk1-f197.google.com [209.85.222.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-591-qTN0TNZLPFqqvqLsFeJpVQ-1; Mon, 16 May 2022 11:36:31 -0400 X-MC-Unique: qTN0TNZLPFqqvqLsFeJpVQ-1 Received: by mail-qk1-f197.google.com with SMTP id c8-20020a05620a268800b0069c0f1b3206so11544598qkp.18 for ; Mon, 16 May 2022 08:36:31 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=bgVbnEGSBB0FolC1NgIrPFXCit2lp4ZvhCGoU2QrVGw=; b=xYmAVM5E91Fme5eezAMJ+/shDMGgIG+4B2pTqEFcdkXw3CjodgnwsAeWRvipw2Ci3l IdBBqVk7lbndGNA27aWQ+CnRqZTjtlrNMxb3rOOY9hXLE3crc+E5zp3FBXOzQuj0YGP5 MtHAwvLq8ID0Sy3J8ezz22sE+IHeyJmyaP/5uUPcxGK7dGHCsAUjRCrt1TSGiIEvFmJK /TUBYJR2Cdgke6ecyvTUy0XF8DXsWXXstQK3aL31121wDG3pdFB+cP5OaTUhJjPcDnZr AZg/s6lH25dNyIAaOzXnYkTli8u3a7TwDDAq8LdrFD1vr8NBcZLJ8h1VOyr92zORSbFC jSjg== X-Gm-Message-State: AOAM530skCMBvOt+WfVQWUNaG3SNHyADm6F0JmJv2lN6WyfGh2/gzreU N7eWDoVbO0TtyDbAoeXxyzbdEpZDqrwnKnwbkqrTj6FdSsAxHNXrN8hSnVDY6rgNvkzBRiaTYlr dzy5emEwXnreqgZ/ZDA== X-Received: by 2002:ae9:e709:0:b0:69f:db62:83a3 with SMTP id m9-20020ae9e709000000b0069fdb6283a3mr12634137qka.183.1652715390301; Mon, 16 May 2022 08:36:30 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzPPOtzSj8V/X4pOBE4AurJs/GfCwetnfy2g/iaO7ve9EcMiYd2TPniUK9Mzc1SwNjg4eK0nQ== X-Received: by 2002:ae9:e709:0:b0:69f:db62:83a3 with SMTP id m9-20020ae9e709000000b0069fdb6283a3mr12634111qka.183.1652715389843; Mon, 16 May 2022 08:36:29 -0700 (PDT) Received: from redhat.com ([2601:184:4780:4310::e811]) by smtp.gmail.com with ESMTPSA id p5-20020a37bf05000000b0069fc13ce206sm5893850qkf.55.2022.05.16.08.36.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 08:36:29 -0700 (PDT) Date: Mon, 16 May 2022 11:36:27 -0400 To: Jason Merrill Subject: [PATCH v5] c++: ICE with temporary of class type in DMI [PR100252] Message-ID: References: <20220426230226.677300-1-polacek@redhat.com> <8e0bc483-7fba-225c-807b-dbe89efceb5e@idea> <41c4c020-d058-cdeb-efa9-9b7956ca3f05@redhat.com> <1211247e-15ac-5851-029b-6c632208eb36@redhat.com> MIME-Version: 1.0 In-Reply-To: User-Agent: Mutt/2.2.1 (2022-02-19) X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-23.5 required=5.0 tests=BAYES_00, DKIM_INVALID, DKIM_SIGNED, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, RCVD_IN_DNSWL_LOW, 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-Patchwork-Original-From: Marek Polacek via Gcc-patches From: Marek Polacek Reply-To: Marek Polacek Cc: Jakub Jelinek , GCC Patches Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" On Sat, May 14, 2022 at 11:13:28PM -0400, Jason Merrill wrote: > On 5/13/22 19:41, Marek Polacek wrote: > > --- a/gcc/cp/typeck2.cc > > +++ b/gcc/cp/typeck2.cc > > @@ -1371,6 +1371,70 @@ digest_init_flags (tree type, tree init, int flags, tsubst_flags_t complain) > > return digest_init_r (type, init, 0, flags, complain); > > } > > +/* Return true if a prvalue is used as an initializer rather than for > > + temporary materialization. For instance: > > I might say "if SUBOB initializes the same object as FULL_EXPR"; the > full-expression could still end up initializing a temporary. Fixed. > > + A a = A{}; // initializer > > + A a = (A{}); // initializer > > + A a = (1, A{}); // initializer > > + A a = true ? A{} : A{}; // initializer > > + auto x = A{}.x; // temporary materialization > > + auto x = foo(A{}); // temporary materialization > > + > > + FULL_EXPR is the whole expression, SUBOB is its TARGET_EXPR subobject. */ > > + > > +static bool > > +potential_prvalue_result_of (tree subob, tree full_expr) > > +{ > > + if (subob == full_expr) > > + return true; > > + else if (TREE_CODE (full_expr) == TARGET_EXPR) > > + { > > + tree init = TARGET_EXPR_INITIAL (full_expr); > > + if (TREE_CODE (init) == COND_EXPR) > > + return (potential_prvalue_result_of (subob, TREE_OPERAND (init, 1)) > > + || potential_prvalue_result_of (subob, TREE_OPERAND (init, 2))); > > + else if (TREE_CODE (init) == COMPOUND_EXPR) > > + return (potential_prvalue_result_of (subob, TREE_OPERAND (init, 0)) > > We shouldn't recurse into the LHS of the comma, only the RHS. Fixed. > > + || potential_prvalue_result_of (subob, TREE_OPERAND (init, 1))); > > + /* ??? I don't know if this can be hit. If so, look inside the ( ) > > + instead of the assert. */ > > + else if (TREE_CODE (init) == PAREN_EXPR) > > + gcc_checking_assert (false); > > It seems trivial enough to recurse after the assert, in case it does happen > in the wild. OK, adjusted. Thanks! Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? -- >8 -- Consider struct A { int x; int y = x; }; struct B { int x = 0; int y = A{x}.y; // #1 }; where for #1 we end up with {.x=(&)->x, .y=(&)->x} that is, two PLACEHOLDER_EXPRs for different types on the same level in a {}. This crashes because our CONSTRUCTOR_PLACEHOLDER_BOUNDARY mechanism to avoid replacing unrelated PLACEHOLDER_EXPRs cannot deal with it. Here's why we wound up with those PLACEHOLDER_EXPRs: When we're performing cp_parser_late_parsing_nsdmi for "int y = A{x}.y;" we use finish_compound_literal on type=A, compound_literal={((struct B *) this)->x}. When digesting this initializer, we call get_nsdmi which creates a PLACEHOLDER_EXPR for A -- we don't have any object to refer to yet. After digesting, we have {.x=((struct B *) this)->x, .y=(&)->x} and since we've created a PLACEHOLDER_EXPR inside it, we marked the whole ctor CONSTRUCTOR_PLACEHOLDER_BOUNDARY. f_c_l creates a TARGET_EXPR and returns TARGET_EXPR x, .y=(&)->x}> Then we get to B b = {}; and call store_init_value, which digests the {}, which produces {.x=NON_LVALUE_EXPR <0>, .y=(TARGET_EXPR )->x, .y=(&)->x}>).y} lookup_placeholder in constexpr won't find an object to replace the PLACEHOLDER_EXPR for B, because ctx->object will be D.2395 of type A, and we cannot search outward from D.2395 to find 'b'. The call to replace_placeholders in store_init_value will not do anything: we've marked the inner { } CONSTRUCTOR_PLACEHOLDER_BOUNDARY, and it's only a sub-expression, so replace_placeholders does nothing, so the stays even though now is the perfect time to replace it because we have an object for it: 'b'. Later, in cp_gimplify_init_expr the *expr_p is D.2395 = {.x=(&)->x, .y=(&)->x} where D.2395 is of type A, but we crash because we hit , which has a different type. My idea was to replace with D.2384 after creating the TARGET_EXPR because that means we have an object we can refer to. Then clear CONSTRUCTOR_PLACEHOLDER_BOUNDARY because we no longer have a PLACEHOLDER_EXPR in the {}. Then store_init_value will be able to replace with 'b', and we should be good to go. We must be careful not to break guaranteed copy elision, so this replacement happens in digest_nsdmi_init where we can see the whole initializer, and avoid replacing any placeholders in TARGET_EXPRs used in the context of initialization/copy elision. This is achieved via the new function called potential_prvalue_result_of. While fixing this problem, I found PR105550, thus the FIXMEs in the tests. PR c++/100252 gcc/cp/ChangeLog: * typeck2.cc (potential_prvalue_result_of): New. (replace_placeholders_for_class_temp_r): New. (digest_nsdmi_init): Call it. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/nsdmi-aggr14.C: New test. * g++.dg/cpp1y/nsdmi-aggr15.C: New test. * g++.dg/cpp1y/nsdmi-aggr16.C: New test. * g++.dg/cpp1y/nsdmi-aggr17.C: New test. * g++.dg/cpp1y/nsdmi-aggr18.C: New test. * g++.dg/cpp1y/nsdmi-aggr19.C: New test. --- gcc/cp/typeck2.cc | 91 ++++++++++++++ gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C | 131 ++++++++++++++++++++ gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr15.C | 80 +++++++++++++ gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr16.C | 58 +++++++++ gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr17.C | 138 ++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr18.C | 56 +++++++++ gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr19.C | 28 +++++ 7 files changed, 582 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr15.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr16.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr17.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr18.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr19.C base-commit: 682e587f1021241758f7dfe0b22651008622a312 diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 1d92310edd0..1a96be3d412 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -1371,6 +1371,71 @@ digest_init_flags (tree type, tree init, int flags, tsubst_flags_t complain) return digest_init_r (type, init, 0, flags, complain); } +/* Return true if SUBOB initializes the same object as FULL_EXPR. + For instance: + + A a = A{}; // initializer + A a = (A{}); // initializer + A a = (1, A{}); // initializer + A a = true ? A{} : A{}; // initializer + auto x = A{}.x; // temporary materialization + auto x = foo(A{}); // temporary materialization + + FULL_EXPR is the whole expression, SUBOB is its TARGET_EXPR subobject. */ + +static bool +potential_prvalue_result_of (tree subob, tree full_expr) +{ + if (subob == full_expr) + return true; + else if (TREE_CODE (full_expr) == TARGET_EXPR) + { + tree init = TARGET_EXPR_INITIAL (full_expr); + if (TREE_CODE (init) == COND_EXPR) + return (potential_prvalue_result_of (subob, TREE_OPERAND (init, 1)) + || potential_prvalue_result_of (subob, TREE_OPERAND (init, 2))); + else if (TREE_CODE (init) == COMPOUND_EXPR) + return potential_prvalue_result_of (subob, TREE_OPERAND (init, 1)); + /* ??? I don't know if this can be hit. */ + else if (TREE_CODE (init) == PAREN_EXPR) + { + gcc_checking_assert (false); + return potential_prvalue_result_of (subob, TREE_OPERAND (init, 0)); + } + } + return false; +} + +/* Callback to replace PLACEHOLDER_EXPRs in a TARGET_EXPR (which isn't used + in the context of guaranteed copy elision). */ + +static tree +replace_placeholders_for_class_temp_r (tree *tp, int *, void *data) +{ + tree t = *tp; + tree full_expr = *static_cast(data); + + /* We're looking for a TARGET_EXPR nested in the whole expression. */ + if (TREE_CODE (t) == TARGET_EXPR + && !potential_prvalue_result_of (t, full_expr)) + { + tree init = TARGET_EXPR_INITIAL (t); + while (TREE_CODE (init) == COMPOUND_EXPR) + init = TREE_OPERAND (init, 1); + if (TREE_CODE (init) == CONSTRUCTOR + && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init)) + { + tree obj = TARGET_EXPR_SLOT (t); + replace_placeholders (init, obj); + /* We should have dealt with all PLACEHOLDER_EXPRs. */ + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = false; + gcc_checking_assert (!find_placeholders (init)); + } + } + + return NULL_TREE; +} + /* Process the initializer INIT for an NSDMI DECL (a FIELD_DECL). */ tree digest_nsdmi_init (tree decl, tree init, tsubst_flags_t complain) @@ -1390,6 +1455,32 @@ digest_nsdmi_init (tree decl, tree init, tsubst_flags_t complain) && CP_AGGREGATE_TYPE_P (type)) init = reshape_init (type, init, complain); init = digest_init_flags (type, init, flags, complain); + + /* We may have temporary materialization in a NSDMI, if the initializer + has something like A{} in it. Digesting the {} could have introduced + a PLACEHOLDER_EXPR referring to A. Now that we've got a TARGET_EXPR, + we have an object we can refer to. The reason we bother doing this + here is for code like + + struct A { + int x; + int y = x; + }; + + struct B { + int x = 0; + int y = A{x}.y; // #1 + }; + + where in #1 we don't want to end up with two PLACEHOLDER_EXPRs for + different types on the same level in a {} when lookup_placeholder + wouldn't find a named object for the PLACEHOLDER_EXPR for A. Note, + temporary materialization does not occur when initializing an object + from a prvalue of the same type, therefore we must not replace the + placeholder with a temporary object so that it can be elided. */ + cp_walk_tree (&init, replace_placeholders_for_class_temp_r, &init, + nullptr); + return init; } diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C new file mode 100644 index 00000000000..28b908a0a1a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C @@ -0,0 +1,131 @@ +// PR c++/100252 +// { dg-do run { target c++14 } } + +#define SA(X) static_assert ((X),#X) + +struct A { + int x; + int y = x; +}; + +struct B { + int x = 0; + int y = A{x}.y; +}; + +constexpr B csb1 = { }; +SA(csb1.x == 0 && csb1.y == csb1.x); +constexpr B csb2 = { 1 }; +SA(csb2.x == 1 && csb2.y == csb2.x); +constexpr B csb3 = { 1, 2 }; +SA(csb3.x == 1 && csb3.y == 2); + +B sb1 = { }; +B sb2 = { 1 }; +B sb3 = { 1, 2}; + +struct C { + int x = 0; + int y = (true, A{x}.y) + (A{x}.y, 0); +}; + +constexpr C csc1 = { }; +SA(csc1.x == 0 && csc1.y == csc1.x); +constexpr C csc2 = { 1 }; +SA(csc2.x == 1 && csc2.y == csc2.x); +constexpr C csc3 = { 1, 2 }; +SA(csc3.x == 1 && csc3.y == 2); + +C sc1 = { }; +C sc2 = { 1 }; +C sc3 = { 1, 2}; + +struct D { + int x = 0; + int y = (A{x}.y); +}; + +constexpr D csd1 = { }; +SA(csd1.x == 0 && csd1.y == csd1.x); +constexpr D csd2 = { 1 }; +SA(csd2.x == 1 && csd2.y == csd2.x); +constexpr D csd3 = { 1, 2 }; +SA(csd3.x == 1 && csd3.y == 2); + +D sd1 = { }; +D sd2 = { 1 }; +D sd3 = { 1, 2}; + +struct E { + int x = 0; + int y = x ? A{x}.y : A{x}.y; +}; + +constexpr E cse1 = { }; +SA(cse1.x == 0 && cse1.y == cse1.x); +constexpr E cse2 = { 1 }; +SA(cse2.x == 1 && cse2.y == cse2.x); +constexpr E cse3 = { 1, 2 }; +SA(cse3.x == 1 && cse3.y == 2); + +E se1 = { }; +E se2 = { 1 }; +E se3 = { 1, 2}; + +int +main () +{ + if (sb1.x != 0 || sb1.x != sb1.y) + __builtin_abort(); + if (sb2.x != 1 || sb2.x != sb2.y) + __builtin_abort(); + if (sb3.x != 1 || sb3.y != 2) + __builtin_abort(); + + if (sc1.x != 0 || sc1.x != sc1.y) + __builtin_abort(); + if (sc2.x != 1 || sc2.x != sc2.y) + __builtin_abort(); + if (sc3.x != 1 || sc3.y != 2) + __builtin_abort(); + + B b1 = { }; + B b2 = { 1 }; + B b3 = { 1, 2}; + if (b1.x != 0 || b1.x != b1.y) + __builtin_abort(); + if (b2.x != 1 || b2.x != b2.y) + __builtin_abort(); + if (b3.x != 1 || b3.y != 2) + __builtin_abort(); + + C c1 = { }; + C c2 = { 1 }; + C c3 = { 1, 2}; + if (c1.x != 0 || c1.x != c1.y) + __builtin_abort(); + if (c2.x != 1 || c2.x != c2.y) + __builtin_abort(); + if (c3.x != 1 || c3.y != 2) + __builtin_abort(); + + D d1 = { }; + D d2 = { 1 }; + D d3 = { 1, 2}; + if (d1.x != 0 || d1.x != d1.y) + __builtin_abort(); + if (d2.x != 1 || d2.x != d2.y) + __builtin_abort(); + if (d3.x != 1 || d3.y != 2) + __builtin_abort(); + + E e1 = { }; + E e2 = { 1 }; + E e3 = { 1, 2}; + if (e1.x != 0 || e1.x != e1.y) + __builtin_abort(); + if (e2.x != 1 || e2.x != e2.y) + __builtin_abort(); + if (e3.x != 1 || e3.y != 2) + __builtin_abort(); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr15.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr15.C new file mode 100644 index 00000000000..d091d693042 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr15.C @@ -0,0 +1,80 @@ +// PR c++/100252 +// { dg-do run { target c++14 } } + +struct A { + int x; + int y = x; +}; + +struct B { + int x = 0; + int y = A{x}.y; +}; + +static void +test_b (B b1 = B{}, B b2 = B{1}, B b3 = B{1, 2}) +{ + if (b1.x != 0 || b1.y != b1.x) + __builtin_abort(); + if (b2.x != 1 || b2.y != b2.x) + __builtin_abort(); + if (b3.x != 1 || b3.y != 2) + __builtin_abort(); +} + +struct C { + int x = 0; + int y = (true, A{x}.y) + (A{x}.y, 0); +}; + +static void +test_c (C c1 = C{}, C c2 = C{1}, C c3 = C{1, 2}) +{ + if (c1.x != 0 || c1.y != c1.x) + __builtin_abort(); + if (c2.x != 1 || c2.y != c2.x) + __builtin_abort(); + if (c3.x != 1 || c3.y != 2) + __builtin_abort(); +} + +struct D { + int x = 0; + int y = (A{x}.y); +}; + +static void +test_d (D d1 = D{}, D d2 = D{1}, D d3 = D{1, 2}) +{ + if (d1.x != 0 || d1.y != d1.x) + __builtin_abort(); + if (d2.x != 1 || d2.y != d2.x) + __builtin_abort(); + if (d3.x != 1 || d3.y != 2) + __builtin_abort(); +} + +struct E { + int x = 0; + int y = x ? A{x}.y : A{x}.y; +}; + +static void +test_e (E e1 = E{}, E e2 = E{1}, E e3 = E{1, 2}) +{ + if (e1.x != 0 || e1.y != e1.x) + __builtin_abort(); + if (e2.x != 1 || e2.y != e2.x) + __builtin_abort(); + if (e3.x != 1 || e3.y != 2) + __builtin_abort(); +} + +int +main () +{ + test_b (); + test_c (); + test_d (); + test_e (); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr16.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr16.C new file mode 100644 index 00000000000..dc6492c1b0b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr16.C @@ -0,0 +1,58 @@ +// PR c++/100252 +// { dg-do compile { target c++14 } } + +#define SA(X) static_assert ((X),#X) + +struct A { + const A* p = this; +}; + +struct B { + A a = A{}; +}; + +constexpr B b; +SA(b.a.p == &b.a); +B b1 = { }; + +struct C { + A a = (true, A{}); +}; + +constexpr C c; +SA(c.a.p == &c.a); +C c1 = { }; + +struct D { + A a = (A{}); +}; + +constexpr D d; +SA(d.a.p == &d.a); +D d1 = { }; + +static constexpr A global_a; + +struct E { + A a = true ? A{} : A{}; + A b = true ? global_a : (false ? A{} : A{}); + A c = true ? (false ? A{} : A{}) : global_a; + A d = true ? (false ? A{} : A{}) : (false ? A{} : A{}); +}; + +// FIXME: When fixing this, also fix nsdmi-aggr17.C. +constexpr E e; // { dg-bogus "" "PR105550" { xfail *-*-* } } +SA (e.a.p == &e.a); // { dg-bogus "" "PR105550" { xfail *-*-* } } + +E e1 = { }; + +struct F { + bool b = (A{}, true); +}; + +constexpr F f; + +void +g (B b2 = B{}, C c2 = C{}, D d2 = D{}, E e2 = E{}) +{ +} diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr17.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr17.C new file mode 100644 index 00000000000..fc27a2cdac7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr17.C @@ -0,0 +1,138 @@ +// PR c++/100252 +// { dg-do run { target c++14 } } + +#define SA(X) static_assert ((X),#X) + +struct A { + int x; + int y = x; + const A* p = this; +}; + +struct B { + int x = 42; + A a = A{x}; +}; + +constexpr B b; +SA(b.a.p == &b.a); +SA(b.x == 42); +B b2 = { }; +B b3 = { 42 }; + +struct C { + int x = 42; + B b = B{x}; +}; + +constexpr C c; +C c2; +C c3; + +struct D { + int x = 42; + A a = (true, A{x}); +}; + +constexpr D d; +SA(d.a.p == &d.a); +SA(d.x == 42); +D d2 = { }; +D d3 = { 42 }; + +struct E { + int x = 42; + A a = (A{x}); +}; + +constexpr E e; +SA(e.a.p == &e.a); +SA(e.x == 42); +E e2 = { }; +E e3 = { 42 }; + +struct F { + int x = 42; + A a = true ? A{x} : A{x}; +}; + +// FIXME: Doesn't work due to PR105550. +//constexpr F f; +//SA (f.a.p == &f.a); +SA (e.x == 42); +F f2 = { }; +F f3 = { 42 }; + +static void +test_b (B b4 = B{}, B b5 = B{ 42 }) +{ + if (b2.x != 42 || b2.a.x != 42 || b2.a.y != b2.a.x) + __builtin_abort (); + if (b3.x != 42 || b3.a.x != 42 || b3.a.y != b3.a.x) + __builtin_abort (); + if (b4.x != 42 || b4.a.x != 42 || b4.a.y != b4.a.x) + __builtin_abort (); + if (b5.x != 42 || b5.a.x != 42 || b5.a.y != b5.a.x) + __builtin_abort (); +} + +static void +test_c (C c4 = C{}, C c5 = C{ 42 }) +{ + if (c2.b.x != 42 || c2.b.a.x != 42 || c2.b.a.y != c2.b.a.x) + __builtin_abort (); + if (c3.b.x != 42 || c3.b.a.x != 42 || c3.b.a.y != c3.b.a.x) + __builtin_abort (); + if (c4.b.x != 42 || c4.b.a.x != 42 || c4.b.a.y != c4.b.a.x) + __builtin_abort (); + if (c5.b.x != 42 || c5.b.a.x != 42 || c5.b.a.y != c5.b.a.x) + __builtin_abort (); +} + +static void +test_d (D d4 = D{}, D d5 = D{ 42 }) +{ + if (d2.x != 42 || d2.a.x != 42 || d2.a.y != d2.a.x) + __builtin_abort (); + if (d3.x != 42 || d3.a.x != 42 || d3.a.y != d3.a.x) + __builtin_abort (); + if (d4.x != 42 || d4.a.x != 42 || d4.a.y != d4.a.x) + __builtin_abort (); + if (d5.x != 42 || d5.a.x != 42 || d5.a.y != d5.a.x) + __builtin_abort (); +} + +static void +test_e (E e4 = E{}, E e5 = E{ 42 }) +{ + if (e2.x != 42 || e2.a.x != 42 || e2.a.y != e2.a.x) + __builtin_abort (); + if (e3.x != 42 || e3.a.x != 42 || e3.a.y != e3.a.x) + __builtin_abort (); + if (e4.x != 42 || e4.a.x != 42 || e4.a.y != e4.a.x) + __builtin_abort (); + if (e5.x != 42 || e5.a.x != 42 || e5.a.y != e5.a.x) + __builtin_abort (); +} + +static void +test_f (F f4 = F{}, F f5 = F{ 42 }) +{ + if (f2.x != 42 || f2.a.x != 42 || f2.a.y != f2.a.x) + __builtin_abort (); + if (f3.x != 42 || f3.a.x != 42 || f3.a.y != f3.a.x) + __builtin_abort (); + if (f4.x != 42 || f4.a.x != 42 || f4.a.y != f4.a.x) + __builtin_abort (); + if (f5.x != 42 || f5.a.x != 42 || f5.a.y != f5.a.x) + __builtin_abort (); +} +int +main () +{ + test_b (); + test_c (); + test_d (); + test_e (); + test_f (); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr18.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr18.C new file mode 100644 index 00000000000..567b8ee96d9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr18.C @@ -0,0 +1,56 @@ +// PR c++/100252 +// { dg-do compile { target c++14 } } + +struct B { }; + +struct A { + int x; + int y = x; + constexpr operator B() { return B{}; } +}; + +struct C { + int x = 42; + B b = A{x}; +}; + +C c1 = {}; +C c2 = { 42 }; +constexpr C c3 = {}; +constexpr C c4 = { 42 }; + +struct D { + int x = 42; + B b = (true, A{x}); +}; + +D d1 = {}; +D d2 = { 42 }; +constexpr D d3 = {}; +constexpr D d4 = { 42 }; + +struct E { + int x = 42; + B b = (A{x}); +}; + +E e1 = {}; +E e2 = { 42 }; +constexpr E e3 = {}; +constexpr E e4 = { 42 }; + +struct F { + int x = 42; + B b = (A{x}); +}; + +F f1 = {}; +F f2 = { 42 }; +constexpr F f3 = {}; +constexpr F f4 = { 42 }; + +void +g (C c5 = C{}, C c6 = C{ 42 }, D d5 = D{}, D d6 = D{ 42 }, + E e5 = E{}, E e6 = E{ 42 }, F f5 = F{}, F f6 = F{ 42 }) +{ +} diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr19.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr19.C new file mode 100644 index 00000000000..f4892e3379b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr19.C @@ -0,0 +1,28 @@ +// PR c++/100252 +// { dg-do compile { target c++14 } } + +#define SA(X) static_assert ((X),#X) + +struct A { + const A* p = this; +}; + +struct B { + A a = (A{}, A{}); +}; + +constexpr B b; +SA(b.a.p == &b.a); + +struct C { + int x; + int y = x; +}; + +struct D { + int x = 0; + int y = (C{x}.y, C{x}.y); +}; + +constexpr D d = { }; +D d2 = {};