From patchwork Tue Apr 26 23:02:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 1622729 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=myx9ZgRX; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4Kny972pjNz9s0B for ; Wed, 27 Apr 2022 09:03:22 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A62993858403 for ; Tue, 26 Apr 2022 23:03:19 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A62993858403 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1651014199; bh=H0JvpTpURA92KEuDEj/B88zLfmJo4T/yIyyLLYfzggI=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=myx9ZgRXIwzFshnfYnwcX3M+SvSqc5A+wzyG4Hk1xvxuIgub7gwb55cRvTa7bTzTb db5DFuO1Qo2BKU0CFwDA7ZzHlYP0lkiyEk0iBzkcsXqneL7ep69QWZlmNpGe1cAHvp qHw1JFXFmTN1Dne6oemK9HL8nj8/rwm7L/qpPCVA= 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.133.124]) by sourceware.org (Postfix) with ESMTPS id B0CAE3858C83 for ; Tue, 26 Apr 2022 23:02:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B0CAE3858C83 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-274-oSgp3G4GOVO5JaLbD4qXfg-1; Tue, 26 Apr 2022 19:02:37 -0400 X-MC-Unique: oSgp3G4GOVO5JaLbD4qXfg-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id E71553810789 for ; Tue, 26 Apr 2022 23:02:36 +0000 (UTC) Received: from pdp-11.redhat.com (unknown [10.22.35.36]) by smtp.corp.redhat.com (Postfix) with ESMTP id B5CA314682C5; Tue, 26 Apr 2022 23:02:36 +0000 (UTC) To: GCC Patches , Jason Merrill Subject: [PATCH] c++: ICE with temporary of class type in DMI [PR100252] Date: Tue, 26 Apr 2022 19:02:26 -0400 Message-Id: <20220426230226.677300-1-polacek@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-13.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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 Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" 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 digest the {}, which produces {.x=NON_LVALUE_EXPR <0>, .y=(TARGET_EXPR )->x, .y=(&)->x}>).y} 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 in f_c_l 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. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/11.4? PR c++/100252 gcc/cp/ChangeLog: * semantics.cc (finish_compound_literal): replace_placeholders after creating the TARGET_EXPR. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/nsdmi-aggr14.C: New test. --- gcc/cp/semantics.cc | 31 +++++++++++++++ gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C | 46 +++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C base-commit: 9ace5d4dab2ab39072b0f07089621a823580f27c diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index ab48f11c9be..770369458bb 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -3296,6 +3296,37 @@ finish_compound_literal (tree type, tree compound_literal, if (TREE_CODE (compound_literal) == CONSTRUCTOR) TREE_HAS_CONSTRUCTOR (compound_literal) = false; compound_literal = get_target_expr_sfinae (compound_literal, complain); + /* We may have A{} in a NSDMI. */ + if (parsing_nsdmi ()) + { + /* Digesting the {} could have introduced a PLACEHOLDER_EXPR + referring to A. Now that we've built up 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 {} as in 100252. */ + tree init = TARGET_EXPR_INITIAL (compound_literal); + if (TREE_CODE (init) == CONSTRUCTOR + && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init)) + { + tree obj = TARGET_EXPR_SLOT (compound_literal); + replace_placeholders (compound_literal, obj); + /* We should have dealt with the PLACEHOLDER_EXPRs. */ + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = false; + gcc_checking_assert (!find_placeholders (init)); + } + } } else /* For e.g. int{42} just make sure it's a prvalue. */ 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..7d508f52b48 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C @@ -0,0 +1,46 @@ +// 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}; + +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(); + + 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(); +}