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; } +} + + From patchwork Thu Nov 16 21:38:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1864889 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=jA5ftzsS; 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 4SWYMH5MwKz1yRy for ; Fri, 17 Nov 2023 08:39:07 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 468FF3858C42 for ; Thu, 16 Nov 2023 21:39:05 +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 91DE93858D28 for ; Thu, 16 Nov 2023 21:38:52 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 91DE93858D28 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 91DE93858D28 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=1700170735; cv=none; b=TekSKkYrYMu/A6PMA23Kttuju8pXe7bTCHkpLuNA8Lc4kjE1msJsQ2kkFHShSViV3Xhh7pFVsFkqq+1L/w3uP1e21ibar8D/PhyxO0QkEw2y0qMOpamXqyB3LjsmwD9HYB35H0IYbpbtMfEbTSsYA7ag5rmgaB+SMI95cJhsZiE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700170735; c=relaxed/simple; bh=enC9Ry4DXNRpW12an8cuk4BbSIm6/DPeEB0YUtRGN/Y=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=ebaLyGbkrCiDAXVNmpRAOs/aGuVmFe5iMDrIaVO+JY0ZdrFFmvsxY7Njy+PU0NcdBbZGQPZsMPWgL21qIxjCo683u3NzxiNxWKqNsgLgRaQrHlaPaPkaYnMCBDWj1XH3mV+Yzq+aLfaYZEU9aSvV6AaknsFhi2PgQx4kO5hiWdQ= 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 4SWYLv3s5Pz3wkZ; Thu, 16 Nov 2023 22:38:47 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1700170727; bh=pbzbjWqXCD5U+hEmdt8n4zERR8xgwm1ltTonBxT3tuM=; h=Subject:From:To:Cc:Date:In-Reply-To:References; b=jA5ftzsS6Od3C6QtFZZn8NBjL0CZWkdy7SN81HrEcxwfWgfuFRcFpVdwcK9sPEs4G ievqqCQvxmHFaXhQWk1Ys+v89EUbu1nnzgUnVykrGFnNlz83JrMecvgmxJ3mWIBh48 vw9uF537K3gvTsPE3U12X3zoT6c+puoxuJAWy1dE= Message-ID: Subject: [PATCH 2/4] c23: tag compatibility rules for enums From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Thu, 16 Nov 2023 22:38:47 +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=-11.0 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 Allow redefinition of enum types and enumerators. Diagnose nested redefinitions including redefinitions in the enum specifier for enum types with fixed underlying type. gcc/c: * c-tree.h (c_parser_enum_specifier): Add parameter. * c-decl.cc (start_enum): Allow redefinition. (finish_enum): Diagnose conflicts. (build_enumerator): Set context. (diagnose_mismatched_decls): Diagnose conflicting enumerators. (push_decl): Preserve context for enumerators. * c-parser.cc (c_parser_enum_specifier): Remember when seen is from an enum type which is not yet defined. gcc/testsuide/: * gcc.dg/c23-tag-enum-1.c: New test. * gcc.dg/c23-tag-enum-2.c: New test. * gcc.dg/c23-tag-enum-3.c: New test. * gcc.dg/c23-tag-enum-4.c: New test. * gcc.dg/c23-tag-enum-5.c: New test. --- gcc/c/c-decl.cc | 65 +++++++++++++++++++++++---- gcc/c/c-parser.cc | 5 ++- gcc/c/c-tree.h | 3 +- gcc/c/c-typeck.cc | 5 ++- gcc/testsuite/gcc.dg/c23-tag-enum-1.c | 56 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/c23-tag-enum-2.c | 23 ++++++++++ gcc/testsuite/gcc.dg/c23-tag-enum-3.c | 7 +++ gcc/testsuite/gcc.dg/c23-tag-enum-4.c | 22 +++++++++ gcc/testsuite/gcc.dg/c23-tag-enum-5.c | 18 ++++++++ 9 files changed, 192 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-1.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-2.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-3.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-4.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-5.c diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 194dd595334..e5d48c3fa56 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -2114,9 +2114,24 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, given scope. */ if (TREE_CODE (olddecl) == CONST_DECL) { - auto_diagnostic_group d; - error ("redeclaration of enumerator %q+D", newdecl); - locate_old_decl (olddecl); + if (flag_isoc23 + && TYPE_NAME (DECL_CONTEXT (newdecl)) + && DECL_CONTEXT (newdecl) != DECL_CONTEXT (olddecl) + && TYPE_NAME (DECL_CONTEXT (newdecl)) == TYPE_NAME (DECL_CONTEXT (olddecl))) + { + if (!simple_cst_equal (DECL_INITIAL (olddecl), DECL_INITIAL (newdecl))) + { + auto_diagnostic_group d; + error ("conflicting redeclaration of enumerator %q+D", newdecl); + locate_old_decl (olddecl); + } + } + else + { + auto_diagnostic_group d; + error ("redeclaration of enumerator %q+D", newdecl); + locate_old_decl (olddecl); + } return false; } @@ -3277,8 +3292,11 @@ pushdecl (tree x) /* Must set DECL_CONTEXT for everything not at file scope or DECL_FILE_SCOPE_P won't work. Local externs don't count - unless they have initializers (which generate code). */ + unless they have initializers (which generate code). We + also exclude CONST_DECLs because enumerators will get the + type of the enum as context. */ if (current_function_decl + && TREE_CODE (x) != CONST_DECL && (!VAR_OR_FUNCTION_DECL_P (x) || DECL_INITIAL (x) || !TREE_PUBLIC (x))) DECL_CONTEXT (x) = current_function_decl; @@ -9737,7 +9755,7 @@ layout_array_type (tree t) tree start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, - tree fixed_underlying_type) + tree fixed_underlying_type, bool potential_nesting_p) { tree enumtype = NULL_TREE; location_t enumloc = UNKNOWN_LOCATION; @@ -9749,9 +9767,26 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, if (name != NULL_TREE) enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc); + if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE) + { + /* If the type is currently being defined or if we have seen an + incomplete version which is now complete, this is a nested + redefinition. The later happens if the redefinition occurs + inside the enum specifier itself. */ + if (C_TYPE_BEING_DEFINED (enumtype) + || (potential_nesting_p && TYPE_VALUES (enumtype) != NULL_TREE)) + error_at (loc, "nested redefinition of %", name); + + /* For C23 we allow redefinitions. We set to zero and check for + consistency later. */ + if (flag_isoc23 && TYPE_VALUES (enumtype) != NULL_TREE) + enumtype = NULL_TREE; + } + if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE) { enumtype = make_node (ENUMERAL_TYPE); + TYPE_SIZE (enumtype) = NULL_TREE; pushtag (loc, name, enumtype); if (fixed_underlying_type != NULL_TREE) { @@ -9779,9 +9814,6 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, DECL_SOURCE_LOCATION (TYPE_STUB_DECL (enumtype)) = loc; } - if (C_TYPE_BEING_DEFINED (enumtype)) - error_at (loc, "nested redefinition of %", name); - C_TYPE_BEING_DEFINED (enumtype) = 1; if (TYPE_VALUES (enumtype) != NULL_TREE) @@ -10011,6 +10043,20 @@ finish_enum (tree enumtype, tree values, tree attributes) && !in_sizeof && !in_typeof && !in_alignof) struct_parse_info->struct_types.safe_push (enumtype); + /* Check for consistency with previous definition */ + if (flag_isoc23) + { + tree vistype = previous_tag (enumtype); + if (vistype + && TREE_CODE (vistype) == TREE_CODE (enumtype) + && !C_TYPE_BEING_DEFINED (vistype)) + { + TYPE_STUB_DECL (vistype) = TYPE_STUB_DECL (enumtype); + if (!comptypes_same_p (enumtype, vistype)) + error("conflicting redefinition of enum %qT", enumtype); + } + } + C_TYPE_BEING_DEFINED (enumtype) = 0; return enumtype; @@ -10190,6 +10236,7 @@ build_enumerator (location_t decl_loc, location_t loc, decl = build_decl (decl_loc, CONST_DECL, name, TREE_TYPE (value)); DECL_INITIAL (decl) = value; + DECL_CONTEXT (decl) = the_enum->enum_type; pushdecl (decl); return tree_cons (decl, value, NULL_TREE); @@ -10206,7 +10253,7 @@ c_simulate_enum_decl (location_t loc, const char *name, struct c_enum_contents the_enum; tree enumtype = start_enum (loc, &the_enum, get_identifier (name), - NULL_TREE); + NULL_TREE, false); tree value_chain = NULL_TREE; string_int_pair *value; diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 703f9570dbc..ff30ba198ca 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -3667,6 +3667,7 @@ c_parser_enum_specifier (c_parser *parser) { struct c_typespec ret; bool have_std_attrs; + bool potential_nesting_p = false; tree std_attrs = NULL_TREE; tree attrs; tree ident = NULL_TREE; @@ -3706,6 +3707,7 @@ c_parser_enum_specifier (c_parser *parser) if (!ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec)) error_at (enum_loc, "% declared both with and without " "fixed underlying type"); + potential_nesting_p = NULL_TREE == TYPE_VALUES (ret.spec); } else { @@ -3776,7 +3778,8 @@ c_parser_enum_specifier (c_parser *parser) forward order at the end. */ tree values; timevar_push (TV_PARSE_ENUM); - type = start_enum (enum_loc, &the_enum, ident, fixed_underlying_type); + type = start_enum (enum_loc, &the_enum, ident, fixed_underlying_type, + potential_nesting_p); values = NULL_TREE; c_parser_consume_token (parser); while (true) diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 7df4d65bf7a..a5dd9a37944 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -682,7 +682,8 @@ extern void c_warn_unused_attributes (tree); extern tree c_warn_type_attributes (tree); extern void shadow_tag (const struct c_declspecs *); extern void shadow_tag_warned (const struct c_declspecs *, int); -extern tree start_enum (location_t, struct c_enum_contents *, tree, tree); +extern tree start_enum (location_t, struct c_enum_contents *, tree, tree, + bool potential_nesting_p); extern bool start_function (struct c_declspecs *, struct c_declarator *, tree); extern tree start_decl (struct c_declarator *, struct c_declspecs *, bool, tree, bool = true, location_t * = NULL); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index dc8a16df272..8116c9b3e68 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1419,6 +1419,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, { case ENUMERAL_TYPE: { + if (!comptypes (ENUM_UNDERLYING_TYPE (t1), ENUM_UNDERLYING_TYPE (t2))) + return false; + /* Speed up the case where the type values are in the same order. */ tree tv1 = TYPE_VALUES (t1); tree tv2 = TYPE_VALUES (t2); @@ -6948,7 +6951,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, if (checktype != error_mark_node && TREE_CODE (checktype) == ENUMERAL_TYPE && TREE_CODE (type) == ENUMERAL_TYPE - && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type)) + && !comptypes (TYPE_MAIN_VARIANT (checktype), TYPE_MAIN_VARIANT (type))) { gcc_rich_location loc (location); warning_at (&loc, OPT_Wenum_conversion, diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-1.c b/gcc/testsuite/gcc.dg/c23-tag-enum-1.c new file mode 100644 index 00000000000..0b4829cdbe3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-enum-1.c @@ -0,0 +1,56 @@ +/* + * { dg-do compile } + * { dg-options "-std=c23" } + */ + +// incompatible redeclarations, conflicing redefinitions + + +enum aa { A = 1 } *a; +enum bb { B = 1 } *b; + +void test(void) +{ + enum aa { A = 1 } *c = a; + enum bb { B = 2 } *d = b; /* { dg-warning "incompatible pointer type" } */ +} + +enum cc { C = 1 }; +enum cc { D = 1 }; /* { dg-error "conflicting redefinition" } */ + +enum dd { E = 1 }; +enum dd { E = 2 }; /* { dg-error "conflicting redefinition" } */ + /* { dg-error "redeclaration of enumerator" "" { target *-*-* } .-1 } */ + + + +void test2(void) +{ + enum ee *a; + enum ee { F = 2 } *b; + b = a; +} + + +enum ff { G = 2 }; +enum gg { G = 2 }; /* { dg-error "redeclaration of enumerator" } */ +enum g2 { G = 3 }; /* { dg-error "redeclaration of enumerator" } */ + +enum hh { H = 1, H = 1 }; /* { dg-error "redeclaration of enumerator" } */ + +enum ss { K = 2 }; +enum ss { K = 2 }; + +enum tt { R = 2 } TT; +enum tt { + R = _Generic(&TT, enum tt*: 0, default: 2) +}; + +enum { U = 1 }; +enum { U = 1 }; /* { dg-error "redeclaration of enumerator" } */ + +enum { V = 1 }; +enum { V = 2 }; /* { dg-error "redeclaration of enumerator" } */ + + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-2.c b/gcc/testsuite/gcc.dg/c23-tag-enum-2.c new file mode 100644 index 00000000000..1ced39974f4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-enum-2.c @@ -0,0 +1,23 @@ +/* + * { dg-do compile } + * { dg-options "-std=c23" } + */ + +// incomplete during construction + +enum A { B = 7 } y; +enum A { B = 7 }; + +enum A { B = _Generic(&y, enum A*: 1, default: 7) }; + +void g(void) +{ + enum A { B = _Generic(&y, enum A*: 1, default: 7) }; + _Static_assert(7 == B, ""); +} + +enum X { E = 1, F = 1 + 1 }; +enum X { F = 2, E = 1 }; + + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-3.c b/gcc/testsuite/gcc.dg/c23-tag-enum-3.c new file mode 100644 index 00000000000..12218a5b911 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-enum-3.c @@ -0,0 +1,7 @@ +/* { dg-do compile } + * { dg-options "-std=c23" } + */ + +enum A { N = 0 * sizeof(enum A { M = 1 }) }; /* { dg-error "nested" } */ + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-4.c b/gcc/testsuite/gcc.dg/c23-tag-enum-4.c new file mode 100644 index 00000000000..f20dc55fc6c --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-enum-4.c @@ -0,0 +1,22 @@ +/* { dg-do compile } + * { dg-options "-std=c23" } + */ + +// fixed underlying types + +enum A : int { N = 1 } x1 = { }; +enum B : int { M = 1 } x2 = { }; +enum C { U = 1 } x3 = { }; + +void f(void) +{ + enum A : int { N = 1 } y1 = x1; + enum B : short { M = 1 } y2; + y2 = x2; + enum B : short { M = 1 } y2b; + enum Bb : short { V = 1 } y2d = x2; + enum B : short { M = 1 } *y2e = &x2; /* { dg-warning "incompatible" } */ + enum B : short { M = 1 } y2c = x2; + enum C { U = 1 } y3 = x3; +} + diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-5.c b/gcc/testsuite/gcc.dg/c23-tag-enum-5.c new file mode 100644 index 00000000000..22ce06fb80d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-enum-5.c @@ -0,0 +1,18 @@ +/* { dg-do compile } + * { dg-options "-std=c23" } */ + +// test for nested redefinitions of enums + +void foo(void) +{ + enum e { A = 1 }; + enum e { A = 1 /* { dg-error "redeclaration" } */ + + 0 * sizeof(enum e { A = 1 }) }; /* { dg-error "nested redefinition" } */ + +} + +typedef __SIZE_TYPE__ size_t; +enum f : typeof (sizeof (enum f : size_t { B })) { B }; /* { dg-error "nested redefinition" } */ + + + From patchwork Thu Nov 16 21:39:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1864890 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=lw6TPVBD; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; 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 [8.43.85.97]) (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 4SWYN82RFyz1yRy for ; Fri, 17 Nov 2023 08:39:52 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BD3123858D28 for ; Thu, 16 Nov 2023 21:39:49 +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 4699F3858D28 for ; Thu, 16 Nov 2023 21:39:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4699F3858D28 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 4699F3858D28 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=1700170779; cv=none; b=LSwkIKpz9XyoQlUrs0p/e0nzbCwhD0jMFv5h7Yg9fWKYFJTh/0MdIAdrNRH1izQAcX/1tADL9l4WNf6fGnCiU3totRKbnKF1DE3sMSYrXFlW98y8C8TWlCAF8K8JB9fIko8ABKibnbk5OQ2dKIkW4i08g81caKmtN/QdJYrii5s= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700170779; c=relaxed/simple; bh=2yAd6LJeZwVwZOz9NllBtroyZVgle+vVHN0Zugfii+U=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=d1B5oPcxX7URKBduRvvZZgHVGAB8C6R+sBLL9CFl/kJn5CgeSxxJc7RnQ8y6BQN8k9ojxKfJTi0GIc6eNSoSilg81nZipcQz7Y2uGX00FV+T6IMqMdBL3psSV+mrFnXdnGTw2tnvwHIyEsCunT/a1dnpTtsxrLr7GCI6mRceWro= 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 4SWYMf6JWvz1LM0K; Thu, 16 Nov 2023 22:39:26 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 mailrelay.tugraz.at 4SWYMf6JWvz1LM0K DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1700170767; bh=r9cHizGsYq9cXW2Mtm0+skLtgE8aDXEzxbfHA2OEIjA=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=lw6TPVBDqhx/2jo1HF7rWWGLclZ0yhdXRlDikXaHgIaT4a0iCX5SZfwuHy9JaagU7 JBXR50QEP8Ap9Ye9vQHgnjT93IkUxI/exGusoZi1333LAG9BeNydwlMz73trlSIWxT C+7lmqgFMXTBTQFpsNQOWtT7Sprb5BinqXbE0dFQ= Message-ID: <223aa096afbdbb177d4ad5245696d439ad4cf87f.camel@tugraz.at> Subject: [PATCH 3/4] c23: aliasing of compatible tagged types From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Thu, 16 Nov 2023 22:39:26 +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=-11.1 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 Tell the backend which types are equivalent by setting TYPE_CANONICAL to one struct in the set of equivalent structs. Structs are considered equivalent by ignoring all sizes of arrays nested in types below field level. gcc/c: * c-decl.cc (c_struct_hasher): Hash stable for struct types. (c_struct_hasher::hash, c_struct_hasher::equal): New functions. (finish_struct): Set TYPE_CANONICAL to first struct in equivalence class. * c-objc-common.cc (c_get_alias_set): Let structs or unions with variable size alias anything. * c-tree.h (comptypes_equiv): New prototype. * c-typeck.cc (comptypes_equiv): New function. (comptypes_internal): Implement equivalence mode. (tagged_types_tu_compatible): Implement equivalence mode. gcc/testsuite: * gcc.dg/c23-tag-2.c: Activate. * gcc.dg/c23-tag-6.c: Activate. * gcc.dg/c23-tag-alias-1.c: New test. * gcc.dg/c23-tag-alias-2.c: New test. * gcc.dg/c23-tag-alias-3.c: New test. * gcc.dg/c23-tag-alias-4.c: New test. * gcc.dg/c23-tag-alias-5.c: New test. * gcc.dg/c23-tag-alias-6.c: New test. * gcc.dg/c23-tag-alias-7.c: New test. * gcc.dg/c23-tag-alias-8.c: New test. * gcc.dg/gnu23-tag-alias-1.c: New test. --- gcc/c/c-decl.cc | 48 +++++++++++++ gcc/c/c-objc-common.cc | 5 ++ gcc/c/c-tree.h | 1 + gcc/c/c-typeck.cc | 31 ++++++++ gcc/testsuite/gcc.dg/c23-tag-2.c | 4 +- gcc/testsuite/gcc.dg/c23-tag-5.c | 5 +- gcc/testsuite/gcc.dg/c23-tag-alias-1.c | 48 +++++++++++++ gcc/testsuite/gcc.dg/c23-tag-alias-2.c | 73 +++++++++++++++++++ gcc/testsuite/gcc.dg/c23-tag-alias-3.c | 48 +++++++++++++ gcc/testsuite/gcc.dg/c23-tag-alias-4.c | 73 +++++++++++++++++++ gcc/testsuite/gcc.dg/c23-tag-alias-5.c | 30 ++++++++ gcc/testsuite/gcc.dg/c23-tag-alias-6.c | 77 ++++++++++++++++++++ gcc/testsuite/gcc.dg/c23-tag-alias-7.c | 86 ++++++++++++++++++++++ gcc/testsuite/gcc.dg/c23-tag-alias-8.c | 90 ++++++++++++++++++++++++ gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c | 33 +++++++++ 15 files changed, 648 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-1.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-2.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-3.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-4.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-5.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-6.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-7.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-8.c create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index e5d48c3fa56..d0a405087c3 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -634,6 +634,36 @@ public: auto_vec typedefs_seen; }; + +/* Hash table for structs and unions. */ +struct c_struct_hasher : ggc_ptr_hash +{ + static hashval_t hash (tree t); + static bool equal (tree, tree); +}; + +/* Hash an RECORD OR UNION. */ +hashval_t +c_struct_hasher::hash (tree type) +{ + inchash::hash hstate; + + hstate.add_int (TREE_CODE (type)); + hstate.add_object (TYPE_NAME (type)); + + return hstate.end (); +} + +/* Compare two RECORD or UNION types. */ +bool +c_struct_hasher::equal (tree t1, tree t2) +{ + return comptypes_equiv_p (t1, t2); +} + +/* All tagged typed so that TYPE_CANONICAL can be set correctly. */ +static GTY (()) hash_table *c_struct_htab; + /* Information for the struct or union currently being parsed, or NULL if not parsing a struct or union. */ static class c_struct_parse_info *struct_parse_info; @@ -9646,6 +9676,24 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, C_TYPE_BEING_DEFINED (t) = 0; + /* Set type canonical based on equivalence class. */ + if (flag_isoc23) + { + if (NULL == c_struct_htab) + c_struct_htab = hash_table::create_ggc (61); + + hashval_t hash = c_struct_hasher::hash (t); + + tree *e = c_struct_htab->find_slot_with_hash (t, hash, INSERT); + if (*e) + TYPE_CANONICAL (t) = *e; + else + { + TYPE_CANONICAL (t) = t; + *e = t; + } + } + 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-objc-common.cc b/gcc/c/c-objc-common.cc index c8f49aa2370..738afbad770 100644 --- a/gcc/c/c-objc-common.cc +++ b/gcc/c/c-objc-common.cc @@ -389,6 +389,11 @@ c_get_alias_set (tree t) if (TREE_CODE (t) == ENUMERAL_TYPE) return get_alias_set (ENUM_UNDERLYING_TYPE (t)); + /* Structs with variable size can alias different incompatible + structs. Let them alias anything. */ + if (RECORD_OR_UNION_TYPE_P (t) && C_TYPE_VARIABLE_SIZE (t)) + return 0; + return c_common_get_alias_set (t); } diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index a5dd9a37944..ece5b6a5d26 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -758,6 +758,7 @@ 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_equiv_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 8116c9b3e68..262b04c582f 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1063,6 +1063,7 @@ struct comptypes_data { bool different_types_p; bool warning_needed; bool anon_field; + bool equiv; const struct tagged_tu_seen_cache* cache; }; @@ -1123,6 +1124,21 @@ comptypes_check_different_types (tree type1, tree type2, return ret ? (data.warning_needed ? 2 : 1) : 0; } + + +/* Like comptypes, but if it returns nonzero for struct and union + types considered equivalent for aliasing purposes. */ + +int +comptypes_equiv_p (tree type1, tree type2) +{ + struct comptypes_data data = { }; + data.equiv = true; + bool ret = comptypes_internal (type1, type2, &data); + + return ret; +} + /* Return true if TYPE1 and TYPE2 are compatible types for assignment or various other operations. If they are compatible but a warning may @@ -1250,6 +1266,9 @@ comptypes_internal (const_tree type1, const_tree type2, if ((d1 == NULL_TREE) != (d2 == NULL_TREE)) data->different_types_p = true; + /* ignore size mismatches */ + if (data->equiv) + return 1; /* Sizes must match unless one is missing or variable. */ if (d1 == NULL_TREE || d2 == NULL_TREE || d1 == d2) return true; @@ -1467,6 +1486,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2))) return false; + if (data->equiv && (C_TYPE_VARIABLE_SIZE (t1) || C_TYPE_VARIABLE_SIZE (t2))) + return 0; + for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); s1 && s2; s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2)) @@ -1486,6 +1508,15 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), DECL_FIELD_BIT_OFFSET (s2)) != 1) return false; + + tree st1 = TYPE_SIZE (TREE_TYPE (s1)); + tree st2 = TYPE_SIZE (TREE_TYPE (s2)); + + if (data->equiv + && st1 && TREE_CODE (st1) == INTEGER_CST + && st2 && TREE_CODE (st2) == INTEGER_CST + && !tree_int_cst_equal (st1, st2)) + return 0; } return true; diff --git a/gcc/testsuite/gcc.dg/c23-tag-2.c b/gcc/testsuite/gcc.dg/c23-tag-2.c index 5dd4a21e9df..e28c2b5eea2 100644 --- a/gcc/testsuite/gcc.dg/c23-tag-2.c +++ b/gcc/testsuite/gcc.dg/c23-tag-2.c @@ -1,5 +1,5 @@ -/* { dg-do compile { target { ! "*-*-*" } } } - * { dg-options "-std=c23" } +/* { dg-do compile } + * { dg-options "-std=c2x" } */ // compatibility of structs in assignment diff --git a/gcc/testsuite/gcc.dg/c23-tag-5.c b/gcc/testsuite/gcc.dg/c23-tag-5.c index ff40d07aef1..95a04bf9b0e 100644 --- a/gcc/testsuite/gcc.dg/c23-tag-5.c +++ b/gcc/testsuite/gcc.dg/c23-tag-5.c @@ -1,5 +1,6 @@ -/* { dg-do run { target { ! "*-*-*" } } } - * { dg-options "-std=c23" } +/* + * { dg-do run } + * { dg-options "-std=c2x" } */ // nesting and parameters diff --git a/gcc/testsuite/gcc.dg/c23-tag-alias-1.c b/gcc/testsuite/gcc.dg/c23-tag-alias-1.c new file mode 100644 index 00000000000..6704ba9c8b4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-1.c @@ -0,0 +1,48 @@ +/* + * { dg-do run } + * { dg-options "-std=c23 -O2" } + */ + + +struct foo { int x; }; + +int test_foo(struct foo* a, void* b) +{ + a->x = 1; + + struct foo { int x; }* p = b; + p->x = 2; + + return a->x; +} + + +enum bar { A = 1, B = 3 }; + +int test_bar(enum bar* a, void* b) +{ + *a = A; + + enum bar { A = 1, B = 3 }* p = b; + *p = B; + + return *a; +} + + +int main() +{ + struct foo y; + + if (2 != test_foo(&y, &y)) + __builtin_abort(); + + enum bar z; + + if (A == test_bar(&z, &z)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-alias-2.c b/gcc/testsuite/gcc.dg/c23-tag-alias-2.c new file mode 100644 index 00000000000..555c30a8501 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-2.c @@ -0,0 +1,73 @@ +/* + * { dg-do run } + * { dg-options "-std=c23 -O2" } + */ + + +struct foo { int x; }; + +int test_foo1(struct foo* a, void* b) +{ + a->x = 1; + + struct foo { int x; int y; }* p = b; + p->x = 2; + + return a->x; +} + +int test_foo2(struct foo* a, void* b) +{ + a->x = 1; + + struct fox { int x; }* p = b; + p->x = 2; + + return a->x; +} + +enum bar { A = 1, B = 3, C = 5, D = 9 }; + +int test_bar1(enum bar* a, void* b) +{ + *a = A; + + enum bar { A = 1, B = 3, C = 6, D = 9 }* p = b; + *p = B; + + return *a; +} + +int test_bar2(enum bar* a, void* b) +{ + *a = A; + + enum baX { A = 1, B = 3, C = 5, D = 9 }* p = b; + *p = B; + + return *a; +} + + +int main() +{ + struct foo y; + + if (1 != test_foo1(&y, &y)) + __builtin_abort(); + + if (1 != test_foo2(&y, &y)) + __builtin_abort(); + + enum bar z; + + if (A == test_bar1(&z, &z)) + __builtin_abort(); + + if (A == test_bar2(&z, &z)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-alias-3.c b/gcc/testsuite/gcc.dg/c23-tag-alias-3.c new file mode 100644 index 00000000000..122e8806af8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-3.c @@ -0,0 +1,48 @@ +/* + * { dg-do run } + * { dg-options "-std=c23 -flto -O2" } + */ + + +struct foo { int x; }; + +int test_foo(struct foo* a, void* b) +{ + a->x = 1; + + struct foo { int x; }* p = b; + p->x = 2; + + return a->x; +} + + +enum bar { A = 1, B = 3 }; + +int test_bar(enum bar* a, void* b) +{ + *a = A; + + enum bar { A = 1, B = 3 }* p = b; + *p = B; + + return *a; +} + + +int main() +{ + struct foo y; + + if (2 != test_foo(&y, &y)) + __builtin_abort(); + + enum bar z; + + if (A == test_bar(&z, &z)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-alias-4.c b/gcc/testsuite/gcc.dg/c23-tag-alias-4.c new file mode 100644 index 00000000000..d86a174f4a2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-4.c @@ -0,0 +1,73 @@ +/* + * { dg-do run } + * { dg-options "-std=c23 -flto -O2" } + */ + + +struct foo { int x; }; + +int test_foo1(struct foo* a, void* b) +{ + a->x = 1; + + struct foo { int x; int y; }* p = b; + p->x = 2; + + return a->x; +} + +int test_foo2(struct foo* a, void* b) +{ + a->x = 1; + + struct fox { int x; }* p = b; + p->x = 2; + + return a->x; +} + +enum bar { A = 1, B = 3, C = 5, D = 9 }; + +int test_bar1(enum bar* a, void* b) +{ + *a = A; + + enum bar { A = 1, B = 3, C = 6, D = 9 }* p = b; + *p = B; + + return *a; +} + +int test_bar2(enum bar* a, void* b) +{ + *a = A; + + enum baX { A = 1, B = 3, C = 5, D = 9 }* p = b; + *p = B; + + return *a; +} + + +int main() +{ + struct foo y; + + if (1 != test_foo1(&y, &y)) + __builtin_abort(); + + if (1 != test_foo2(&y, &y)) + __builtin_abort(); + + enum bar z; + + if (A == test_bar1(&z, &z)) + __builtin_abort(); + + if (A == test_bar2(&z, &z)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-alias-5.c b/gcc/testsuite/gcc.dg/c23-tag-alias-5.c new file mode 100644 index 00000000000..4e956720143 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-5.c @@ -0,0 +1,30 @@ +/* { dg-do run } + * { dg-options "-std=c23 -O2" } + */ + +// not sure this is wise, but this was already like thi sbefore + +typedef struct { int x; } foo_t; + +int test_foo(foo_t* a, void* b) +{ + a->x = 1; + + struct { int x; }* p = b; + p->x = 2; + + return a->x; +} + + +int main() +{ + foo_t y; + + if (1 != test_foo(&y, &y)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-alias-6.c b/gcc/testsuite/gcc.dg/c23-tag-alias-6.c new file mode 100644 index 00000000000..3f3e5f01473 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-6.c @@ -0,0 +1,77 @@ +/* + * { dg-do run } + * { dg-options "-std=c23 -O2" } + */ + + +/* We check that we tolerate differences for + * optimization. + */ + + +struct bar0 { int x; int f[3]; int y; }; + +int test_bar0(struct bar0* a, void* b) +{ + a->x = 1; + + struct bar0 { int x; int f[4]; int y; }* p = b; + p->x = 2; + + return a->x; +} + + + +struct bar1 { int x; int (*f)[3]; }; + +int test_bar1(struct bar1* a, void* b) +{ + a->x = 1; + + struct bar1 { int x; int (*f)[3]; }* p = b; + p->x = 2; + + return a->x; +} + + +struct bar2 { int x; int (*f)[3]; }; + +int test_bar2(struct bar2* a, void* b) +{ + a->x = 1; + + struct bar2 { int x; int (*f)[4]; }* p = b; + p->x = 2; + + return a->x; +} + + + +int main() +{ + // control + + struct bar0 z0; + + if (1 != test_bar0(&z0, &z0)) + __builtin_abort(); + + // this could be different + struct bar1 z1; + + if (2 != test_bar1(&z1, &z1)) + __builtin_abort(); + + struct bar2 z2; + + if (2 != test_bar2(&z2, &z2)) + __builtin_abort(); + + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-alias-7.c b/gcc/testsuite/gcc.dg/c23-tag-alias-7.c new file mode 100644 index 00000000000..74cf5f212b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-7.c @@ -0,0 +1,86 @@ +/* + * { dg-do run } + * { dg-options "-std=c23 -O2" } + */ + + + +struct bar { int x; int f[]; }; + +int test_bar1(struct bar* a, void* b) +{ + a->x = 1; + + struct bar { int x; int f[]; }* p = b; + struct bar* q = a; + p->x = 2; + + return a->x; +} + + +int test_bar3(struct bar* a, void* b) +{ + a->x = 1; + + struct bar { int x; int f[1]; }* p = b; + struct bar* q = a; /* { dg-warning "incompatible" } */ + p->x = 2; + + return a->x; +} + + +int test_bar4(struct bar* a, void* b) +{ + a->x = 1; + + int n = 3; + struct bar { int x; int f[n]; }* p = b; + struct bar* q = a; + p->x = 2; + + return a->x; +} + + +struct foo { int x; int f[3]; }; + + +int test_foo1(struct foo* a, void* b) +{ + a->x = 1; + + int n = 3; + struct foo { int x; int f[n]; }* p = b; + struct foo* q = a; + p->x = 2; + + return a->x; +} + + + +int main() +{ + struct bar z; + + if (2 != test_bar1(&z, &z)) + __builtin_abort(); + +#if 0 + if (1 != test_bar3(&z, &z)) + __builtin_abort(); +#endif + if (2 != test_bar4(&z, &z)) + __builtin_abort(); + + struct foo y; + + if (2 != test_foo1(&y, &y)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-alias-8.c b/gcc/testsuite/gcc.dg/c23-tag-alias-8.c new file mode 100644 index 00000000000..7c2ced4de51 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-8.c @@ -0,0 +1,90 @@ +/* + * { dg-do run } + * { dg-options "-std=c23 -O2" } + */ + + +/* We check that we tolerate differences for + * optimization. + */ + +struct bar1 { int x; enum A1 { X1 = 1 } f; }; + +int test_bar1(struct bar1* a, void* b) +{ + a->x = 1; + + struct bar1 { int x; enum A1 { X1 = 2 } f; }* p = b; + p->x = 2; + + return a->x; +} + + +struct bar2 { int x; enum A2 { X2 = 1 } f; }; + +int test_bar2(struct bar2* a, void* b) +{ + a->x = 1; + + struct bar2 { int x; enum B2 { X2 = 1 } f; }* p = b; + p->x = 2; + + return a->x; +} + + + +struct bar3 { int x; enum A3 { X3 = 1 } f; }; + +int test_bar3(struct bar3* a, void* b) +{ + a->x = 1; + + struct bar3 { int x; enum A3 { Y3 = 1 } f; }* p = b; + p->x = 2; + + return a->x; +} + + +struct bar4 { int x; enum { Z4 = 1 } f; }; + +int test_bar4(struct bar4* a, void* b) +{ + a->x = 1; + + struct bar4 { int x; enum { Z4 = 1 } f; }* p = b; + p->x = 2; + + return a->x; +} + + + +int main() +{ + struct bar1 z1; + + if (1 != test_bar1(&z1, &z1)) + __builtin_abort(); + + struct bar2 z2; + + if (1 != test_bar2(&z2, &z2)) + __builtin_abort(); + + struct bar3 z3; + + if (1 != test_bar3(&z3, &z3)) + __builtin_abort(); + + struct bar4 z4; + + if (1 != test_bar4(&z4, &z4)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c b/gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c new file mode 100644 index 00000000000..9bccc651afb --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c @@ -0,0 +1,33 @@ +/* + * { dg-do run } + * { dg-options "-std=gnu23 -O2" } + */ + + + +struct bar { int x; int f[]; }; + +int test_bar2(struct bar* a, void* b) +{ + a->x = 1; + + struct bar { int x; int f[0]; }* p = b; + struct bar* q = a; + p->x = 2; + + return a->x; +} + + + +int main() +{ + struct bar z; + + if (2 != test_bar2(&z, &z)) + __builtin_abort(); + + return 0; +} + + From patchwork Thu Nov 16 21:40:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1864892 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=mkchSF7K; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; 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 [8.43.85.97]) (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 4SWYNw5Xttz1yRW for ; Fri, 17 Nov 2023 08:40:32 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1402B3858013 for ; Thu, 16 Nov 2023 21:40:30 +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 0CAC43858C54 for ; Thu, 16 Nov 2023 21:40:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0CAC43858C54 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 0CAC43858C54 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=1700170820; cv=none; b=Rv+B5gvRSNvDvrJqX+caCgN/mzJIBmHW7zUki7TTg+7f2oUP++woyawxyj/z5yLQ+TZSJVrZvGedvQcQuozu6TZNMyI8dLjfZZL/WmUoDCGBO6Zwx85gol/E7F3kNfIvmcWFPwxYTYEVyFB8cda8shReG5Bj6P3MyG9n1SGNuGo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700170820; c=relaxed/simple; bh=VhzQo7Sxc0KPLDgcFNwcHtQx6mpK9LTe0v34UhXPpk4=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=bFAOLS3mApuZ7COIPegoCMcEbSa+FJTKVL/e/QRzYUBfWgErrjP2I3zUn4k30xL8mhYsYDXP/tFIONClzHNSZri5UwMjayRHPvjrJ1K2R1wDwC1BkSNipvu8KrP/4BaxnDbspufGv4iyVmd79Q9QQYzq8O9tj7iq3oDsX2GgUSs= 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 4SWYNT5NNCz3wnp; Thu, 16 Nov 2023 22:40:09 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1700170809; bh=eoQGfuEmXr++XxuPRhJ2alOPQ6aMsd3Dq+8II0paSY0=; h=Subject:From:To:Cc:Date:In-Reply-To:References; b=mkchSF7KRYVp3OXwKR2xR3ENgGJUyNDz4XkgMDlMKj18aHetGfeC0OjeZd6pyTMGI joeTJttzFJ3haxenu3G9rWYw7AnAcMkCDYxiwnFWhyhgL7vWcTxljOg6Y74IuxLBLo Lb0imnUhDcI3VLS2XCL1VWQwCkv8x6xhgDmgiBTw= Message-ID: Subject: [PATCH 4/4] c23: construct composite type for tagged types From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Thu, 16 Nov 2023 22:40:09 +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=-11.2 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 Support for constructing composite type for structs and unions in C23. gcc/c: * c-typeck.cc (composite_type_internal): Adapted from composite_type to support structs and unions. (composite_type): New wrapper function. (build_conditional_operator): Return composite type. gcc/testsuite: * gcc.dg/c23-tag-composite-1.c: New test. * gcc.dg/c23-tag-composite-2.c: New test. * gcc.dg/c23-tag-composite-3.c: New test. * gcc.dg/c23-tag-composite-4.c: New test. --- gcc/c/c-typeck.cc | 114 +++++++++++++++++---- gcc/testsuite/gcc.dg/c23-tag-composite-1.c | 26 +++++ gcc/testsuite/gcc.dg/c23-tag-composite-2.c | 16 +++ gcc/testsuite/gcc.dg/c23-tag-composite-3.c | 17 +++ gcc/testsuite/gcc.dg/c23-tag-composite-4.c | 21 ++++ 5 files changed, 176 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-1.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-2.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-3.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-4.c diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 262b04c582f..2255fb66bb2 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -381,8 +381,15 @@ build_functype_attribute_variant (tree ntype, tree otype, tree attrs) nonzero; if that isn't so, this may crash. In particular, we assume that qualifiers match. */ +struct composite_cache { + tree t1; + tree t2; + tree composite; + struct composite_cache* next; +}; + tree -composite_type (tree t1, tree t2) +composite_type_internal (tree t1, tree t2, struct composite_cache* cache) { enum tree_code code1; enum tree_code code2; @@ -427,7 +434,8 @@ composite_type (tree t1, tree t2) { tree pointed_to_1 = TREE_TYPE (t1); tree pointed_to_2 = TREE_TYPE (t2); - tree target = composite_type (pointed_to_1, pointed_to_2); + tree target = composite_type_internal (pointed_to_1, + pointed_to_2, cache); t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false); t1 = build_type_attribute_variant (t1, attributes); return qualify_type (t1, t2); @@ -435,7 +443,8 @@ composite_type (tree t1, tree t2) case ARRAY_TYPE: { - tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2)); + tree elt = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2), + cache); int quals; tree unqual_elt; tree d1 = TYPE_DOMAIN (t1); @@ -503,9 +512,61 @@ composite_type (tree t1, tree t2) return build_type_attribute_variant (t1, attributes); } - case ENUMERAL_TYPE: case RECORD_TYPE: case UNION_TYPE: + if (flag_isoc23 && !comptypes_same_p (t1, t2)) + { + gcc_checking_assert (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2)); + gcc_checking_assert (comptypes (t1, t2)); + + /* If a composite type for these two types is already under + construction, return it. */ + + for (struct composite_cache *c = cache; c != NULL; c = c->next) + if (c->t1 == t1 && c->t2 == t2) + return c->composite; + + /* Otherwise, create a new type node and link it into the cache. */ + + tree n = make_node (code1); + struct composite_cache cache2 = { t1, t2, n, cache }; + cache = &cache2; + + tree f1 = TYPE_FIELDS (t1); + tree f2 = TYPE_FIELDS (t2); + tree fields = NULL_TREE; + + for (tree a = f1, b = f2; a && b; + a = DECL_CHAIN (a), b = DECL_CHAIN (b)) + { + tree ta = TREE_TYPE (a); + tree tb = TREE_TYPE (b); + + gcc_assert (DECL_NAME (a) == DECL_NAME (b)); + gcc_assert (comptypes (ta, tb)); + + tree f = build_decl (input_location, FIELD_DECL, DECL_NAME (a), + composite_type_internal (ta, tb, cache)); + + DECL_FIELD_CONTEXT (f) = n; + DECL_CHAIN (f) = fields; + fields = f; + } + + TYPE_NAME (n) = TYPE_NAME (t1); + TYPE_FIELDS (n) = nreverse (fields); + TYPE_ATTRIBUTES (n) = attributes; + layout_type (n); + n = build_type_attribute_variant (n, attributes); + n = qualify_type (n, t1); + + gcc_checking_assert (comptypes (n, t1)); + gcc_checking_assert (comptypes (n, t2)); + + return n; + } + /* FALLTHRU */ + case ENUMERAL_TYPE: if (attributes != NULL) { /* Try harder not to create a new aggregate type. */ @@ -520,7 +581,8 @@ composite_type (tree t1, tree t2) /* Function types: prefer the one that specified arg types. If both do, merge the arg types. Also merge the return types. */ { - tree valtype = composite_type (TREE_TYPE (t1), TREE_TYPE (t2)); + tree valtype = composite_type_internal (TREE_TYPE (t1), + TREE_TYPE (t2), cache); tree p1 = TYPE_ARG_TYPES (t1); tree p2 = TYPE_ARG_TYPES (t2); int len; @@ -565,6 +627,16 @@ composite_type (tree t1, tree t2) for (; p1 && p1 != void_list_node; p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n)) { + tree mv1 = TREE_VALUE (p1); + if (mv1 && mv1 != error_mark_node + && TREE_CODE (mv1) != ARRAY_TYPE) + mv1 = TYPE_MAIN_VARIANT (mv1); + + tree mv2 = TREE_VALUE (p2); + if (mv2 && mv2 != error_mark_node + && TREE_CODE (mv2) != ARRAY_TYPE) + mv2 = TYPE_MAIN_VARIANT (mv2); + /* A null type means arg type is not specified. Take whatever the other function type has. */ if (TREE_VALUE (p1) == NULL_TREE) @@ -585,10 +657,6 @@ composite_type (tree t1, tree t2) && TREE_VALUE (p1) != TREE_VALUE (p2)) { tree memb; - tree mv2 = TREE_VALUE (p2); - if (mv2 && mv2 != error_mark_node - && TREE_CODE (mv2) != ARRAY_TYPE) - mv2 = TYPE_MAIN_VARIANT (mv2); for (memb = TYPE_FIELDS (TREE_VALUE (p1)); memb; memb = DECL_CHAIN (memb)) { @@ -598,8 +666,9 @@ composite_type (tree t1, tree t2) mv3 = TYPE_MAIN_VARIANT (mv3); if (comptypes (mv3, mv2)) { - TREE_VALUE (n) = composite_type (TREE_TYPE (memb), - TREE_VALUE (p2)); + TREE_VALUE (n) = composite_type_internal (TREE_TYPE (memb), + TREE_VALUE (p2), + cache); pedwarn (input_location, OPT_Wpedantic, "function types not truly compatible in ISO C"); goto parm_done; @@ -610,10 +679,6 @@ composite_type (tree t1, tree t2) && TREE_VALUE (p2) != TREE_VALUE (p1)) { tree memb; - tree mv1 = TREE_VALUE (p1); - if (mv1 && mv1 != error_mark_node - && TREE_CODE (mv1) != ARRAY_TYPE) - mv1 = TYPE_MAIN_VARIANT (mv1); for (memb = TYPE_FIELDS (TREE_VALUE (p2)); memb; memb = DECL_CHAIN (memb)) { @@ -623,15 +688,17 @@ composite_type (tree t1, tree t2) mv3 = TYPE_MAIN_VARIANT (mv3); if (comptypes (mv3, mv1)) { - TREE_VALUE (n) = composite_type (TREE_TYPE (memb), - TREE_VALUE (p1)); + TREE_VALUE (n) + = composite_type_internal (TREE_TYPE (memb), + TREE_VALUE (p1), + cache); pedwarn (input_location, OPT_Wpedantic, "function types not truly compatible in ISO C"); goto parm_done; } } } - TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2)); + TREE_VALUE (n) = composite_type_internal (mv1, mv2, cache); parm_done: ; } @@ -643,7 +710,13 @@ composite_type (tree t1, tree t2) default: return build_type_attribute_variant (t1, attributes); } +} +tree +composite_type (tree t1, tree t2) +{ + struct composite_cache cache = { }; + return composite_type_internal (t1, t2, &cache); } /* Return the type of a conditional expression between pointers to @@ -5528,6 +5601,11 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, result_type = type2; else if (code1 == POINTER_TYPE && code2 == NULLPTR_TYPE) result_type = type1; + else if (RECORD_OR_UNION_TYPE_P (type1) && RECORD_OR_UNION_TYPE_P (type2) + && comptypes (TYPE_MAIN_VARIANT (type1), + TYPE_MAIN_VARIANT (type2))) + result_type = composite_type (TYPE_MAIN_VARIANT (type1), + TYPE_MAIN_VARIANT (type2)); if (!result_type) { diff --git a/gcc/testsuite/gcc.dg/c23-tag-composite-1.c b/gcc/testsuite/gcc.dg/c23-tag-composite-1.c new file mode 100644 index 00000000000..d79c8eefc91 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-composite-1.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c23" } */ + +void b(void) +{ + int n = 3; + + extern struct f { char (*x)[3]; char (*y)[]; } q; + { extern struct f { char (*x)[]; char (*y)[4]; } q; + _Static_assert(3 == sizeof(*q.x), ""); + _Static_assert(4 == sizeof(*q.y), ""); + } + { extern struct f { char (*x)[2]; char (*y)[]; } q; (void)q; } /* { dg-error "conflicting" } */ + + { struct f { char (*x)[n]; char (*y)[3]; }* qp = &q; (void)*qp; } + (void)q; + + static struct g { int a; char buf[n]; } *p; (void)p; + { static struct g { int a; char buf[3]; } *p; (void)p; } + + static struct h { int a; void (*s)(char buf[n]); } *t; (void)t; + { static struct h { int a; void (*s)(char buf[3]); } *t; (void)t; } +} + + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-composite-2.c b/gcc/testsuite/gcc.dg/c23-tag-composite-2.c new file mode 100644 index 00000000000..0b06c573e87 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-composite-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c23" } */ + + +struct foo { int (*(*i)(void))[]; } x; + + +void f(void) +{ + const struct foo { int (*(*i)())[3]; } y; + _Static_assert(3 * sizeof(int) == sizeof(*((1 ? &x : &y)->i())), ""); +} + +void g(struct foo { int x; } a); +void g(const struct foo { int x; } a); + diff --git a/gcc/testsuite/gcc.dg/c23-tag-composite-3.c b/gcc/testsuite/gcc.dg/c23-tag-composite-3.c new file mode 100644 index 00000000000..bc689478d8d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-composite-3.c @@ -0,0 +1,17 @@ +/* { dg-do compile } + * { dg-options "-std=c23" } + */ + +// bit-fields + +extern struct foo { int x:3; } x; +struct foo { int x:3; } y; + +void f(void) +{ + extern typeof(*(1 ? &x : &y)) x; + &x.x; /* { dg-error "bit-field" } */ +} + +struct foo { int x:2; }; /* { dg-error "redefinition" } */ + diff --git a/gcc/testsuite/gcc.dg/c23-tag-composite-4.c b/gcc/testsuite/gcc.dg/c23-tag-composite-4.c new file mode 100644 index 00000000000..2cc4b067c05 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-composite-4.c @@ -0,0 +1,21 @@ +/* { dg-do compile } + * { dg-options "-std=c23" } + */ + +// conditional operator + +void f(void) +{ + struct foo { int x; } a; + struct foo { int x; } b; + 1 ? a : b; +} + +struct bar { int x; } a; + +void g(void) +{ + struct bar { int x; } b; + 1 ? a : b; +} +