From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-1.mimecast.com (us-smtp-1.mimecast.com [205.139.110.61]) by sourceware.org (Postfix) with ESMTP id 431243857C61 for ; Fri, 4 Sep 2020 21:39:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 431243857C61 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-450-caQkRiIHPPe7Td05pSqOgw-1; Fri, 04 Sep 2020 17:39:32 -0400 X-MC-Unique: caQkRiIHPPe7Td05pSqOgw-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 6AF2418B9F0C for ; Fri, 4 Sep 2020 21:39:31 +0000 (UTC) Received: from pdp-11.redhat.com (ovpn-116-54.rdu2.redhat.com [10.10.116.54]) by smtp.corp.redhat.com (Postfix) with ESMTP id E5C5360C17; Fri, 4 Sep 2020 21:39:30 +0000 (UTC) From: Marek Polacek To: Jason Merrill , GCC Patches Subject: [PATCH] c++: Fix ICE in reshape_init with init-list [PR95164] Date: Fri, 4 Sep 2020 17:39:22 -0400 Message-Id: <20200904213922.2543048-1-polacek@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Mimecast-Spam-Score: 0.001 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-14.1 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_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) 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: Fri, 04 Sep 2020 21:39:35 -0000 This patch fixes a long-standing bug in reshape_init_r. Since r209314 we implement DR 1467 which handles list-initialization with a single initializer of the same type as the target. In this test this causes a crash in reshape_init_r when we're processing a constructor that has undergone the DR 1467 transformation. Take e.g. the foo({{1, {H{k}}}}); line in the attached test. {H{k}} initializes the field b of H in I. H{k} is a functional cast, so has TREE_HAS_CONSTRUCTOR set, so is COMPOUND_LITERAL_P. We perform the DR 1467 transformation and turn {H{k}} into H{k}. Then we attempt to reshape H{k} again and since first_initializer_p is null and it's COMPOUND_LITERAL_P, we go here: else if (COMPOUND_LITERAL_P (stripped_init)) gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (stripped_init)); then complain about the missing braces, go to reshape_init_class and ICE on gcc_checking_assert (d->cur->index == get_class_binding (type, id)); because due to the missing { } we're looking for 'b' in H, but that's not found. So we have to be prepared to handle an initializer whose outer braces have been removed due to DR 1467. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk and 10? gcc/cp/ChangeLog: PR c++/95164 * decl.c (list_init_from_same_type_p): New function. (reshape_init_r): Call it. When we've found a missing set of braces, but list_init_from_same_type_p is true, don't reshape again. gcc/testsuite/ChangeLog: PR c++/95164 * g++.dg/cpp0x/initlist123.C: New test. --- gcc/cp/decl.c | 43 +++++++++++++++++++----- gcc/testsuite/g++.dg/cpp0x/initlist123.C | 39 +++++++++++++++++++++ 2 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist123.C diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 31d68745844..a07d52cdf5b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6350,6 +6350,21 @@ has_designator_problem (reshape_iter *d, tsubst_flags_t complain) return false; } +/* Handle [dcl.init.list]p3.2: Return true if we should elide braces when we're + initializing an object of class type (or, as an extension, vector type) by + list-initialization with a single initializer of the same type as the target. + + TYPE is the type of the target, INIT_TYPE is the type of the element of the + initializer list, and D is the iterator within the CONSTRUCTOR. */ + +static bool +list_init_from_same_type_p (reshape_iter *d, tree type, tree init_type) +{ + return (cxx_dialect >= cxx11 && (CLASS_TYPE_P (type) || VECTOR_TYPE_P (type)) + && d->end - d->cur == 1 + && reference_related_p (type, init_type)); +} + /* Subroutine of reshape_init, which processes a single initializer (part of a CONSTRUCTOR). TYPE is the type of the variable being initialized, D is the iterator within the CONSTRUCTOR which points to the initializer to process. @@ -6445,13 +6460,13 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, return init; } - /* "If T is a class type and the initializer list has a single element of - type cv U, where U is T or a class derived from T, the object is - initialized from that element." Even if T is an aggregate. */ - if (cxx_dialect >= cxx11 && (CLASS_TYPE_P (type) || VECTOR_TYPE_P (type)) - && first_initializer_p - && d->end - d->cur == 1 - && reference_related_p (type, TREE_TYPE (init))) + /* [dcl.init.list]p3.2: "If T is an aggregate class and the initializer list + has a single element of type cv U, where U is T or a class derived from T, + the object is initialized from that element (by copy-initialization for + copy-list-initialization, or by direct-initialization for + direct-list-initialization)." */ + if (first_initializer_p + && list_init_from_same_type_p (d, type, TREE_TYPE (init))) { d->cur++; return init; @@ -6531,7 +6546,19 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, /* For a nested compound literal, proceed to specialized routines, to handle initialization of arrays and similar. */ else if (COMPOUND_LITERAL_P (stripped_init)) - gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (stripped_init)); + { + gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (stripped_init)); + /* If we previously elided the braces around the single element + of an initializer list when initializing an object of the same + class type, don't report missing braces or reshape again. In + this case the braces had been enclosing a compound literal or + functional cast with aggregate, e.g. {S{}} -> S{}. */ + if (list_init_from_same_type_p (d, type, init_type)) + { + ++d->cur; + return init; + } + } /* A CONSTRUCTOR of the target's type is a previously digested initializer. */ else if (same_type_ignoring_top_level_qualifiers_p (type, init_type)) diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist123.C b/gcc/testsuite/g++.dg/cpp0x/initlist123.C new file mode 100644 index 00000000000..29f037f07ef --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist123.C @@ -0,0 +1,39 @@ +// PR c++/95164 +// { dg-do compile { target c++11 } } +// { dg-options "-Wmissing-braces" } + +struct H { + int a; +}; + +struct X : H { }; + +struct I { + int c; + H b; +}; +struct E { I d; }; +void foo(E); + +template +void fn () +{ + int a = 42; + int &k = a; + + foo({1, {H{k}}}); // { dg-warning "missing braces around initializer for .I." } + foo({1, {X{k}}}); // { dg-warning "missing braces around initializer for .I." } + + foo({{1, {k}}}); + foo({{1, {N}}}); + + foo({{1, H{k}}}); + foo({{1, H{N}}}); + foo({{1, X{k}}}); + foo({{1, X{N}}}); + + foo({{1, {H{k}}}}); + foo({{1, {H{N}}}}); + foo({{1, {X{k}}}}); + foo({{1, {X{N}}}}); +} base-commit: f923c40f9baba19e58f65afa7e5572f08cee93ff -- 2.26.2