From patchwork Thu Nov 16 21:38:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1864888 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=ulv5LaWD; 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 4SWYLd4MT8z1yRy for ; Fri, 17 Nov 2023 08:38:29 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 934933858C54 for ; Thu, 16 Nov 2023 21:38:26 +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 1437D3858CD1 for ; Thu, 16 Nov 2023 21:38:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1437D3858CD1 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 1437D3858CD1 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=1700170695; cv=none; b=S8vsOMY2eKsNZxZLXjIzCCk1YOsvET9Rh4zxpVxeRWB6fxC9Z8u+Uqn2oWjKKIbtlC1VXfK3xlFkl3oCIZzZ9j6dNC7PJSEb6Mwob1Vs3KYRFdRzZLKyz4EOeYf69BVPsq5Q3xFnCOLMqAFVS3Gnuo1cdFbZbcTaCfnfH3lMsKc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700170695; c=relaxed/simple; bh=KnycLNXh2d0v7JAOaHM3YhXzWMnSAB3v9dAqhy7lKVo=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=OzQ/PgVHPneogpdayxAxuMz95KB3n+Cm/xgIPBtwB4SoqSoONkePndbNw2HRnzcs2+U3TIszbh9j0aTNZP0rFYJKSj5oTV+tten8c9Bnh/O1fE2TWxrmna1nOSjdxEyKkYCeVN8kPmYYVyE+BTeHKXiAms5I8xFvjh2kJNMqp34= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from vra-171-78.tugraz.at (vra-171-78.tugraz.at [129.27.171.78]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4SWYL90jLgz3wVP; Thu, 16 Nov 2023 22:38:09 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1700170689; bh=2qUt5BI0VECurespZVc/FzXPyIz3HAOC/ciPAgeFGBA=; h=Subject:From:To:Cc:Date:In-Reply-To:References; b=ulv5LaWDvo234iZxZFdwNTP4xBCl5mGhbs9v+YFcLitCWAa7QRkNpF6M7y4Z5tnka kH+cgQkJyzqpZRC1c0xCrI4ngtw9NLHZSWfROwHj8JIgF4hUudjsMHokW7m+GChLuD WNlYGTAOW/kY08wyxxN4ZA4wIQvsleHo44s8EgvE= Message-ID: <3e5e3ecbfd65851bbee77c7c70644b50d3d0895a.camel@tugraz.at> Subject: [PATCH 1/4] c23: tag compatibility rules for struct and unions From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Thu, 16 Nov 2023 22:38:08 +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.117 X-Spam-Status: No, score=-10.7 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 Implement redeclaration and compatibility rules for structures and unions in C23. gcc/c/: * c-decl.cc (previous_tag): New function. (get_parm_info): Turn off warning for C2X. (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): Ingore 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 | 62 ++++++++++++++++++++++++--- 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 | 25 +++++++++++ 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, 411 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..194dd595334 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)); } + +/* Subroutine of finish_struct. 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, @@ -8782,6 +8807,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 +9609,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..f8eb5698af5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-6.c @@ -0,0 +1,25 @@ +/* + * { dg-do compile } + * { dg-options "-std=c23" } + */ + +// (in-)completeness + +struct foo { + char x[10]; +} x; + +struct foo { + _Static_assert(_Generic(&x, struct foo*: 0, default: 1)); + char x[_Generic(&x, struct foo*: 1, default: 10)]; +}; + +void f(void) +{ + struct foo { char x[_Generic(&x, struct foo*: 1, default: 10)]; }; + + struct foo z; + _Static_assert(10 == sizeof(z.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..7ec121fe80e --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-tag-3.c @@ -0,0 +1,28 @@ +/* + * { dg-do compile } + * { dg-options "-Wno-vla -std=gnu2x" } + */ + +// 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; } +} + +