From patchwork Sat Aug 26 16:23:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1826417 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=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=iYSa+iNO; 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 4RY2FC5zZ0z1yZ9 for ; Sun, 27 Aug 2023 02:23:43 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D4B07385828D for ; Sat, 26 Aug 2023 16:23:41 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D4B07385828D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1693067021; bh=x426C35Ym19uYRSSSw4TSk00Xo8Z2aeZqGIojk5vs3E=; h=Subject:To:Cc:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=iYSa+iNOU/1Vbu54cko/OLNSk2fy9TDwQiItQu20lqBBbfy7RqEVyj/lamv0eZuWA sBi2l30Gu9ihok355Lr0n/JTb//ypSbRt9lQmVZo8CAy1klm2n9TpEL8ZtFzyxlVI2 /Hi6ZFIYD1s7Dy88EkbeMSTsKer+DqRE78PxjZpk= 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 0CB563858412 for ; Sat, 26 Aug 2023 16:23:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0CB563858412 Received: from vra-173-28.tugraz.at (vra-173-28.tugraz.at [129.27.173.28]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4RY2Db34DMz3whg; Sat, 26 Aug 2023 18:23:11 +0200 (CEST) Message-ID: <00f5c725f1e5234a8f5f396c393d4d09159c6eae.camel@tugraz.at> Subject: [C PATCH 3/6] c23: tag compatibility rules for struct and unions To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sat, 26 Aug 2023 18:23:10 +0200 In-Reply-To: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.camel@tugraz.at> References: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.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.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Martin Uecker via Gcc-patches From: Martin Uecker Reply-To: Martin Uecker Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" 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/c2x-enum-7.c: Remove warning. * gcc.dg/c2x-tag-1.c: New test. * gcc.dg/c2x-tag-2.c: New test. * gcc.dg/c2x-tag-3.c: New test. * gcc.dg/c2x-tag-4.c: New test. * gcc.dg/c2x-tag-5.c: New test. * gcc.dg/c2x-tag-6.c: New test. * gcc.dg/c2x-tag-7.c: New test. * gcc.dg/c2x-tag-8.c: New test. * gcc.dg/c2x-tag-9.c: New test. * gcc.dg/c2x-tag-10.c: New test. --- gcc/c/c-decl.cc | 56 ++++++++++++++++++++++--- gcc/c/c-tree.h | 1 + gcc/c/c-typeck.cc | 38 +++++++++++++---- gcc/testsuite/gcc.dg/c2x-enum-7.c | 6 +-- gcc/testsuite/gcc.dg/c2x-tag-1.c | 68 +++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-10.c | 31 ++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-2.c | 43 +++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-3.c | 16 ++++++++ gcc/testsuite/gcc.dg/c2x-tag-4.c | 19 +++++++++ gcc/testsuite/gcc.dg/c2x-tag-5.c | 26 ++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-6.c | 34 ++++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-7.c | 28 +++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-8.c | 25 ++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-9.c | 12 ++++++ 14 files changed, 387 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-1.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-10.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-2.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-3.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-4.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-5.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-6.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-7.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-8.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-9.c diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 1f9eb44dbaa..c5c6a853fa9 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -1993,6 +1993,24 @@ locate_old_decl (tree decl) decl, TREE_TYPE (decl)); } +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 @@ -8442,11 +8460,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_isoc2x) + 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, @@ -8651,6 +8672,12 @@ start_struct (location_t loc, enum tree_code code, tree name, if (name != NULL_TREE) ref = lookup_tag (code, name, true, &refloc); + + /* For C2X, even if we already have a completed definition, + we do not use it. We will check for consistency later. */ + if (flag_isoc2x && ref && TYPE_SIZE (ref)) + ref = NULL_TREE; + if (ref && TREE_CODE (ref) == code) { if (TYPE_STUB_DECL (ref)) @@ -9439,6 +9466,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_isoc2x) + { + 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 7c5234e80fd..511fd9ee0e5 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -747,6 +747,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 41ef05f005c..802c727d9d3 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1058,6 +1058,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. */ @@ -1243,11 +1260,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_isoc2x) + 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)) @@ -6978,7 +6995,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); @@ -8315,6 +8332,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 %qT %qT", type, TREE_TYPE (inside_init)); + return error_mark_node; + } + if (require_constant && TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR) { @@ -10399,7 +10423,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/c2x-enum-7.c b/gcc/testsuite/gcc.dg/c2x-enum-7.c index 08bae31d82c..d4ddcc821dc 100644 --- a/gcc/testsuite/gcc.dg/c2x-enum-7.c +++ b/gcc/testsuite/gcc.dg/c2x-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/c2x-tag-1.c b/gcc/testsuite/gcc.dg/c2x-tag-1.c new file mode 100644 index 00000000000..0cda7aa0c34 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-1.c @@ -0,0 +1,68 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// 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[0]; }; +struct r { int a; char b[1]; }; /* { dg-error "redefinition of struct or union" } */ + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-10.c b/gcc/testsuite/gcc.dg/c2x-tag-10.c new file mode 100644 index 00000000000..39abcb2db60 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-10.c @@ -0,0 +1,31 @@ +/* { dg-do compile } + * { dg-options "-std=c2x" } */ + +// 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; } +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-2.c b/gcc/testsuite/gcc.dg/c2x-tag-2.c new file mode 100644 index 00000000000..a68392e1fab --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-2.c @@ -0,0 +1,43 @@ +/* { dg-do { compile xfail { *-*-* } } } + * { dg-options "-std=c2x" } + */ + +// 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/c2x-tag-3.c b/gcc/testsuite/gcc.dg/c2x-tag-3.c new file mode 100644 index 00000000000..bafb08ca11d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-3.c @@ -0,0 +1,16 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// 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/c2x-tag-4.c b/gcc/testsuite/gcc.dg/c2x-tag-4.c new file mode 100644 index 00000000000..b7c793c2dce --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-4.c @@ -0,0 +1,19 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// 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/c2x-tag-5.c b/gcc/testsuite/gcc.dg/c2x-tag-5.c new file mode 100644 index 00000000000..b597d6403d2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-5.c @@ -0,0 +1,26 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// 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/c2x-tag-6.c b/gcc/testsuite/gcc.dg/c2x-tag-6.c new file mode 100644 index 00000000000..bf7cfb342d4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-6.c @@ -0,0 +1,34 @@ +/* + * { dg-do { run xfail { "*-*-*" } } } + * { dg-options "-std=c2x" } + */ + +// 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/c2x-tag-7.c b/gcc/testsuite/gcc.dg/c2x-tag-7.c new file mode 100644 index 00000000000..7ec121fe80e --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-7.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/c2x-tag-8.c b/gcc/testsuite/gcc.dg/c2x-tag-8.c new file mode 100644 index 00000000000..d1f503f23ba --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-8.c @@ -0,0 +1,25 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// (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/c2x-tag-9.c b/gcc/testsuite/gcc.dg/c2x-tag-9.c new file mode 100644 index 00000000000..fdbae7baf46 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-9.c @@ -0,0 +1,12 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// 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" } */ +