From patchwork Sun Dec 17 17:42:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 82339 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 76F1038582BA for ; Sun, 17 Dec 2023 17:43:04 +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 48CDD385843A for ; Sun, 17 Dec 2023 17:42:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 48CDD385843A 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 48CDD385843A 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=1702834968; cv=none; b=nTm5ubc9mQmwbUntWl+0wbU9+G1/5YJuwCATuwDRPAHouy6F41r7tgTzMWUrNsQEsShq5Il/Fm1pgEG2qA4jhTlVeZBtFq0QJ0mddRA+zEDXbjrEN/xT01FrfSeSepPFJaugJ327dMal+SGCagLFThL/TnrlAJw/dFX+2Au5TV0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1702834968; c=relaxed/simple; bh=1tpA6DycsSIAQH445a5k33YpAw3yJ24FL6LmDjhwTaQ=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=aJWE0UMecC+4KfmUCSrJaTECfkFwYWbSOMAFSvSXbmX2gL22ckT2E4zAF7+wq13TKkzlAQuq2A72NQPnnwj3veCTWwnmtcK88lZtJtr/QGY8JkQFn0YG8iPTWjAvk1/yP7QWW9TPJeFn1J/GhwHIQJ1eM3kuFY7EwKIPDEG2mZI= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from vra-173-234.tugraz.at (vra-173-234.tugraz.at [129.27.173.234]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4StVfB04yZz1LM03; Sun, 17 Dec 2023 18:42:41 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 mailrelay.tugraz.at 4StVfB04yZz1LM03 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1702834962; bh=WE5/o6hog7FRniwZvOUkgLp66FrQr7YGveNmHJsG6t8=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=eL+QphzwfwvTjAAoRwao4W0/PHj0uvNZLbSAqirK1feJriivBkzFPjdenTK+DLVz1 hlkWlXec+7+GUK8MHnYH5anE+NnD09IiAg30q3Y/yVYf3YujFRodz4c0wZG+uCnQyu GipcjMGlplGl22zeMO81iZv9ggXdegTYzIWZIpZE= Message-ID: <65c6d12e3a15500931f1aa2de73320cf6d374ccd.camel@tugraz.at> Subject: [V5] [C PATCH 4/4] c23: construct composite type for tagged types From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sun, 17 Dec 2023 18:42:41 +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.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+patchwork=sourceware.org@gcc.gnu.org Support for constructing composite types 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. * c-decl.cc (finish_struct): Allow NULL for enclosing_struct_parse_info. gcc/testsuite: * gcc.dg/c23-tag-alias-6.c: New test. * 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.dg/c23-tag-composite-5.c: New test. * gcc.dg/c23-tag-composite-6.c: New test. * gcc.dg/c23-tag-composite-7.c: New test. * gcc.dg/c23-tag-composite-8.c: New test. * gcc.dg/c23-tag-composite-9.c: New test. * gcc.dg/gnu23-tag-composite-1.c: New test. * gcc.dg/gnu23-tag-composite-2.c: New test. * gcc.dg/gnu23-tag-composite-3.c: New test. * gcc.dg/gnu23-tag-composite-4.c: New test. --- gcc/c/c-decl.cc | 21 +-- gcc/c/c-typeck.cc | 137 ++++++++++++++++--- gcc/testsuite/gcc.dg/c23-tag-alias-6.c | 32 +++++ 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 | 50 +++++++ gcc/testsuite/gcc.dg/c23-tag-composite-4.c | 21 +++ gcc/testsuite/gcc.dg/c23-tag-composite-5.c | 25 ++++ gcc/testsuite/gcc.dg/c23-tag-composite-6.c | 18 +++ gcc/testsuite/gcc.dg/c23-tag-composite-7.c | 20 +++ gcc/testsuite/gcc.dg/c23-tag-composite-8.c | 15 ++ gcc/testsuite/gcc.dg/c23-tag-composite-9.c | 19 +++ gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c | 45 ++++++ gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c | 30 ++++ gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c | 24 ++++ gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c | 28 ++++ 16 files changed, 500 insertions(+), 27 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-6.c 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 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-5.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-6.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-7.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-8.c create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-9.c create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 6639ec35e5f..b72738ea04a 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9674,7 +9674,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, } /* Check for consistency with previous definition. */ - if (flag_isoc23) + if (flag_isoc23 && NULL != enclosing_struct_parse_info) { tree vistype = previous_tag (t); if (vistype @@ -9744,16 +9744,19 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, if (warn_cxx_compat) warn_cxx_compat_finish_struct (fieldlist, TREE_CODE (t), loc); - delete struct_parse_info; + if (NULL != enclosing_struct_parse_info) + { + delete struct_parse_info; - struct_parse_info = enclosing_struct_parse_info; + struct_parse_info = enclosing_struct_parse_info; - /* If this struct is defined inside a struct, add it to - struct_types. */ - if (warn_cxx_compat - && struct_parse_info != NULL - && !in_sizeof && !in_typeof && !in_alignof) - struct_parse_info->struct_types.safe_push (t); + /* If this struct is defined inside a struct, add it to + struct_types. */ + if (warn_cxx_compat + && struct_parse_info != NULL + && !in_sizeof && !in_typeof && !in_alignof) + struct_parse_info->struct_types.safe_push (t); + } return t; } diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 4d3079156ba..ac31eba6e46 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,84 @@ 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 (!TYPE_NAME (t1) || 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); + TYPE_NAME (n) = TYPE_NAME (t1); + + 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); + + if (DECL_C_BIT_FIELD (a)) + { + ta = DECL_BIT_FIELD_TYPE (a); + tb = DECL_BIT_FIELD_TYPE (b); + } + + gcc_assert (DECL_NAME (a) == DECL_NAME (b)); + gcc_checking_assert (!DECL_NAME (a) || comptypes (ta, tb)); + + tree f = build_decl (input_location, FIELD_DECL, DECL_NAME (a), + composite_type_internal (ta, tb, cache)); + + DECL_PACKED (f) = DECL_PACKED (a); + SET_DECL_ALIGN (f, DECL_ALIGN (a)); + DECL_ATTRIBUTES (f) = DECL_ATTRIBUTES (a); + + finish_decl (f, input_location, NULL, NULL, NULL); + + if (DECL_C_BIT_FIELD (a)) + { + /* This will be processed by finish_struct. */ + SET_DECL_C_BIT_FIELD (f); + DECL_INITIAL (f) = build_int_cst (integer_type_node, + tree_to_uhwi (DECL_SIZE (a))); + } + + DECL_CHAIN (f) = fields; + fields = f; + } + + fields = nreverse (fields); + + /* Setup the struct/union type. Because we inherit all variably + modified components, we can ignore the size expression. */ + tree expr = NULL_TREE; + n = finish_struct(input_location, n, fields, attributes, NULL, &expr); + + n = qualify_type (n, t1); + + gcc_checking_assert (!TYPE_NAME (n) || comptypes (n, t1)); + gcc_checking_assert (!TYPE_NAME (n) || comptypes (n, t2)); + + return n; + } + /* FALLTHRU */ + case ENUMERAL_TYPE: if (attributes != NULL) { /* Try harder not to create a new aggregate type. */ @@ -520,7 +604,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 +650,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 +680,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 +689,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 +702,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 +711,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 +733,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 @@ -5566,6 +5662,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-alias-6.c b/gcc/testsuite/gcc.dg/c23-tag-alias-6.c new file mode 100644 index 00000000000..586965f3eac --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-6.c @@ -0,0 +1,32 @@ +/* { dg-do run } + * { dg-options "-std=c23 -O2" } + */ + + +/* These tests check that a composite type for a struct + * can alias the original definition. */ + +struct foo { int (*y)[]; int x; } s; + +int test_foo(struct foo* a, void* b) +{ + a->x = 1; + + struct foo { int (*y)[1]; int x; } t; + typeof(*(1 ? &s: &t)) *p = b; + p->x = 2; + + return a->x; +} + + +int main() +{ + struct foo y; + + if (2 != test_foo(&y, &y)) + __builtin_abort(); + + return 0; +} + 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..2c1c699440d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-composite-3.c @@ -0,0 +1,50 @@ +/* { dg-do compile } + * { dg-options "-std=c23" } + */ + +// bit-fields + +extern struct foo { int x:3; } x; +struct foo { int x:3; } y; + +void f() +{ + extern typeof(*(1 ? &x : &y)) x; + &x.x; /* { dg-error "bit-field" } */ +} + + +void g() +{ + struct foo { int x:3; } z; + extern typeof(*(1 ? &x : &z)) x; + &x.x; /* { dg-error "bit-field" } */ +} + +struct foo { int x:2; }; /* { dg-error "redefinition" } */ + +extern struct bar { int x:3; } a; + +void h() +{ + struct bar { signed int x:3; } b; + extern typeof(*(1 ? &a : &b)) a; + &a.x; /* { dg-error "bit-field" } */ +} + +void i() +{ + struct bar { unsigned int x:3; } c; + (1 ? &a : &c); /* { dg-error "mismatch" } */ +} + +struct bar { unsigned int x:3; } d; /* { dg-error "redefinition" } */ +struct bar { signed int x:3; } e; /* { dg-error "redefinition" } */ + + +struct bas { int x:2; int :0; int z:1; }; +struct bas { int x:2; int :0; int z:1; }; +struct bas { int x:2; int :1; int z:1; }; /* { 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; +} + diff --git a/gcc/testsuite/gcc.dg/c23-tag-composite-5.c b/gcc/testsuite/gcc.dg/c23-tag-composite-5.c new file mode 100644 index 00000000000..3e4820742f8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-composite-5.c @@ -0,0 +1,25 @@ +/* { dg-do compile } + * { dg-options "-std=c23" } + */ + +// anonymous structs / unions + +extern struct foo { int (*x)[]; struct { int y; }; } a; +extern struct foo { int (*x)[]; struct { int y; }; } a; +extern struct bar { int (*x)[]; union { int y; }; } b; +extern struct bar { int (*x)[]; union { int y; }; } b; + +void f(void) +{ + struct foo { int (*x)[1]; struct { int y; }; } c; + extern typeof(*(1 ? &a : &c)) a; + a.y; + + struct bar { int (*x)[1]; union { int y; }; } d; + extern typeof(*(1 ? &b : &d)) b; + b.y; +} + + +struct foo { int (*x)[]; union { int y; }; }; /* { dg-error "redefinition" } */ + diff --git a/gcc/testsuite/gcc.dg/c23-tag-composite-6.c b/gcc/testsuite/gcc.dg/c23-tag-composite-6.c new file mode 100644 index 00000000000..999bec60e5d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-composite-6.c @@ -0,0 +1,18 @@ +/* { dg-do compile } + * { dg-options "-std=c23" } + */ + +// alignment + +extern struct foo { char x; alignas(int) char y; } a; +extern struct foo { char x; alignas(int) char y; } a; + +void f() +{ + extern struct foo { char x; alignas(int) char y; } b; + extern typeof(*(1 ? &a : &b)) a; + static_assert(alignof(a.y) == alignof(int)); +} + + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-composite-7.c b/gcc/testsuite/gcc.dg/c23-tag-composite-7.c new file mode 100644 index 00000000000..a0976191f21 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-composite-7.c @@ -0,0 +1,20 @@ +/* { dg-do run } + * { dg-options "-std=c23" } + */ + +// bit-fields + +struct foo { char (*y)[]; unsigned x:3; } x; + +int main() +{ + struct foo { char (*y)[1]; unsigned x:3; } y; + + typeof(*(1 ? &x : &y)) a; + a.x = 8; /* { dg-warning "changes value" } */ + + if (a.x) + __builtin_abort(); +} + + diff --git a/gcc/testsuite/gcc.dg/c23-tag-composite-8.c b/gcc/testsuite/gcc.dg/c23-tag-composite-8.c new file mode 100644 index 00000000000..5c61119f9dd --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-composite-8.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c23" } */ + +// adapted from PR c/11428. + +struct s { int m : 1; char (*y)[]; } s; + +int +foo (void *q) +{ + struct s { int m : 1; char (*y)[1]; } t; + typeof(1 ? &s : &t) p = q; + return !p->m; +} + diff --git a/gcc/testsuite/gcc.dg/c23-tag-composite-9.c b/gcc/testsuite/gcc.dg/c23-tag-composite-9.c new file mode 100644 index 00000000000..46300eef9b6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-composite-9.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -Wc++-compat" } */ + +// test that DECL_BIT_FIELD_TYPE is set correctly + +enum e { A, B, C }; +struct s { enum e m : 3; char (*y)[]; } s = { }; + +void f(enum e); + +void foo () +{ + struct s { enum e m : 3; char (*y)[1]; } t = { }; + f(s.m); + f(t.m); + typeof(*(1 ? &s : &t)) u = { }; + f(u.m); // should not warn +} + diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c b/gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c new file mode 100644 index 00000000000..7ffaa8ad8af --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c @@ -0,0 +1,45 @@ +/* { dg-do compile } + * { dg-options "-std=c23" } + */ + +// packed structs + +struct foo { + char a; + int b [[gnu::packed]]; + char d; + int c [[gnu::packed]]; +}; + +struct foo { + char a; + int b [[gnu::packed]]; + char d; + int c [[gnu::packed]]; +}; + +extern struct foo x; + +void g() +{ + struct foo { + char a; + int b [[gnu::packed]]; + char d; + int c [[gnu::packed]]; + }; + + extern struct foo y; + extern typeof(*(1 ? &x : &y)) x; +} + +void h() +{ + struct foo { + char a; + int b; + char d; + int c; + }* z = &x; /* { dg-error "incompatible" } */ +} + diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c b/gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c new file mode 100644 index 00000000000..61f2feef183 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c @@ -0,0 +1,30 @@ +/* { dg-do compile } + * { dg-options "-std=c23" } + */ + +// attributes + +struct [[gnu::designated_init]] buf { char x; }; + +struct buf s = { 0 }; /* { dg-warning "positional" } */ + +void j() +{ + struct buf { char x; } t = { 0 }; + typeof(*(1 ? &s : &t)) u = { 0 }; /* { dg-warning "positional" } */ + typeof(*(1 ? &t : &s)) v = { 0 }; /* { dg-warning "positional" } */ +} + + +struct bar { struct buf y; }; +extern struct bar a; +struct bar a = { { 0 } }; /* { dg-warning "positional" } */ + +void k() +{ + struct buf { char x; } t = { 0 }; + struct bar { struct buf y; } b; + extern typeof(*(1 ? &a : &b)) a; + typeof(*(1 ? &a : &b)) c = { { 0 } }; /* { dg-warning "positional" } */ +} + diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c b/gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c new file mode 100644 index 00000000000..f69e9ee1379 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -std=gnu23" } */ + +// struct with variably-modified member + +struct s { char (*y)[]; } s; + +int +foo () +{ + int n = 10; + struct s { char (*y)[n]; } t; + typeof(*(1 ? &s : &t)) u; + return sizeof(*u.y); +} + +int main() +{ + if (10 != foo()) + __builtin_abort(); + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c b/gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c new file mode 100644 index 00000000000..f3cb7369d4a --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -std=gnu23" } */ + +// struct with variable size + + + +int +foo () +{ + int n = 10; + struct s { char buf[n]; } s; + { + int m = 10; + struct s { char buf[m]; } t; + typeof(*(1 ? &s : &t)) u; + return sizeof(u.buf); + } +} + +int main() +{ + if (10 != foo()) + __builtin_abort(); + + return 0; +} +