From patchwork Mon Nov 27 13:16:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1868808 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=tugraz.at header.i=@tugraz.at header.a=rsa-sha256 header.s=mailrelay header.b=g3/e/2E9; 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 4Sf5ht009sz1yRy for ; Tue, 28 Nov 2023 00:17:00 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0640338582AA for ; Mon, 27 Nov 2023 13:16:53 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mailrelay.tugraz.at (mailrelay.tugraz.at [129.27.2.202]) by sourceware.org (Postfix) with ESMTPS id E4BFC3858CD1 for ; Mon, 27 Nov 2023 13:16:32 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E4BFC3858CD1 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=tugraz.at Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tugraz.at ARC-Filter: OpenARC Filter v1.0.0 sourceware.org E4BFC3858CD1 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=129.27.2.202 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701090996; cv=none; b=WB90oP3eOzzk+g9FYjX94PdaNqWApgKq5TxyB9SUYz4NJqBsQuCga9aS5c2oM8ltAATf3F2wVp7Z/zagSLJIRMOF5I58IlbzZjpcbwLs/yp1r23uiWGeuL9JkEuChJBM/LGKrJeIP1reUt9XnzwdROO8+eF1aE2sxzlWS4Tx1zM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701090996; c=relaxed/simple; bh=3llAL0ZAHkeQyXkFzHC0Ue7DUanH2/4JbmllKu/3Ynk=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=xecDmk4Qv/Jdef27/jakSj6/D7LbA5GDptum/hoPfMknbrD1fEWsmqI4xgFgtjHecWlYPFdWDg5vwl5SEDZeT/sCWIW0yCTMYBY8kDHabg0/XOXSylFojEZVB/nM7m2EnjJ4i3MRZX1wBsrgRUuI36Z57HkPXc3foq/JSGYEFA0= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from fbmtpc21.tugraz.at (fbmtpc21.tugraz.at [129.27.144.40]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4Sf5hF2c7Zz3wcP; Mon, 27 Nov 2023 14:16:29 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1701090989; bh=PSQdSLGDqZMOucIEousJgi96n60oDx9TMxyTV9LrmpM=; h=Subject:From:To:Cc:Date:In-Reply-To:References; b=g3/e/2E9drKve0Xe8aUXV/43Ay4Jp6YK/5BV0RXvN5pMiNekR6e02H+QhGMfoHSLw 9h92Ri1FlUX+Rggv296YGPqS3GxhJlHqqwwFLuqrG1yV3Mqwq38OuuowGjAN0Plc0s xUzEWPadmBzYNGLs9PlEqc0nZZ2AI0ekR0/BEbIw= Message-ID: <85008511e64113eaf86afa8b546ed55fd3620177.camel@tugraz.at> Subject: [V4] [C PATCH 1/4] c23: tag compatibility rules for struct and unions From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Mon, 27 Nov 2023 14:16:29 +0100 In-Reply-To: <02a9b94e4d653b6f1b9f89a1b62187f46e871738.camel@tugraz.at> References: <02a9b94e4d653b6f1b9f89a1b62187f46e871738.camel@tugraz.at> User-Agent: Evolution 3.46.4-2 MIME-Version: 1.0 X-TUG-Backscatter-control: G/VXY7/6zeyuAY/PU2/0qw X-Spam-Scanner: SpamAssassin 3.003001 X-Spam-Score-relay: -1.9 X-Scanned-By: MIMEDefang 2.74 on 129.27.10.116 X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, 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.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Note that there is an additional change in parser_xref_tag to address the issue regarding completeness in redefinition which affects also structs / unions. The test c23-tag-6.c was changed accordingly. c23: tag compatibility rules for struct and unions Implement redeclaration and compatibility rules for structures and unions in C23. gcc/c/: * c-decl.cc (previous_tag): New function. (parser_xref_tag): Find earlier definition. (get_parm_info): Turn off warning for C23. (start_struct): Allow redefinitons. (finish_struct): Diagnose conflicts. * c-tree.h (comptypes_same_p): Add prototype. * c-typeck.cc (comptypes_same_p): New function (comptypes_internal): Activate comparison of tagged types. (convert_for_assignment): Ignore qualifiers. (digest_init): Add error. (initialized_elementwise_p): Allow compatible types. gcc/testsuite/: * gcc.dg/c23-enum-7.c: Remove warning. * gcc.dg/c23-tag-1.c: New test. * gcc.dg/c23-tag-2.c: New deactivated test. * gcc.dg/c23-tag-3.c: New test. * gcc.dg/c23-tag-4.c: New test. * gcc.dg/c23-tag-5.c: New deactivated test. * gcc.dg/c23-tag-6.c: New test. * gcc.dg/c23-tag-7.c: New test. * gcc.dg/c23-tag-8.c: New test. * gcc.dg/gnu23-tag-1.c: New test. * gcc.dg/gnu23-tag-2.c: New test. * gcc.dg/gnu23-tag-3.c: New test. * gcc.dg/gnu23-tag-4.c: New test. --- gcc/c/c-decl.cc | 72 +++++++++++++++++++++++++++--- gcc/c/c-tree.h | 1 + gcc/c/c-typeck.cc | 38 +++++++++++++--- gcc/testsuite/gcc.dg/c23-enum-7.c | 6 +-- gcc/testsuite/gcc.dg/c23-tag-1.c | 67 +++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c23-tag-2.c | 43 ++++++++++++++++++ gcc/testsuite/gcc.dg/c23-tag-3.c | 16 +++++++ gcc/testsuite/gcc.dg/c23-tag-4.c | 26 +++++++++++ gcc/testsuite/gcc.dg/c23-tag-5.c | 33 ++++++++++++++ gcc/testsuite/gcc.dg/c23-tag-6.c | 58 ++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c23-tag-7.c | 12 +++++ gcc/testsuite/gcc.dg/c23-tag-8.c | 10 +++++ gcc/testsuite/gcc.dg/gnu23-tag-1.c | 10 +++++ gcc/testsuite/gcc.dg/gnu23-tag-2.c | 19 ++++++++ gcc/testsuite/gcc.dg/gnu23-tag-3.c | 28 ++++++++++++ gcc/testsuite/gcc.dg/gnu23-tag-4.c | 31 +++++++++++++ 16 files changed, 454 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c23-tag-1.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-2.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-3.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-4.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-5.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-6.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-7.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-8.c create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-1.c create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-2.c create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-3.c create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-4.c diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 64d3a941cb9..ebe1708b977 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -2039,6 +2039,28 @@ locate_old_decl (tree decl) decl, TREE_TYPE (decl)); } + +/* Helper function. For a tagged type, it finds the declaration + for a visible tag declared in the the same scope if such a + declaration exists. */ +static tree +previous_tag (tree type) +{ + struct c_binding *b = NULL; + tree name = TYPE_NAME (type); + + if (name) + b = I_TAG_BINDING (name); + + if (b) + b = b->shadowed; + + if (b && B_IN_CURRENT_SCOPE (b)) + return b->decl; + + return NULL_TREE; +} + /* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL. Returns true if the caller should proceed to merge the two, false if OLDDECL should simply be discarded. As a side effect, issues @@ -8573,11 +8595,14 @@ get_parm_info (bool ellipsis, tree expr) if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE) { if (b->id) - /* The %s will be one of 'struct', 'union', or 'enum'. */ - warning_at (b->locus, 0, - "%<%s %E%> declared inside parameter list" - " will not be visible outside of this definition or" - " declaration", keyword, b->id); + { + /* The %s will be one of 'struct', 'union', or 'enum'. */ + if (!flag_isoc23) + warning_at (b->locus, 0, + "%<%s %E%> declared inside parameter list" + " will not be visible outside of this definition or" + " declaration", keyword, b->id); + } else /* The %s will be one of 'struct', 'union', or 'enum'. */ warning_at (b->locus, 0, @@ -8668,6 +8693,16 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name, present, only a definition in the current scope is relevant. */ ref = lookup_tag (code, name, has_enum_type_specifier, &refloc); + + /* If the visble type is still being defined, see if there is + an earlier definition (which may be complete). */ + if (flag_isoc23 && ref && C_TYPE_BEING_DEFINED (ref)) + { + tree vis = previous_tag (ref); + if (vis) + ref = vis; + } + /* If this is the right type of tag, return what we found. (This reference will be shadowed by shadow_tag later if appropriate.) If this is the wrong type of tag, do not return it. If it was the @@ -8782,6 +8817,14 @@ start_struct (location_t loc, enum tree_code code, tree name, if (name != NULL_TREE) ref = lookup_tag (code, name, true, &refloc); + + /* For C23, even if we already have a completed definition, + we do not use it. We will check for consistency later. + If we are in a nested redefinition the type is not + complete. We will then detect this below. */ + if (flag_isoc23 && ref && TYPE_SIZE (ref)) + ref = NULL_TREE; + if (ref && TREE_CODE (ref) == code) { if (TYPE_STUB_DECL (ref)) @@ -9576,6 +9619,25 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, warning_at (loc, 0, "union cannot be made transparent"); } + /* Check for consistency with previous definition. */ + if (flag_isoc23) + { + tree vistype = previous_tag (t); + if (vistype + && TREE_CODE (vistype) == TREE_CODE (t) + && !C_TYPE_BEING_DEFINED (vistype)) + { + TYPE_STUB_DECL (vistype) = TYPE_STUB_DECL (t); + if (c_type_variably_modified_p (t)) + error ("redefinition of struct or union %qT with variably " + "modified type", t); + else if (!comptypes_same_p (t, vistype)) + error ("redefinition of struct or union %qT", t); + } + } + + C_TYPE_BEING_DEFINED (t) = 0; + tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)); for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) { diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index c6f38ec94a0..7df4d65bf7a 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -756,6 +756,7 @@ extern tree c_objc_common_truthvalue_conversion (location_t, tree); extern tree require_complete_type (location_t, tree); extern bool same_translation_unit_p (const_tree, const_tree); extern int comptypes (tree, tree); +extern bool comptypes_same_p (tree, tree); extern int comptypes_check_different_types (tree, tree, bool *); extern int comptypes_check_enum_int (tree, tree, bool *); extern bool c_mark_addressable (tree, bool = false); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 1dbb4471a88..dc8a16df272 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1080,6 +1080,23 @@ comptypes (tree type1, tree type2) return ret ? (data.warning_needed ? 2 : 1) : 0; } + +/* Like comptypes, but it returns non-zero only for identical + types. */ + +bool +comptypes_same_p (tree type1, tree type2) +{ + struct comptypes_data data = { }; + bool ret = comptypes_internal (type1, type2, &data); + + if (data.different_types_p) + return false; + + return ret; +} + + /* Like comptypes, but if it returns non-zero because enum and int are compatible, it sets *ENUM_AND_INT_P to true. */ @@ -1266,11 +1283,11 @@ comptypes_internal (const_tree type1, const_tree type2, case ENUMERAL_TYPE: case RECORD_TYPE: case UNION_TYPE: - if (false) - { - return tagged_types_tu_compatible_p (t1, t2, data); - } - return false; + + if (!flag_isoc23) + return false; + + return tagged_types_tu_compatible_p (t1, t2, data); case VECTOR_TYPE: return known_eq (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2)) @@ -7031,7 +7048,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, /* Aggregates in different TUs might need conversion. */ if ((codel == RECORD_TYPE || codel == UNION_TYPE) && codel == coder - && comptypes (type, rhstype)) + && comptypes (TYPE_MAIN_VARIANT (type), TYPE_MAIN_VARIANT (rhstype))) return convert_and_check (expr_loc != UNKNOWN_LOCATION ? expr_loc : location, type, rhs); @@ -8401,6 +8418,13 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, conversion. */ inside_init = convert (type, inside_init); + if ((code == RECORD_TYPE || code == UNION_TYPE) + && !comptypes (TYPE_MAIN_VARIANT (type), TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)))) + { + error_init (init_loc, "invalid initializer"); + return error_mark_node; + } + if (require_constant && TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR) { @@ -10486,7 +10510,7 @@ initialize_elementwise_p (tree type, tree value) return !VECTOR_TYPE_P (value_type); if (AGGREGATE_TYPE_P (type)) - return type != TYPE_MAIN_VARIANT (value_type); + return !comptypes (type, TYPE_MAIN_VARIANT (value_type)); return false; } diff --git a/gcc/testsuite/gcc.dg/c23-enum-7.c b/gcc/testsuite/gcc.dg/c23-enum-7.c index c9ef0882b41..ff8e145c2a8 100644 --- a/gcc/testsuite/gcc.dg/c23-enum-7.c +++ b/gcc/testsuite/gcc.dg/c23-enum-7.c @@ -26,17 +26,15 @@ enum e13 : short x13; /* { dg-error "'enum' underlying type may not be specified enum e14 : short f14 (); /* { dg-error "'enum' underlying type may not be specified here" } */ typeof (enum e15 : long) x15; /* { dg-error "'enum' underlying type may not be specified here" } */ int f16 (enum e16 : char p); /* { dg-error "'enum' underlying type may not be specified here" } */ -/* { dg-warning "will not be visible outside of this definition or declaration" "warning" { target *-*-* } .-1 } */ int f17 (enum e17 : char); /* { dg-error "'enum' underlying type may not be specified here" } */ -/* { dg-warning "will not be visible outside of this definition or declaration" "warning" { target *-*-* } .-1 } */ struct s18 { enum e18 : int x; }; /* { dg-error "'enum' underlying type may not be specified here" } */ /* But those are OK if the enum content is defined. */ enum e19 : short { E19 } x19; enum e20 : long { E20 } f20 (); typeof (enum e21 : long { E21 }) x21; -int f22 (enum e22 : long long { E22 } p); /* { dg-warning "will not be visible outside of this definition or declaration" } */ -int f23 (enum e23 : long long { E23 } p); /* { dg-warning "will not be visible outside of this definition or declaration" } */ +int f22 (enum e22 : long long { E22 } p); +int f23 (enum e23 : long long { E23 } p); struct s24 { enum e24 : int { E24 } x; }; /* Incompatible kinds of tags in the same scope are errors. */ diff --git a/gcc/testsuite/gcc.dg/c23-tag-1.c b/gcc/testsuite/gcc.dg/c23-tag-1.c new file mode 100644 index 00000000000..4a6207ec626 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-1.c @@ -0,0 +1,67 @@ +/* + * { dg-do compile } + * { dg-options "-std=c23" } + */ + +// allowed and forbidden redefinitions of the same struct/union in the same scope + +typedef struct p { int a; } pd_t; +typedef struct p { int a; } pd_t; + +typedef struct bar { int x; } X; +typedef struct bar { float x; } Y; /* { dg-error "redefinition of struct or union" } */ + +void test(void) +{ + struct foo { int x; }; + struct foo { float x; }; /* { dg-error "redefinition of struct or union" } */ +} + +struct aa { int a; }; + +void f(void) +{ + typedef struct aa A; + struct bb { struct aa a; } x; + struct aa { int a; }; + typedef struct aa A; /* { dg-error "redefinition" } */ + struct bb { struct aa a; } y; /* { dg-error "redefinition of struct or union" } */ + (void)x; (void)y; +} + + + +void h(void) +{ + struct a2 { int a; }; + { + typedef struct a2 A; + struct b2 { struct a2 a; } x; + struct a2 { int a; }; + typedef struct a2 A; /* { dg-error "redefinition" } */ + struct b2 { struct a2 a; } y; /* { dg-error "redefinition of struct or union" } */ + (void)x; (void)y; + } +} + + +union cc { int x; float y; } z; +union cc { int x; float y; } z1; +union cc { float y; int x; } z2; /* { dg-error "redefinition of struct or union" } */ + +void g(void) +{ + struct s { int a; }; + struct s { int a; } x0; + struct p { struct s c; } y1 = { x0 }; + struct p { struct s { int a; } c; } y = { x0 }; +} + +struct q { struct { int a; }; }; +struct q { struct { int a; }; }; +struct q { int a; }; /* { dg-error "redefinition of struct or union" } */ + +struct r { int a; char b[]; }; +struct r { int a; char b[]; }; +struct r { int a; char b[1]; }; /* { dg-error "redefinition of struct or union" } */ + diff --git a/gcc/testsuite/gcc.dg/c23-tag-2.c b/gcc/testsuite/gcc.dg/c23-tag-2.c new file mode 100644 index 00000000000..5dd4a21e9df --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-2.c @@ -0,0 +1,43 @@ +/* { dg-do compile { target { ! "*-*-*" } } } + * { dg-options "-std=c23" } + */ + +// compatibility of structs in assignment + +typedef struct p { int a; } pd_t; + +void test1(void) +{ + pd_t y0; + struct p { int a; } x; + y0 = x; +} + +void test2(void) +{ + struct p { int a; } x; + struct p y0 = x; +} + +void test3(void) +{ + struct p { int a; } x; + pd_t y0 = x; +} + +typedef struct p { int a; } p2_t; + +void test4(void) +{ + p2_t x; + pd_t y0 = x; +} + +void test5(void) +{ + struct q { int a; } a; + struct q { int a; } b; + a = b; +} + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-3.c b/gcc/testsuite/gcc.dg/c23-tag-3.c new file mode 100644 index 00000000000..4847e783c82 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-3.c @@ -0,0 +1,16 @@ +/* + * { dg-do compile } + * { dg-options "-std=c23" } + */ + +// conflicting types via linkage + +extern struct foo { int x; } x; +extern struct bar { float x; } y; + +void test(void) +{ + extern struct foo { int x; } x; + extern struct bar { int x; } y; /* { dg-error "conflicting types" } */ +} + diff --git a/gcc/testsuite/gcc.dg/c23-tag-4.c b/gcc/testsuite/gcc.dg/c23-tag-4.c new file mode 100644 index 00000000000..8083c43f607 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-4.c @@ -0,0 +1,26 @@ +/* + * { dg-do compile } + * { dg-options "-std=c23" } + */ + +// conflicting types for anonymous structs / unions + +extern struct { int x; } a; +extern struct { int x; } a; /* { dg-error "conflicting types" } */ + +extern union { int x; } b; +extern union { int x; } b; /* { dg-error "conflicting types" } */ + +typedef struct { int x; } u; +typedef struct { int x; } v; + +u c; +v c; /* { dg-error "conflicting types" } */ + +typedef union { int x; } q; +typedef union { int x; } r; + +q d; +r d; /* { dg-error "conflicting types" } */ + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-5.c b/gcc/testsuite/gcc.dg/c23-tag-5.c new file mode 100644 index 00000000000..ff40d07aef1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-5.c @@ -0,0 +1,33 @@ +/* { dg-do run { target { ! "*-*-*" } } } + * { dg-options "-std=c23" } + */ + +// nesting and parameters + +#define product_type(T, A, B) \ +struct product_ ## T { A a ; B b ; } +#define sum_type(T, A, B) \ +struct sum_ ## T { _Bool flag ; union { A a ; B b ; }; } + +float foo1(product_type(iSfd_, int, sum_type(fd, float, double)) x) +{ + return x.b.a; +} + +static void test1(void) +{ + product_type(iSfd_, int, sum_type(fd, float, double)) y = { 3, { 1, { .a = 1. } } }; + product_type(iSfd_, int, sum_type(fd, float, double)) z = y; + product_type(iSfd_, int, sum_type(fd, float, double)) *zp = &y; + float a = foo1(y); + product_type(iSid_, int, sum_type(id, int, double)) *wp = &y; /* { dg-warning "incompatible pointer type" } */ + float b = foo1(y); + product_type(iSid_, int, sum_type(id, int, double)) w = *wp; + (void)a; (void)b; (void)z; (void)zp; (void)w; (void)wp; +} + +int main() +{ + test1(); +} + diff --git a/gcc/testsuite/gcc.dg/c23-tag-6.c b/gcc/testsuite/gcc.dg/c23-tag-6.c new file mode 100644 index 00000000000..1b65ed3e35d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-6.c @@ -0,0 +1,58 @@ +/* + * { dg-do compile } + * { dg-options "-std=c23" } + */ + +// (in-)completeness + +struct foo { + char x[10]; +} x; + +// complete, same type + +struct foo { + _Static_assert(_Generic(&x, struct foo*: 1, default: 0)); + char x[_Generic(&x, struct foo*: 10, default: 1)]; + _Static_assert(_Generic(0, struct foo: 0, default: 1)); +}; + +// incomplete, same type + +struct bar* p; +struct bar { + _Static_assert(_Generic(p, struct bar*: 1, default: 0)); + char x[_Generic(p, struct bar*: 10, default: 1)]; + _Static_assert(_Generic(0, struct bar: 0, default: 1)); /* { dg-error "incomplete type" } */ +}; + +struct bar { + char x[10]; +}; + +struct h *hp; + +void f(void) +{ + // again incomplete, different type + + struct foo { + char x[_Generic(&x, struct foo*: 1, default: 10)]; + _Static_assert(_Generic(0, struct foo: 0, default: 1)); /* { dg-error "incomplete type" } */ + }; + + struct foo z; + _Static_assert(10 == sizeof(z.x), ""); + + // still incomplete, different type + + struct h { + char x[_Generic(hp, struct h*: 1, default: 10)]; + _Static_assert(_Generic(0, struct h: 0, default: 1)); /* { dg-error "incomplete type" } */ + }; + + struct h y; + _Static_assert(10 == sizeof(y.x), ""); +} + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-7.c b/gcc/testsuite/gcc.dg/c23-tag-7.c new file mode 100644 index 00000000000..dd3b5988e24 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-7.c @@ -0,0 +1,12 @@ +/* + * { dg-do compile } + * { dg-options "-std=c23" } + */ + +// recursive declarations + +extern struct bar { struct bar* p; int x; } b; +extern struct bar { struct bar* p; int x; } b; + +struct foo { struct foo { struct foo* p; int x; }* p; int x; } a; /* { dg-error "nested" } */ + diff --git a/gcc/testsuite/gcc.dg/c23-tag-8.c b/gcc/testsuite/gcc.dg/c23-tag-8.c new file mode 100644 index 00000000000..8b3b5ef5dfe --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-8.c @@ -0,0 +1,10 @@ +/* { dg-do compile } + { dg-options "-std=c23" } */ + +void foo(void) +{ + struct bar { struct bar* next; }; + struct bar { struct bar* next; }; + struct bar { struct bar { struct bar* next; }* next; }; /* { dg-error "nested" } */ +} + diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-1.c b/gcc/testsuite/gcc.dg/gnu23-tag-1.c new file mode 100644 index 00000000000..3c0303d4c3f --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-tag-1.c @@ -0,0 +1,10 @@ +/* + * { dg-do compile } + * { dg-options "-std=gnu23" } + */ + +struct r { int a; char b[]; }; +struct r { int a; char b[0]; }; /* allowed GNU extension */ +struct r { int a; char b[1]; }; /* { dg-error "redefinition of struct or union" } */ + + diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-2.c b/gcc/testsuite/gcc.dg/gnu23-tag-2.c new file mode 100644 index 00000000000..73725c79ebf --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-tag-2.c @@ -0,0 +1,19 @@ +/* + * { dg-do compile } + * { dg-options "-std=gnu23" } + */ + +// conflicting attributes + +extern struct __attribute__(( transaction_safe )) foo { int x; } x; +extern struct __attribute__(( unused )) foo2 { int x; } x2; +extern struct __attribute__(( may_alias )) foo3 { int x; } x3; + +void test(void) +{ + extern struct foo { int x; } x; /* { dg-error "conflicting types" } */ + extern struct foo2 { int x; } x2; + extern struct foo3 { int x; } x3; +} + + diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-3.c b/gcc/testsuite/gcc.dg/gnu23-tag-3.c new file mode 100644 index 00000000000..8919144ef3a --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-tag-3.c @@ -0,0 +1,28 @@ +/* + * { dg-do compile } + * { dg-options "-Wno-vla -std=gnu23" } + */ + +// arrays in structs + +void foo(int n, int m) +{ + struct f { int b; int a[n]; }; + struct f { int b; int a[n]; }; /* { dg-error "redefinition of struct or union" } */ + struct f { int b; int a[m]; }; /* { dg-error "redefinition of struct or union" } */ + struct f { int b; int a[5]; }; /* { dg-error "redefinition of struct or union" } */ + struct f { int b; int a[]; }; /* { dg-error "redefinition of struct or union" } */ + + struct g { int a[n]; int b; }; + struct g { int a[n]; int b; }; /* { dg-error "redefinition of struct or union" } */ + struct g { int a[m]; int b; }; /* { dg-error "redefinition of struct or union" } */ + struct g { int a[4]; int b; }; /* { dg-error "redefinition of struct or union" } */ + + struct h { int (*a)[n]; int b; }; + struct h { int (*a)[n]; int b; }; /* { dg-error "redefinition of struct or union" } */ + struct h { int (*a)[m]; int b; }; /* { dg-error "redefinition of struct or union" } */ + struct h { int (*a)[4]; int b; }; /* { dg-error "redefinition of struct or union" } */ + struct h { int (*a)[]; int b; }; /* { dg-error "redefinition of struct or union" } */ +} + + diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-4.c b/gcc/testsuite/gcc.dg/gnu23-tag-4.c new file mode 100644 index 00000000000..8db81c7b87d --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-tag-4.c @@ -0,0 +1,31 @@ +/* { dg-do compile } + * { dg-options "-std=gnu23" } */ + +// structs with variably modified types + +void bar(int n, int m) +{ + struct f { int b; int a[n]; } *x; + { struct f { int b; int a[n]; } *x2 = x; } + { struct f { int b; int a[m]; } *x2 = x; } + { struct f { int b; int a[5]; } *x2 = x; } + { struct f { int b; int a[0]; } *x2 = x; } + { struct f { int b; int a[]; } *x2 = x; } + + struct g { int a[n]; int b; } *y; + { struct g { int a[n]; int b; } *y2 = y; } + { struct g { int a[m]; int b; } *y2 = y; } + { struct g { int a[4]; int b; } *y2 = y; } + + struct h { int b; int a[5]; } *w; + { struct h { int b; int a[5]; } *w2 = w; } + { struct h { int b; int a[n]; } *w2 = w; } + { struct h { int b; int a[m]; } *w2 = w; } + + struct i { int b; int (*a)(int c[n]); } *u; + { struct i { int b; int (*a)(int c[4]); } *u2 = u; } + { struct i { int b; int (*a)(int c[]); } *u2 = u; } + { struct i { int b; int (*a)(int c[*]); } *u2 = u; } +} + +