From patchwork Sat Jun 22 00:05:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Sebor X-Patchwork-Id: 1120586 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-503498-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45Vwmy4BYfz9sBp for ; Sat, 22 Jun 2019 10:05:36 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to :from:subject:message-id:date:mime-version:content-type; q=dns; s=default; b=yPn4YYT6ZrWcE2wYxK1ddsC2DSTlOqKdWy4W73l/PdvLmH+06p KIE+3/+1ZeF5bWTszh/RqWXB9DhR78sP2nTlD3xxQHLM3E/qN0zk7QpczeO2kVhY 5JUzRfO99F7IAr4YRiwl6y8IbY/vjN9mWgdjJ+auDgxBRzW4cG3f1k9MM= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to :from:subject:message-id:date:mime-version:content-type; s= default; bh=70Q75UNe8L49g+HAJ/V61ucNOpU=; b=aiQfG2zkDyDQpnz5eIhi mcNr/F8/4Epn194doUHZKElvNS8SJVEJPX6IQNfukDZDQ0i558w0aJN/J+J5g0dJ 8WzsptJEWck/DpDUHv7emUDGyL5gDf/gN+icrjx1IVoKHT8i+oIx9Yy9rErg638u Bw8rndwtmO0Ia6AolxehbuA= Received: (qmail 78945 invoked by alias); 22 Jun 2019 00:05:27 -0000 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 Received: (qmail 78938 invoked by uid 89); 22 Jun 2019 00:05:27 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.6 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=vecsize, yzw, considers X-HELO: mail-qk1-f176.google.com Received: from mail-qk1-f176.google.com (HELO mail-qk1-f176.google.com) (209.85.222.176) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 22 Jun 2019 00:05:24 +0000 Received: by mail-qk1-f176.google.com with SMTP id p144so5706579qke.11 for ; Fri, 21 Jun 2019 17:05:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=to:from:subject:message-id:date:user-agent:mime-version :content-language; bh=JyDj1trztSU7uzW1gurK8BawW65zBYG+mewqCb42onw=; b=DmaDIOrVXlkhXD1LGXd1vwIcVhy2Ud8k7IMoz4U5/lN9i1MrEvgMCvDanU/AHfGszQ EuBEyMp3W+UEeXirMXoPlDn/pXOFgmevfwWVMSz0QvWX6Bx0/VvuNcTDxUFViLo26hXI kajwxE118ImzaRoIIiBddh2I4HnDzzG4XrESMP0E0N2J4L4JfokJreU0rXOJZDrGxyme BnnhrJO/pSk39zFkLtvcroTe3HyUlvm/biAGTvLJqjY15br6fG/7dS7uLviVCogKgVxP 9JYYPj5q3qFKMLSzkZUrDAMu16lFLp44p9K2PcMByGBqQL9l1gd2JoR/ThrAEepU+U7E Cx0w== Received: from [192.168.0.41] (75-166-109-122.hlrn.qwest.net. [75.166.109.122]) by smtp.gmail.com with ESMTPSA id q17sm2085151qtj.96.2019.06.21.17.05.20 (version=TLS1_3 cipher=AEAD-AES128-GCM-SHA256 bits=128/128); Fri, 21 Jun 2019 17:05:21 -0700 (PDT) To: gcc-patches , Jason Merrill From: Martin Sebor Subject: [PATCH] don't trim empty string initializers for pointers (PR 90947) Message-ID: <2d5f1526-c124-03b4-63fd-a476da5c35f1@gmail.com> Date: Fri, 21 Jun 2019 18:05:19 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 X-IsSubscribed: yes The solution we implemented in GCC 9 to get the mangling of non-type template arguments of class types containing array members consistent regardless of the form of their initialization introduced a couple of bugs. One of these is the subject of this patch. The bug results in stripping trailing initializers for array elements that involve the empty string such as in here: void f (void) { const char* a[1][1] = { "" }; if (!a[0][0]) __builtin_abort (); } The problem is caused by relying on initializer_zerop() that returns true for the empty string regardless of whether it's used to initialize an array or a pointer (the function doesn't know what the initializer is being used for). To handle this correctly the attached patch introduces a new function, type_initializer_zero_p, that takes in addition to an initializer also the type it is being used to initialize. The function then traverses both arguments and returns true only if each string is being used to initialize an array and false if any of them is being used to initialize a pointer. Since the function is generic the patch adds it to tree.c rather than somewhere in the C++ front-end. Tested on x86_64-linux. Martin PR c++/90947 - Simple lookup table of array of strings is miscompiled gcc/cp/ChangeLog: PR c++/90947 * decl.c (reshape_init_array_1): Avoid truncating initializer lists containing string literals. gcc/testsuite/ChangeLog: PR c++/90947 * c-c++-common/array-1.c: New test. * g++.dg/abi/mangle73.C: New test. * g++.dg/cpp2a/nontype-class18.C: New test. gcc/ChangeLog: PR c++/90947 * tree.c (type_initializer_zero_p): Define. * tree.h (type_initializer_zero_p): New function. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 98b54d542a0..95893631992 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5863,8 +5863,9 @@ reshape_init_array_1 (tree elt_type, tree max_index, reshape_iter *d, /* Pointers initialized to strings must be treated as non-zero even if the string is empty. */ tree init_type = TREE_TYPE (elt_init); - if ((POINTER_TYPE_P (elt_type) != POINTER_TYPE_P (init_type)) - || !initializer_zerop (elt_init)) + if ((POINTER_TYPE_P (elt_type) != POINTER_TYPE_P (init_type))) + last_nonzero = index; + else if (!type_initializer_zero_p (elt_type, elt_init)) last_nonzero = index; /* This can happen with an invalid initializer (c++/54501). */ diff --git a/gcc/testsuite/c-c++-common/array-1.c b/gcc/testsuite/c-c++-common/array-1.c new file mode 100644 index 00000000000..5de9ade4d43 --- /dev/null +++ b/gcc/testsuite/c-c++-common/array-1.c @@ -0,0 +1,247 @@ +// PR c++/90947 - Simple lookup table of array of strings is miscompiled +// { dg-do compile } +// { dg-options "-O1 -fdump-tree-optimized" } + +#define assert(expr) ((expr) ? (void)0 : __builtin_abort ()) + +void pr90947 (void) +{ + int vecsize = 4; + int index = 0; + static const char *a[4][4] = + { + { ".x", ".y", ".z", ".w" }, + { ".xy", ".yz", ".zw", 0 }, + { ".xyz", ".yzw", 0, 0 }, + { "", 0, 0, 0 }, + }; + + assert (vecsize >= 1 && vecsize <= 4); + assert (index >= 0 && index < 4); + assert (a[vecsize - 1][index]); +} + +void f_a1_1 (void) +{ + { + const char* a[1][1] = { { 0 } }; + assert (0 == a[0][0]); + } + { + const char* a[1][1] = { { "" } }; + assert ('\0' == *a[0][0]); + } +} + +void f_a2_1 (void) +{ + { + const char* a[2][1] = { { "" }, { "" } }; + assert ('\0' == *a[0][0] && '\0' == *a[1][0]); + } + { + const char* a[2][1] = { { 0 }, { "" } }; + assert (0 == a[0][0] && '\0' == *a[1][0]); + } + { + const char* a[2][1] = { { }, { "" } }; + assert (0 == a[0][0] && '\0' == *a[1][0]); + } +} + +void f_a2_2 (void) +{ + { + const char* a[2][2] = { { "", "" }, { "", "" } }; + assert ('\0' == *a[0][0] && '\0' == *a[0][1]); + assert ('\0' == *a[1][0] && '\0' == *a[1][1]); + } + { + const char* a[2][2] = { { "", "" }, { "", 0 } }; + assert ('\0' == *a[0][0] && '\0' == *a[0][1]); + assert ('\0' == *a[1][0] && 0 == a[1][1]); + } + { + const char* a[2][2] = { { "", "" }, { "" } }; + assert ('\0' == *a[0][0] && '\0' == *a[0][1]); + assert ('\0' == *a[1][0] && 0 == a[1][1]); + } + { + const char* a[2][2] = { { "", "" }, { 0, "" } }; + assert ('\0' == *a[0][0] && '\0' == *a[0][1]); + assert (0 == a[1][0] && '\0' == *a[1][1]); + } + { + const char* a[2][2] = { { "", 0 }, { 0, "" } }; + assert ('\0' == *a[0][0] && 0 == a[0][1]); + assert (0 == a[1][0] && '\0' == *a[1][1]); + } + { + const char* a[2][2] = { { 0, 0 }, { 0, "" } }; + assert (0 == a[0][0] && 0 == a[0][1]); + assert (0 == a[1][0] && '\0' == *a[1][1]); + } + { + const char* a[2][2] = { { 0 }, { 0, "" } }; + assert (0 == a[0][0] && 0 == a[0][1]); + assert (0 == a[1][0] && '\0' == *a[1][1]); + } + { + const char* a[2][2] = { { }, { 0, "" } }; + assert (0 == a[0][0] && 0 == a[0][1]); + assert (0 == a[1][0] && '\0' == *a[1][1]); + } +} + +void f_a2_2_2 (void) +{ + { + const char* a[2][2][2] = + { { { "", "" }, { "", "" } }, { { "", "" }, { "", "" } } }; + + assert ('\0' == *a[0][0][0] && '\0' == *a[0][0][1]); + assert ('\0' == *a[0][1][0] && '\0' == *a[0][1][1]); + assert ('\0' == *a[1][0][0] && '\0' == *a[1][0][1]); + assert ('\0' == *a[1][1][0] && '\0' == *a[1][1][1]); + } + + { + const char* a[2][2][2] = + { { { "", "" }, { "", "" } }, { { "", "" }, { 0, "" } } }; + + assert ('\0' == *a[0][0][0] && '\0' == *a[0][0][1]); + assert ('\0' == *a[0][1][0] && '\0' == *a[0][1][1]); + assert ('\0' == *a[1][0][0] && '\0' == *a[1][0][1]); + assert (0 == a[1][1][0] && '\0' == *a[1][1][1]); + } + + { + const char* a[2][2][2] = + { { { "", "" }, { "", "" } }, { { 0, 0 }, { 0, "" } } }; + + assert ('\0' == *a[0][0][0] && '\0' == *a[0][0][1]); + assert ('\0' == *a[0][1][0] && '\0' == *a[0][1][1]); + assert (0 == a[1][0][0] && 0 == a[1][0][1]); + assert (0 == a[1][1][0] && '\0' == *a[1][1][1]); + } + + { + const char* a[2][2][2] = + { { { "", "" }, { 0, 0 } }, { { 0, 0 }, { 0, "" } } }; + + assert ('\0' == *a[0][0][0] && '\0' == *a[0][0][1]); + assert (0 == a[0][1][0] && 0 == a[0][1][1]); + assert (0 == a[1][0][0] && 0 == a[1][0][1]); + assert (0 == a[1][1][0] && '\0' == *a[1][1][1]); + } + + { + const char* a[2][2][2] = + { { { 0, 0 }, { 0, 0 } }, { { 0, 0 }, { 0, "" } } }; + + assert (0 == a[0][0][0] && 0 == a[0][0][1]); + assert (0 == a[0][1][0] && 0 == a[0][1][1]); + assert (0 == a[1][0][0] && 0 == a[1][0][1]); + assert (0 == a[1][1][0] && '\0' == *a[1][1][1]); + } + + { + const char* a[2][2][2] = + { { { }, { } }, { { }, { 0, "" } } }; + + assert (0 == a[0][0][0] && 0 == a[0][0][1]); + assert (0 == a[0][1][0] && 0 == a[0][1][1]); + assert (0 == a[1][0][0] && 0 == a[1][0][1]); + assert (0 == a[1][1][0] && '\0' == *a[1][1][1]); + } +} + +void f_sa2_2_2 (void) +{ + struct S { const char a[2], *s, c; }; + + { + const struct S a[2][2][2] = { + { }, + { + { { }, { "", "" } }, + { } + } + }; + + assert ('\0' == *a[0][0][0].a && 0 == a[0][0][0].s && 0 == a[0][0][0].c); + assert ('\0' == *a[0][0][1].a && 0 == a[0][0][1].s && 0 == a[0][0][1].c); + assert ('\0' == *a[0][1][0].a && 0 == a[0][1][0].s && 0 == a[0][1][0].c); + assert ('\0' == *a[0][1][1].a && 0 == a[0][1][1].s && 0 == a[0][1][1].c); + + assert ('\0' == *a[1][0][0].a && 0 == a[1][0][0].s && 0 == a[1][0][0].c); + assert ('\0' == *a[1][0][1].a && '\0' == *a[1][0][1].s && 0 == a[1][0][1].c); + assert ('\0' == *a[1][1][0].a && 0 == a[1][1][0].s && 0 == a[1][1][0].c); + assert ('\0' == *a[1][1][1].a && 0 == a[1][1][1].s && 0 == a[1][1][1].c); + } + + { + const struct S a[2][2][2] = { + { }, + { + { { } }, + { { "", "" } } + } + }; + + assert ('\0' == *a[0][0][0].a && 0 == a[0][0][0].s); + assert ('\0' == *a[0][0][1].a && 0 == a[0][0][1].s); + assert ('\0' == *a[0][1][0].a && 0 == a[0][1][0].s); + assert ('\0' == *a[0][1][1].a && 0 == a[0][1][1].s); + + assert ('\0' == *a[1][0][0].a && 0 == a[1][0][0].s); + assert ('\0' == *a[1][0][1].a && 0 == a[1][0][1].s); + assert ('\0' == *a[1][1][0].a && '\0' == *a[1][1][0].s); + assert ('\0' == *a[1][1][1].a && 0 == a[1][1][1].s); + } + + { + const struct S a[2][2][2] = { + { }, + { + { { }, { } }, + { { }, { "", "", 0 } } + } + }; + + assert ('\0' == *a[0][0][0].a && 0 == a[0][0][0].s); + assert ('\0' == *a[0][0][1].a && 0 == a[0][0][1].s); + assert ('\0' == *a[0][1][0].a && 0 == a[0][1][0].s); + assert ('\0' == *a[0][1][1].a && 0 == a[0][1][1].s); + + assert ('\0' == *a[1][0][0].a && 0 == a[1][0][0].s); + assert ('\0' == *a[1][0][1].a && 0 == a[1][0][1].s); + assert ('\0' == *a[1][1][0].a && 0 == a[1][1][0].s); + assert ('\0' == *a[1][1][1].a && '\0' == *a[1][1][1].s); + } + + { + const struct S a[2][2][2] = { + { + { { { 0 }, 0, 0 }, { { 0 } , 0, 0 } }, + { { { 0 }, 0, 0 }, { { 0 } , 0, 0 } }, + }, + { + { { { 0 }, 0, 0 }, { { 0 } , 0, 0 } }, + { { }, { "", "", 0 } } + } + }; + + assert ('\0' == *a[0][0][0].a && 0 == a[0][0][0].s); + assert ('\0' == *a[0][0][1].a && 0 == a[0][0][1].s); + assert ('\0' == *a[0][1][0].a && 0 == a[0][1][0].s); + assert ('\0' == *a[0][1][1].a && 0 == a[0][1][1].s); + + assert ('\0' == *a[1][0][0].a && 0 == a[1][0][0].s); + assert ('\0' == *a[1][0][1].a && 0 == a[1][0][1].s); + assert ('\0' == *a[1][1][0].a && 0 == a[1][1][0].s); + assert ('\0' == *a[1][1][1].a && '\0' == *a[1][1][1].s); + } +} + +// { dg-final { scan-tree-dump-not "abort" "optimized" } } diff --git a/gcc/testsuite/g++.dg/abi/mangle73.C b/gcc/testsuite/g++.dg/abi/mangle73.C new file mode 100644 index 00000000000..2a5322a37c3 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle73.C @@ -0,0 +1,96 @@ +// { dg-do compile { target c++2a } } + +struct A +{ + char a[2][2]; +}; + +template struct B { }; + +typedef B AZZZZ; +typedef B AZZZ_; +typedef B AZZ__; +typedef B AZ___; +typedef B A____; + +typedef B AS_S_; +typedef B AS_ZZ; +typedef B AS_Z_; +typedef B AS___; + + +// Verify that the types mangle the same. +void a_zzzz (AZZZZ) { } +// { dg-final { scan-assembler "_Z6a_zzzz1BIXtl1AEEE" } } + +void a_zzz_ (AZZZ_) { } +// { dg-final { scan-assembler "_Z6a_zzz_1BIXtl1AEEE" } } + +void a_zz__ (AZZ__) { } +// { dg-final { scan-assembler "_Z6a_zz__1BIXtl1AEEE" } } + +void a_z___ (AZ___) { } +// { dg-final { scan-assembler "_Z6a_z___1BIXtl1AEEE" } } + +void a_____ (A____) { } +// { dg-final { scan-assembler "_Z6a_____1BIXtl1AEEE" } } + +void a_s_s_ (AS_S_) { } +// { dg-final { scan-assembler "_Z6a_s_s_1BIXtl1AEEE" } } + +void a_s_zz (AS_ZZ) { } +// { dg-final { scan-assembler "_Z6a_s_zz1BIXtl1AEEE" } } + +void a_s_z_ (AS_Z_) { } +// { dg-final { scan-assembler "_Z6a_s_z_1BIXtl1AEEE" } } + +void a_s___ (AS___) { } +// { dg-final { scan-assembler "_Z6a_s___1BIXtl1AEEE" } } + + +struct C +{ + struct { const char a[2][2], *p; } a[2]; +}; + +template struct D { }; + +typedef D DZZZZZZZZZZ; +typedef D DZZZZZZZZZ_; +typedef D DZZZZZZZZ__; +typedef D DZZZZZZZ___; +typedef D DZZZZZZ____; +typedef D DZZZZZ_____; +typedef D DZZZZ______; +typedef D DZZZ_______; +typedef D DZZ________; +typedef D DZ_________; +typedef D D__________; + +typedef D DS_S_ZS_S_Z; + +void d_zzzzzzzzzz (DZZZZZZZZZZ) { } +// { dg-final { scan-assembler "_Z12d_zzzzzzzzzz1DIXtl1CEEE" } } +void d_zzzzzzzzz_ (DZZZZZZZZZ_) { } +// { dg-final { scan-assembler "_Z12d_zzzzzzzzz_1DIXtl1CEEE" } } +void d_zzzzzzzz__ (DZZZZZZZZ__) { } +// { dg-final { scan-assembler "_Z12d_zzzzzzzz__1DIXtl1CEEE" } } +void d_zzzzzzz___ (DZZZZZZZ___) { } +// { dg-final { scan-assembler "_Z12d_zzzzzzz___1DIXtl1CEEE" } } +void d_zzzzzz____ (DZZZZZZ____) { } +// { dg-final { scan-assembler "_Z12d_zzzzzz____1DIXtl1CEEE" } } +void d_zzzzz_____ (DZZZZZ_____) { } +// { dg-final { scan-assembler "_Z12d_zzzzz_____1DIXtl1CEEE" } } +void d_zzzz______ (DZZZZ______) { } +// { dg-final { scan-assembler "_Z12d_zzzz______1DIXtl1CEEE" } } +void d_zzz_______ (DZZZ_______) { } +// { dg-final { scan-assembler "_Z12d_zzz_______1DIXtl1CEEE" } } +void d_zz________ (DZZ________) { } +// { dg-final { scan-assembler "_Z12d_zz________1DIXtl1CEEE" } } +void d_z_________ (DZ_________) { } +// { dg-final { scan-assembler "_Z12d_z_________1DIXtl1CEEE" } } +void d___________ (D__________) { } +// { dg-final { scan-assembler "_Z12d___________1DIXtl1CEEE" } } + +void d_s_s_zs_s_z (DS_S_ZS_S_Z) { } +// { dg-final { scan-assembler "_Z12d_s_s_zs_s_z1DIXtl1CEEE" } } diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class18.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class18.C new file mode 100644 index 00000000000..ab9e80fd335 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class18.C @@ -0,0 +1,102 @@ +// PR c++/90947 - Simple lookup table of array of strings is miscompiled +// Test to verify that the same specializations on non-type template +// parameters of class types are in fact treated as the same. Unlike +// nontype-class15.C which involves only one-dimensional arrays this +// test involves arrays of arrays and arrays of structs. +// { dg-do compile { target c++2a } } + +struct AA3 +{ + const char a[2][2][2]; +}; + +template struct BAA3 { }; + +// Redeclare the same variable using different initialization forms +// of the same constant to verify that they are in fact all recognized +// as the same. +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; +extern BAA3 baa3; + +extern BAA3 baa3_1; +extern BAA3 baa3_1; +extern BAA3 baa3_1; + +extern BAA3 baa3_2; +extern BAA3 baa3_2; +extern BAA3 baa3_2; +extern BAA3 baa3_2; + +extern BAA3 baa3_3; +extern BAA3 baa3_3; +extern BAA3 baa3_3; + +extern BAA3 baa3_4; +extern BAA3 baa3_4; +extern BAA3 baa3_4; + +struct AS2 +{ + struct S { const char a[2], *p; } a[2]; +}; + +template struct BAS2 { }; + +extern BAS2 bas2; +extern BAS2 bas2; +extern BAS2 bas2; +extern BAS2 bas2; +extern BAS2 bas2; +extern BAS2 bas2; +extern BAS2 bas2; +extern BAS2 bas2; +extern BAS2 bas2; +extern BAS2 bas2; +extern BAS2 bas2; +extern BAS2 bas2; + +struct AS2_2 +{ + struct S { const char a[2], *p; } a[2][2]; +}; + +template struct BAS2_2 { }; + +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; +extern BAS2_2 b2_2; diff --git a/gcc/tree.c b/gcc/tree.c index f65025f1089..ecc60b11a2c 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -11357,6 +11357,67 @@ initializer_each_zero_or_onep (const_tree expr) } } +/* Given an initializer INIT for a TYPE, return true if INIT is zero + so that it can be replaced by value initialization. This function + distinguishes betwen empty strings as initializers for arrays and + for pointers (which make it return false). */ + +bool +type_initializer_zero_p (tree type, tree init) +{ + STRIP_NOPS (init); + + if (POINTER_TYPE_P (type)) + return TREE_CODE (init) != STRING_CST && initializer_zerop (init); + + if (TREE_CODE (init) != CONSTRUCTOR) + return initializer_zerop (init); + + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree elt_type = TREE_TYPE (type); + elt_type = TYPE_MAIN_VARIANT (elt_type); + if (elt_type == char_type_node) + return initializer_zerop (init); + + tree elt_init; + unsigned HOST_WIDE_INT i; + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, elt_init) + if (!type_initializer_zero_p (elt_type, elt_init)) + return false; + return true; + } + + if (TREE_CODE (type) != RECORD_TYPE) + return initializer_zerop (init); + + tree fld = TYPE_FIELDS (type); + + tree fld_init; + unsigned HOST_WIDE_INT i; + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, fld_init) + { + while (TREE_CODE (fld) != FIELD_DECL + || DECL_ARTIFICIAL (fld)) + { + fld = DECL_CHAIN (fld); + if (!fld) + return true; + continue; + } + + tree fldtype = TREE_TYPE (fld); + if (!type_initializer_zero_p (fldtype, fld_init)) + return false; + + fld = DECL_CHAIN (fld); + if (!fld) + break; + } + + return true; +} + /* Check if vector VEC consists of all the equal elements and that the number of elements corresponds to the type of VEC. The function returns first element of the vector diff --git a/gcc/tree.h b/gcc/tree.h index 23ac9b1ff5e..1082b6dab96 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4558,6 +4558,12 @@ extern tree first_field (const_tree); extern bool initializer_zerop (const_tree, bool * = NULL); extern bool initializer_each_zero_or_onep (const_tree); +/* Analogous to initializer_zerop but examines the type for which + the initializer is being used but unlike it, considers empty + strings to be zero initializers for arrays and non-zero for + pointers. */ +extern bool type_initializer_zero_p (tree, tree); + extern wide_int vector_cst_int_elt (const_tree, unsigned int); extern tree vector_cst_elt (const_tree, unsigned int);