public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Martin Uecker <uecker@tugraz.at>
To: gcc-patches@gcc.gnu.org
Cc: Joseph Myers <joseph@codesourcery.com>
Subject: [C PATCH 6/6] c23: construct composite type for tagged types
Date: Sat, 26 Aug 2023 18:26:06 +0200	[thread overview]
Message-ID: <748ad71f62bb0e306d2fc050763b2e69ca81190f.camel@tugraz.at> (raw)
In-Reply-To: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.camel@tugraz.at>



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/c2x-tag-composite-1.c: New test.
	* gcc.dg/c2x-tag-composite-2.c: New test.
	* gcc.dg/c2x-tag-composite-3.c: New test.
	* gcc.dg/c2x-tag-composite-4.c: New test.
---
 gcc/c/c-typeck.cc                          | 114 +++++++++++++++++----
 gcc/testsuite/gcc.dg/c2x-tag-composite-1.c |  26 +++++
 gcc/testsuite/gcc.dg/c2x-tag-composite-2.c |  16 +++
 gcc/testsuite/gcc.dg/c2x-tag-composite-3.c |  17 +++
 gcc/testsuite/gcc.dg/c2x-tag-composite-4.c |  21 ++++
 5 files changed, 176 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-4.c

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 2489fa1e3d1..357367eab09 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;
@@ -425,7 +432,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);
@@ -433,7 +441,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);
@@ -501,9 +510,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_isoc2x && !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.  */
@@ -518,7 +579,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;
@@ -563,6 +625,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)
@@ -583,10 +655,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))
 		  {
@@ -596,8 +664,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;
@@ -608,10 +677,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))
 		  {
@@ -621,15 +686,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: ;
 	  }
 
@@ -641,7 +708,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
@@ -5480,6 +5553,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/c2x-tag-composite-1.c b/gcc/testsuite/gcc.dg/c2x-tag-composite-1.c
new file mode 100644
index 00000000000..aae11f6cee2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-tag-composite-1.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2x" } */
+
+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/c2x-tag-composite-2.c b/gcc/testsuite/gcc.dg/c2x-tag-composite-2.c
new file mode 100644
index 00000000000..dfc4336751a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-tag-composite-2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2x" } */
+
+
+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/c2x-tag-composite-3.c b/gcc/testsuite/gcc.dg/c2x-tag-composite-3.c
new file mode 100644
index 00000000000..02159f3c44d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-tag-composite-3.c
@@ -0,0 +1,17 @@
+/* { dg-do compile }
+ * { dg-options "-std=c2x" }
+ */
+
+// 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/c2x-tag-composite-4.c b/gcc/testsuite/gcc.dg/c2x-tag-composite-4.c
new file mode 100644
index 00000000000..1bd98cc1a44
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-tag-composite-4.c
@@ -0,0 +1,21 @@
+/* { dg-do compile }
+ * { dg-options "-std=c2x" } 
+ */
+
+// 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;
+}
+
-- 
2.30.2



  parent reply	other threads:[~2023-08-26 16:26 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 ` [C PATCH 3/6] c23: tag compatibility rules for struct and unions Martin Uecker
2023-11-07 23:18   ` 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 ` Martin Uecker [this message]
2023-11-07 23:45   ` [C PATCH 6/6] c23: construct composite type for " 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=748ad71f62bb0e306d2fc050763b2e69ca81190f.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).