From: Martin Uecker <uecker@tugraz.at>
To: gcc-patches@gcc.gnu.org
Cc: Joseph Myers <joseph@codesourcery.com>
Subject: [C PATCH 3/6] c23: tag compatibility rules for struct and unions
Date: Sat, 26 Aug 2023 18:23:10 +0200 [thread overview]
Message-ID: <00f5c725f1e5234a8f5f396c393d4d09159c6eae.camel@tugraz.at> (raw)
In-Reply-To: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.camel@tugraz.at>
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" } */
+
--
2.30.2
next prev parent reply other threads:[~2023-08-26 16:23 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-26 16:19 c23 type compatibility rules, v2 Martin Uecker
2023-08-26 16:20 ` [C PATCH 1/6] c: reorganize recursive type checking Martin Uecker
2023-09-06 20:59 ` Joseph Myers
2023-09-10 8:17 ` [C PATCH 1/6 v2] " Martin Uecker
2023-09-11 20:28 ` Joseph Myers
2023-08-26 16:22 ` [C PATCH 2/6] c23: recursive type checking of tagged type Martin Uecker
2023-11-07 23:06 ` Joseph Myers
2023-08-26 16:23 ` Martin Uecker [this message]
2023-11-07 23:18 ` [C PATCH 3/6] c23: tag compatibility rules for struct and unions Joseph Myers
2023-08-26 16:24 ` [C PATCH 4/6] c23: tag compatibility rules for enums Martin Uecker
2023-11-07 23:20 ` Joseph Myers
2023-08-26 16:25 ` [C PATCH 5/6] c23: aliasing of compatible tagged types Martin Uecker
2023-08-26 16:26 ` [C PATCH 6/6] c23: construct composite type for " Martin Uecker
2023-11-07 23:45 ` Joseph Myers
2023-08-26 16:26 ` [C PATCH] c: flag for tag compatibility rules Martin Uecker
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=00f5c725f1e5234a8f5f396c393d4d09159c6eae.camel@tugraz.at \
--to=uecker@tugraz.at \
--cc=gcc-patches@gcc.gnu.org \
--cc=joseph@codesourcery.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).