From patchwork Thu Jul 18 12:49:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1962097 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=L0I3qm60; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.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 ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WPt2071Vqz1xrQ for ; Thu, 18 Jul 2024 22:50:16 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E6899385DDE7 for ; Thu, 18 Jul 2024 12:50:13 +0000 (GMT) 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 3C3203858C53 for ; Thu, 18 Jul 2024 12:49:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3C3203858C53 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3C3203858C53 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1721306998; cv=none; b=KcNbGTARCo4UJOnEg8GDIq8TjZ+xjfmPZMMjQmq2P+zNg1YkjXIMBJMMGh4cCTAp58jPP3ob0P5TMqNhQarU2JZVat8CocoeyyVNz+X7Wn3qP8CfnNRSIxuYYHdcoDuwfsN1ALwW5y0dPJZhz45f9EZJuUfdRU9UWnHwUhcRQlc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1721306998; c=relaxed/simple; bh=6piS44ItSmDx3ufKFmNOolx9uKYyGFMlLJ7E4auVAps=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=tmcyPx0IJXRIGFHxVsRbGHs7LVskPpI+nx438mPvt1SWUCIhKwa+u+UymSteYk3GynZhPlp2bmSdwhQkbduGA+3L1jMuCih0cgAWWFiEANpbbpWftKYHmuknrOknAs5cooZ0stTKnap/0VbVrhj2EcUmeUejtC0yoe2yQtrB1Yg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721306995; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type; bh=fdp2cYhp+jEQyi2J/BwpElEHhwUZrGh1vbAYp5jMvo0=; b=L0I3qm60DL99/wm9RD7VzXGir9XUMc9E/SAZBbDBvHa/6VEz9pcwOLK7kGlWeEpDld7CR+ NG1L1iqTTeVBnZzRyQJieOmHWbp6xNyxgvrMjt3ASmga4m8wi+TZmAgDWcddd2BOFPnnKM kG1dlqQMhuYZotilgOG0BNOssg2d/6o= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-344-SlM9uKXuO7expyLv0z3oBw-1; Thu, 18 Jul 2024 08:49:53 -0400 X-MC-Unique: SlM9uKXuO7expyLv0z3oBw-1 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id AF7CD1955F3D for ; Thu, 18 Jul 2024 12:49:51 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.45.224.25]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id F33C43000185; Thu, 18 Jul 2024 12:49:49 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 46ICnlxB988763 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Thu, 18 Jul 2024 14:49:47 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 46ICnlBn988762; Thu, 18 Jul 2024 14:49:47 +0200 Date: Thu, 18 Jul 2024 14:49:46 +0200 From: Jakub Jelinek To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: Add [dcl.init.aggr] examples to testsuite Message-ID: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-0.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=no 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.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Hi! When working on the #embed optimization support, I went recently through all of reshape_init_r* and today I read in detail all the P3106R1 changes and I believe we implement it that way for years. To double check that, I've added tests with the current [dcl.init.aggr] examples but tested in all the languages from C++98 to C++26, of course guarded as needed for constructs which require newer versions of C++. The examples come in two tests, one is a runtime test for the non-erroneous examples, the other is a compile time test for the diagnostics. The former one includes mostly intact examples with runtime checking (both to test what is written in the section exactly and to test at least something with C++98) and then when useful also adds constexpr tests with static_asserts for C++11 and later. Tested on x86_64-linux and i686-linux with GXX_TESTSUITE_STDS=98,11,14,17,20,23,26 make check-g++ RUNTESTFLAGS='dg.exp=aggr-init*.C' Ok for trunk? Also tested on GCC 11 branch with GXX_TESTSUITE_STDS=98,11,14,17,20,2b make check-g++ RUNTESTFLAGS='dg.exp=aggr-init*.C' where just the " is a GCC extension" part of one error is left out, otherwise it passes the same, ditto with clang 14 (of course with different diagnostics, but verified it emits diagnostics on the right lines), so I believe we can claim implementation of this DR paper, either in all versions or at least in GCC 11+. 2024-07-18 Jakub Jelinek PR c++/114460 * g++.dg/cpp26/aggr-init1.C: New test. * g++.dg/cpp26/aggr-init2.C: New test. Jakub --- gcc/testsuite/g++.dg/cpp26/aggr-init1.C.jj 2024-07-18 12:25:03.767375097 +0200 +++ gcc/testsuite/g++.dg/cpp26/aggr-init1.C 2024-07-18 14:27:48.324677997 +0200 @@ -0,0 +1,341 @@ +// P3106R1 - Clarifying rules for brace elision in aggregate initialization +// Examples from C++26 [dcl.init.aggr] +// { dg-do run } + +extern "C" void abort (); + +namespace N1 { +#if __cpp_designated_initializers >= 201707L + struct C { + union { + int a; + const char* p; + }; + int x; + } c = { .a = 1, .x = 3 }; + constexpr C c2 = { .a = 1, .x = 3 }; + static_assert (c2.a == 1 && c2.x == 3, ""); +#endif + + bool + test () + { +#if __cpp_designated_initializers >= 201707L + return c.a == 1 && c.x == 3; +#else + return true; +#endif + } +} + +namespace N2 { + struct A { + int x; + struct B { + int i; + int j; + } b; + } a = { 1, { 2, 3 } }; + +#if __cplusplus >= 201703L + struct base1 { int b1, b2 = 42; }; + struct base2 { + base2 () { b3 = 42; } + int b3; + }; + struct derived : base1, base2 { + int d; + }; + + derived d1 { { 1, 2 }, {}, 4 }; + derived d2 { {}, {}, 4 }; +#endif + + bool + test () + { + return a.x == 1 && a.b.i == 2 && a.b.j == 3 +#if __cplusplus >= 201703L + && d1.b1 == 1 && d1.b2 == 2 && d1.b3 == 42 && d1.d == 4 + && d2.b1 == 0 && d2.b2 == 42 && d2.b3 == 42 && d2.d == 4 +#endif + ; + } + +#if __cplusplus >= 201703L + constexpr A a2 = { 1, { 2, 3 } }; + static_assert (a2.x == 1 && a2.b.i == 2 && a2.b.j == 3, ""); + + struct base3 { +#if __cplusplus >= 202002L + constexpr base3 () { b3 = 42; } +#else + constexpr base3 () : b3 (42) {} +#endif + int b3; + }; + struct derived2 : base1, base3 { + int d; + }; + constexpr derived2 d3 { { 1, 2}, {}, 4}; + constexpr derived2 d4 { {}, {}, 4 }; + static_assert (d3.b1 == 1 && d3.b2 == 2 && d3.b3 == 42 && d3.d == 4, ""); + static_assert (d4.b1 == 0 && d4.b2 == 42 && d4.b3 == 42 && d4.d == 4, ""); +#endif +} + +namespace N3 { +#if __cplusplus >= 201402L + struct S { int a; const char *b; int c; int d = b[a]; }; + S ss = { 1, "asdf" }; + constexpr S ss2 = { 1, "asdf" }; + static_assert (ss2.a == 1 && ss2.b[0] == 'a' && ss2.b[3] == 'f' && ss2.c == 0 && ss2.d == 's', ""); + +#if __cpp_designated_initializers >= 201707L + struct string { int s = -42; }; + struct A { + string a; + int b = 42; + int c = -1; + }; + static_assert (A { .c = 21 }.a.s == -42 && A { .c = 21 }.b == 42 && A { .c = 21 }.c == 21, ""); +#endif +#endif + + bool + test () + { +#if __cplusplus >= 201402L + return ss.a == 1 && __builtin_strcmp (ss.b, "asdf") == 0 && ss.c == 0 && ss.d == 's'; +#else + return true; +#endif + } +} + +namespace N4 { + int x[] = { 1, 3, 5 }; + + bool + test () + { + return sizeof (x) == 3 * sizeof (int) && x[0] == 1 && x[1] == 3 && x[2] == 5; + } + +#if __cplusplus >= 201103L + constexpr int x2[] = { 1, 3, 5 }; + static_assert (sizeof (x2) == 3 * sizeof (int) + && x2[0] == 1 && x2[1] == 3 && x2[2] == 5, ""); +#endif +} + +namespace N5 { + struct X { int i, j, k; }; + X a[] = { 1, 2, 3, 4, 5, 6 }; + X b[2] = { { 1, 2, 3 }, { 4, 5, 6 } }; + + bool + test () + { + return sizeof (a) == sizeof (b) && __builtin_memcmp (a, b, sizeof (a)) == 0; + } + +#if __cplusplus >= 201103L + constexpr X a2[] = { 1, 2, 3, 4, 5, 6 }; + constexpr X b2[2] = { { 1, 2, 3 }, { 4, 5, 6 } }; + static_assert (sizeof (a2) == 2 * sizeof (X) + && a2[0].i == 1 && a2[0].j == 2 && a2[0].k == 3 + && a2[1].i == 4 && a2[1].j == 5 && a2[1].k == 6, ""); + static_assert (sizeof (b2) == 2 * sizeof (X) + && b2[0].i == 1 && b2[0].j == 2 && b2[0].k == 3 + && b2[1].i == 4 && b2[1].j == 5 && b2[1].k == 6, ""); +#endif +} + +namespace N7 { + struct A { + int i; + static int s; + int j; + int : 17; + int k; + } a = { 1, 2, 3 }; + + bool + test () + { + return a.i == 1 && a.j == 2 && a.k == 3; + } + +#if __cplusplus >= 201103L + constexpr A a2 = { 1, 2, 3 }; + static_assert (a2.i == 1 && a2.j == 2 && a2.k == 3, ""); +#endif +} + +namespace N9 { + int x[2][2] = { 3, 1, 4, 2 }; + float y[4][3] = { + { 1 }, { 2 }, { 3 }, { 4 } + }; + + bool + test () + { + return x[0][0] == 3 && x[0][1] == 1 && x[1][0] == 4 && x[1][1] == 2 + && y[0][0] == 1.f && y[0][1] == 0.f && y[0][2] == 0.f + && y[1][0] == 2.f && y[1][1] == 0.f && y[1][2] == 0.f + && y[2][0] == 3.f && y[2][1] == 0.f && y[2][2] == 0.f + && y[3][0] == 4.f && y[3][1] == 0.f && y[3][2] == 0.f; + } + +#if __cplusplus >= 201103L + constexpr int x2[2][2] = { 3, 1, 4, 2 }; + constexpr float y2[4][3] = { + { 1 }, { 2 }, { 3 }, { 4 } + }; + static_assert (x2[0][0] == 3 && x2[0][1] == 1 && x2[1][0] == 4 && x2[1][1] == 2, ""); + static_assert (y2[0][0] == 1.f && y2[0][1] == 0.f && y2[0][2] == 0.f, ""); + static_assert (y2[1][0] == 2.f && y2[1][1] == 0.f && y2[1][2] == 0.f, ""); + static_assert (y2[2][0] == 3.f && y2[2][1] == 0.f && y2[2][2] == 0.f, ""); + static_assert (y2[3][0] == 4.f && y2[3][1] == 0.f && y2[3][2] == 0.f, ""); +#endif +} + +namespace N10 { + struct S1 { int a, b; }; + struct S2 { S1 s, t; }; + + S2 x[2] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + S2 y[2] = { + { + { 1, 2 }, + { 3, 4 } + }, + { + { 5, 6 }, + { 7, 8 } + } + }; + + bool + test () + { + return sizeof (x) == sizeof (y) && __builtin_memcmp (x, y, sizeof (x)) == 0; + } + +#if __cplusplus >= 201103L + constexpr S2 x2[2] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + constexpr S2 y2[2] = { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } }; + static_assert (x2[0].s.a == 1 && x2[0].s.b == 2 && x2[0].t.a == 3 && x2[0].t.b == 4, ""); + static_assert (x2[1].s.a == 5 && x2[1].s.b == 6 && x2[1].t.a == 7 && x2[1].t.b == 8, ""); + static_assert (y2[0].s.a == 1 && y2[0].s.b == 2 && y2[0].t.a == 3 && y2[0].t.b == 4, ""); + static_assert (y2[1].s.a == 5 && y2[1].s.b == 6 && y2[1].t.a == 7 && y2[1].t.b == 8, ""); +#endif +} + +namespace N12 { + float y[4][3] = { + { 1, 3, 5 }, + { 2, 4, 6 }, + { 3, 5, 7 }, + }; + float y2[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 }; + + bool + test () + { + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + if (y[i][j] != (i == 3 ? 0.f : (float) (i + 1 + j * 2)) + || y[i][j] != y2[i][j]) + return false; + return true; + } + +#if __cplusplus >= 201103L + constexpr float y3[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 }, }; + constexpr float y4[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 }; + static_assert (y3[0][0] == 1.f && y3[0][1] == 3.f && y3[0][2] == 5.f, ""); + static_assert (y3[1][0] == 2.f && y3[1][1] == 4.f && y3[1][2] == 6.f, ""); + static_assert (y3[2][0] == 3.f && y3[2][1] == 5.f && y3[2][2] == 7.f, ""); + static_assert (y3[3][0] == 0.f && y3[3][1] == 0.f && y3[3][2] == 0.f, ""); + static_assert (y4[0][0] == 1.f && y4[0][1] == 3.f && y4[0][2] == 5.f, ""); + static_assert (y4[1][0] == 2.f && y4[1][1] == 4.f && y4[1][2] == 6.f, ""); + static_assert (y4[2][0] == 3.f && y4[2][1] == 5.f && y4[2][2] == 7.f, ""); + static_assert (y4[3][0] == 0.f && y4[3][1] == 0.f && y4[3][2] == 0.f, ""); +#endif +} + +namespace N13 { + bool + test () + { + struct S { } s; + struct A { + S s1; + int i1; + S s2; + int i2; + S s3; + int i3; + } a = { + { }, + 0, + s, + 0 + }; + return a.i1 == 0 && a.i2 == 0; + } +} + +namespace N14 { + struct A { + int i; + operator int (); + }; + struct B { + A a1, a2; + int z; + }; + A a; + B b = { 4, a, a }; + A::operator int () { return 42; } + + bool + test () + { + return b.a1.i == 4 && b.a2.i == 0 && b.z == 42; + } + +#if __cplusplus >= 201103L + struct A2 { + int i; + constexpr operator int () const { return 42; } + }; + struct B2 { + A2 a1, a2; + int z; + }; + constexpr A2 a2 = { 26 }; + constexpr B2 b2 = { 4, a2, a2 }; + static_assert (b2.a1.i == 4 && b2.a2.i == 26 && b2.z == 42, ""); +#endif +} + +int +main () +{ + if (!N1::test () + || !N2::test () + || !N3::test () + || !N4::test () + || !N5::test () + || !N7::test () + || !N9::test () + || !N10::test () + || !N12::test () + || !N13::test () + || !N14::test ()) + abort (); +} --- gcc/testsuite/g++.dg/cpp26/aggr-init2.C.jj 2024-07-18 13:03:47.980808005 +0200 +++ gcc/testsuite/g++.dg/cpp26/aggr-init2.C 2024-07-18 14:31:20.930947591 +0200 @@ -0,0 +1,67 @@ +// P3106R1 - Clarifying rules for brace elision in aggregate initialization +// Examples from C++26 [dcl.init.aggr] +// { dg-do compile } + +namespace N1 { +#if __cpp_designated_initializers >= 201707L + struct C { + union { + int a; + const char* p; + }; + int x; + }; + constexpr C c2 = { .a = 42.0, .x = 3 }; // { dg-error "narrowing conversion of '4.2e\\\+1' from 'double' to 'int'" "" { target c++20 } } +#endif +} + +namespace N6 { +#if __cplusplus >= 201103L + struct S { + int y[] = { 0 }; // { dg-error "ISO C\\\+\\\+ forbids flexible array member 'y'" "" { target c++11 } } + // { dg-error "flexible array member 'N6::S::y' in an otherwise empty 'struct N6::S' is a GCC extension" "" { target c++11 } .-1 } + // { dg-error "initializer for flexible array member 'int N6::S::y \\\[\\\]'" "" { target c++11 } .-2 } + }; +#endif +} + +namespace N8 { +#if __cplusplus >= 201402L + struct A; + extern A a; + struct A { + const A &a1 { A { a, a } }; + const A &a2 { A { } }; // { dg-error "default member initializer for 'N8::A::a2' required before the end of its enclosing class" "" { target c++14 } } + }; // { dg-error "invalid initialization of reference of type 'const N8::A\\\&' from expression of type ''" "" { target c++14 } .-1 } + A a { a, a }; + + struct B { + int n = B {}.n; // { dg-error "default member initializer for 'N8::B::n' required before the end of its enclosing class" "" { target c++14 } } + }; + + struct C; + extern C c; + struct C { + const C &c1 { C { c, c } }; + const C &c2 { C { c, c } }; + }; + C c { c, c }; +#endif +} + +namespace N11 { + char cv[4] = { 'a', 's', 'd', 'f', 0 }; // { dg-error "too many initializers for 'char \\\[4\\\]'" } +} + +namespace N15 { + union u { int a; const char* b; }; + u a = { 1 }; + u b = a; + u c = 1; // { dg-error "conversion from 'int' to non-scalar type 'N15::u' requested" } + u d = { 0, "asdf" }; // { dg-error "too many initializers for 'N15::u'" } + u e = { "asdf" }; // { dg-error "invalid conversion from 'const char\\\*' to 'int'" } +#if __cpp_designated_initializers >= 201707L + u f = { .b = "asdf" }; + u g = { .a = 1, .b = "asdf" }; // { dg-error "too many initializers for 'N15::u'" "" { target c++20 } } +#endif +}