diff mbox series

[committed] d: Delay completing aggregate and enum types until after attributes have been applied.

Message ID 20220615103510.3604857-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Delay completing aggregate and enum types until after attributes have been applied. | expand

Commit Message

Iain Buclaw June 15, 2022, 10:35 a.m. UTC
Hi,

This patch rejigs the logic for completing D types with (eventually)
recursive references to itself within its members.  Because of these
forward/recursive references, the TYPE_SIZE, TYPE_ALIGN, and TYPE_MODE
of structs and enums were set before laying out its members.

This adds a new macro TYPE_FORWARD_REFERENCES for storing those forward
references against the incomplete type, laying them out after the type
has been completed.  Construction of the TYPE_DECL has also been moved
on earlier in the type generation pass, which will allow the possibility
of adding gdc-specific type attributes to the D front-end in the future.

Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32,
committed to mainline.

Regards,
Iain.

---
gcc/d/ChangeLog:

	* d-attribs.cc (apply_user_attributes): Set ATTR_FLAG_TYPE_IN_PLACE
	only on incomplete types.
	* d-codegen.cc (copy_aggregate_type): Set TYPE_STUB_DECL after copy.
	* d-compiler.cc (Compiler::onParseModule): Adjust.
	* d-tree.h (AGGREGATE_OR_ENUM_TYPE_CHECK): Define.
	(TYPE_FORWARD_REFERENCES): Define.
	* decl.cc (gcc_attribute_p): Update documentation.
	(DeclVisitor::visit (StructDeclaration *)): Exit before building type
	node if gcc.attributes symbol.
	(DeclVisitor::visit (ClassDeclaration *)): Build type node and add
	TYPE_NAME to current binding level before emitting anything else.
	(DeclVisitor::visit (InterfaceDeclaration *)): Likewise.
	(DeclVisitor::visit (EnumDeclaration *)): Likewise.
	(build_type_decl): Move rest_of_decl_compilation() call to
	finish_aggregate_type().
	* types.cc (insert_aggregate_field): Move layout_decl() call to
	finish_aggregate_type().
	(insert_aggregate_bitfield): Likewise.
	(layout_aggregate_members): Adjust.
	(finish_incomplete_fields): New function.
	(finish_aggregate_type): Handle forward referenced field types.  Call
	rest_of_type_compilation() after completing the aggregate.
	(TypeVisitor::visit (TypeEnum *)): Don't set size and alignment until
	after apply_user_attributes().  Call rest_of_type_compilation() after
	completing the enumeral.
	(TypeVisitor::visit (TypeStruct *)): Call build_type_decl() before
	apply_user_attributes().  Don't set size, alignment, and mode until
	after apply_user_attributes().
	(TypeVisitor::visit (TypeClass *)): Call build_type_decl() before
	applly_user_attributes().
---
 gcc/d/d-attribs.cc  |   7 ++-
 gcc/d/d-codegen.cc  |   1 +
 gcc/d/d-compiler.cc |  20 +++---
 gcc/d/d-tree.h      |  12 ++++
 gcc/d/decl.cc       |  44 +++++++-------
 gcc/d/types.cc      | 145 +++++++++++++++++++++++++++++++++-----------
 6 files changed, 159 insertions(+), 70 deletions(-)
diff mbox series

Patch

diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc
index c271de0c77e..b8ce30cf3c9 100644
--- a/gcc/d/d-attribs.cc
+++ b/gcc/d/d-attribs.cc
@@ -424,9 +424,12 @@  apply_user_attributes (Dsymbol *sym, tree node)
   location_t saved_location = input_location;
   input_location = make_location_t (sym->loc);
 
+  int attr_flags = 0;
+  if (TYPE_P (node) && !COMPLETE_TYPE_P (node))
+    attr_flags |= ATTR_FLAG_TYPE_IN_PLACE;
+
   Expressions *attrs = sym->userAttribDecl->getAttributes ();
-  decl_attributes (&node, build_attributes (attrs),
-		   TYPE_P (node) ? ATTR_FLAG_TYPE_IN_PLACE : 0);
+  decl_attributes (&node, build_attributes (attrs), attr_flags);
 
   input_location = saved_location;
 }
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 22090a8c755..0e14654e56b 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -115,6 +115,7 @@  tree
 copy_aggregate_type (tree type)
 {
   tree newtype = build_distinct_type_copy (type);
+  TYPE_STUB_DECL (newtype) = TYPE_NAME (newtype);
   TYPE_FIELDS (newtype) = copy_list (TYPE_FIELDS (type));
 
   for (tree f = TYPE_FIELDS (newtype); f; f = DECL_CHAIN (f))
diff --git a/gcc/d/d-compiler.cc b/gcc/d/d-compiler.cc
index 881f3863d2a..ada9721541b 100644
--- a/gcc/d/d-compiler.cc
+++ b/gcc/d/d-compiler.cc
@@ -129,22 +129,22 @@  Compiler::onParseModule (Module *m)
   if (md && md->id)
     {
       if (md->packages.length == 0)
-    	{
-    	  Identifier *id = (md && md->id) ? md->id : m->ident;
-    	  if (!strcmp (id->toChars (), "object"))
+	{
+	  Identifier *id = (md && md->id) ? md->id : m->ident;
+	  if (!strcmp (id->toChars (), "object"))
 	    {
 	      create_tinfo_types (m);
 	      return;
 	    }
 	}
       else if (md->packages.length == 1)
-    	{
-    	  if (!strcmp (md->packages.ptr[0]->toChars (), "gcc")
-    	      && !strcmp (md->id->toChars (), "builtins"))
-    	    {
-    	      d_build_builtins_module (m);
-    	      return;
-    	    }
+	{
+	  if (!strcmp (md->packages.ptr[0]->toChars (), "gcc")
+	      && !strcmp (md->id->toChars (), "builtins"))
+	    {
+	      d_build_builtins_module (m);
+	      return;
+	    }
 	}
     }
 
diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h
index 5f6b9d61001..48a40a6afa4 100644
--- a/gcc/d/d-tree.h
+++ b/gcc/d/d-tree.h
@@ -57,6 +57,9 @@  typedef Array <Expression *> Expressions;
    4: TYPE_DELEGATE (in RECORD_TYPE).
    5: TYPE_ASSOCIATIVE_ARRAY (in RECORD_TYPE).
 
+   Usage of TYPE_LANG_SLOT_?:
+   1: TYPE_FORWARD_REFERENCES (in RECORD_TYPE, UNION_TYPE).
+
    Usage of DECL_LANG_FLAG_?:
    0: LABEL_VARIABLE_CASE (in LABEL_DECL).
       DECL_BUILT_IN_CTFE (in FUNCTION_DECL).
@@ -68,6 +71,10 @@  typedef Array <Expression *> Expressions;
 #define VAR_OR_FUNCTION_DECL_CHECK(NODE) \
   TREE_CHECK2 (NODE, VAR_DECL, FUNCTION_DECL)
 
+#define AGGREGATE_OR_ENUM_TYPE_CHECK(NODE) \
+  TREE_CHECK4 (NODE, RECORD_TYPE, UNION_TYPE, \
+	       QUAL_UNION_TYPE, ENUMERAL_TYPE)
+
 /* The kinds of scopes we recognize.  */
 
 enum level_kind
@@ -378,6 +385,11 @@  lang_tree_node
 #define TYPE_ASSOCIATIVE_ARRAY(NODE) \
   (TYPE_LANG_FLAG_5 (RECORD_TYPE_CHECK (NODE)))
 
+/* In an incomplete RECORD_TYPE, UNION_TYPE, or ENUMERAL_TYPE, a list of field
+   declarations whose type would be completed by completing that type.  */
+#define TYPE_FORWARD_REFERENCES(NODE) \
+  (TYPE_LANG_SLOT_1 (AGGREGATE_OR_ENUM_TYPE_CHECK (NODE)))
+
 /* True if the decl is a variable case label decl.  */
 #define LABEL_VARIABLE_CASE(NODE) \
   (DECL_LANG_FLAG_0 (LABEL_DECL_CHECK (NODE)))
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 5d850065bf0..518d84c1a49 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -99,7 +99,7 @@  mangle_internal_decl (Dsymbol *decl, const char *name, const char *suffix)
   return ident;
 }
 
-/* Returns true if DECL is from the gcc.attribute module.  */
+/* Returns true if DECL is from the gcc.attributes module.  */
 
 static bool
 gcc_attribute_p (Dsymbol *decl)
@@ -367,6 +367,10 @@  public:
 	return;
       }
 
+    /* Don't emit any symbols from gcc.attributes module.  */
+    if (gcc_attribute_p (d))
+      return;
+
     /* Add this decl to the current binding level.  */
     tree ctype = build_ctype (d->type);
     if (TYPE_NAME (ctype))
@@ -377,10 +381,6 @@  public:
     if (d->isAnonymous () || !d->members)
       return;
 
-    /* Don't emit any symbols from gcc.attribute module.  */
-    if (gcc_attribute_p (d))
-      return;
-
     /* Generate TypeInfo.  */
     if (have_typeinfo_p (Type::dtypeinfo))
       create_typeinfo (d->type, NULL);
@@ -482,6 +482,11 @@  public:
 	return;
       }
 
+    /* Add this decl to the current binding level.  */
+    tree ctype = TREE_TYPE (build_ctype (d->type));
+    if (TYPE_NAME (ctype))
+      d_pushdecl (TYPE_NAME (ctype));
+
     if (!d->members)
       return;
 
@@ -533,11 +538,6 @@  public:
       = build_constructor (TREE_TYPE (vtblsym->csym), elms);
     d_finish_decl (vtblsym->csym);
 
-    /* Add this decl to the current binding level.  */
-    tree ctype = TREE_TYPE (build_ctype (d->type));
-    if (TYPE_NAME (ctype))
-      d_pushdecl (TYPE_NAME (ctype));
-
     d->semanticRun = PASS::obj;
   }
 
@@ -556,6 +556,11 @@  public:
 	return;
       }
 
+    /* Add this decl to the current binding level.  */
+    tree ctype = TREE_TYPE (build_ctype (d->type));
+    if (TYPE_NAME (ctype))
+      d_pushdecl (TYPE_NAME (ctype));
+
     if (!d->members)
       return;
 
@@ -576,11 +581,6 @@  public:
     DECL_INITIAL (d->csym) = layout_classinfo (d);
     d_finish_decl (d->csym);
 
-    /* Add this decl to the current binding level.  */
-    tree ctype = TREE_TYPE (build_ctype (d->type));
-    if (TYPE_NAME (ctype))
-      d_pushdecl (TYPE_NAME (ctype));
-
     d->semanticRun = PASS::obj;
   }
 
@@ -599,6 +599,11 @@  public:
 	return;
       }
 
+    /* Add this decl to the current binding level.  */
+    tree ctype = build_ctype (d->type);
+    if (TREE_CODE (ctype) == ENUMERAL_TYPE && TYPE_NAME (ctype))
+      d_pushdecl (TYPE_NAME (ctype));
+
     if (d->isAnonymous ())
       return;
 
@@ -615,11 +620,6 @@  public:
 	d_finish_decl (d->sinit);
       }
 
-    /* Add this decl to the current binding level.  */
-    tree ctype = build_ctype (d->type);
-    if (TYPE_NAME (ctype))
-      d_pushdecl (TYPE_NAME (ctype));
-
     d->semanticRun = PASS::obj;
   }
 
@@ -776,7 +776,7 @@  public:
     if (d->semanticRun >= PASS::obj)
       return;
 
-    /* Don't emit any symbols from gcc.attribute module.  */
+    /* Don't emit any symbols from gcc.attributes module.  */
     if (gcc_attribute_p (d))
       return;
 
@@ -2336,8 +2336,6 @@  build_type_decl (tree type, Dsymbol *dsym)
     }
   else if (type != TYPE_MAIN_VARIANT (type))
     DECL_ORIGINAL_TYPE (decl) = TYPE_MAIN_VARIANT (type);
-
-  rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0);
 }
 
 /* Create a declaration for field NAME of a given TYPE, setting the flags
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index b17b15359c8..0926715b7dc 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -270,7 +270,6 @@  insert_aggregate_field (tree type, tree field, size_t offset)
 
   TREE_ADDRESSABLE (field) = TYPE_SHARED (TREE_TYPE (field));
 
-  layout_decl (field, 0);
   TYPE_FIELDS (type) = chainon (TYPE_FIELDS (type), field);
 }
 
@@ -326,17 +325,6 @@  insert_aggregate_bitfield (tree type, tree bitfield, size_t width,
   DECL_BIT_FIELD (bitfield) = 1;
   DECL_BIT_FIELD_TYPE (bitfield) = TREE_TYPE (bitfield);
 
-  layout_decl (bitfield, 0);
-
-  /* Give bit-field its proper type after layout_decl.  */
-  tree orig_type = DECL_BIT_FIELD_TYPE (bitfield);
-  if (width != TYPE_PRECISION (orig_type))
-    {
-      TREE_TYPE (bitfield)
-    	= d_build_bitfield_integer_type (width, TYPE_UNSIGNED (orig_type));
-      SET_DECL_MODE (bitfield, TYPE_MODE (TREE_TYPE (bitfield)));
-    }
-
   TYPE_FIELDS (type) = chainon (TYPE_FIELDS (type), bitfield);
 }
 
@@ -432,7 +420,7 @@  layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p)
 					     bf->offset, bf->bitOffset);
 		}
 	      else
-  		insert_aggregate_field (context, field, var->offset);
+		insert_aggregate_field (context, field, var->offset);
 
 	      /* Because the front-end shares field decls across classes, don't
 		 create the corresponding back-end symbol unless we are adding
@@ -585,6 +573,35 @@  layout_aggregate_type (AggregateDeclaration *decl, tree type,
     }
 }
 
+/* If the aggregate type TYPE completes the type of any previous field
+   declarations, lay them out now.  */
+
+static void
+finish_incomplete_fields (tree type)
+{
+  for (tree fwdref = TYPE_FORWARD_REFERENCES (type); fwdref != NULL_TREE;
+       fwdref = TREE_CHAIN (fwdref))
+    {
+      tree field = TREE_VALUE (fwdref);
+      tree basetype = TREE_TYPE (field);
+
+      /* Arrays of TYPE have layout_type() called from build_array_type(), but
+	 would skip over setting TYPE_SIZE. Try completing the type again.  */
+      if (TREE_CODE (basetype) == ARRAY_TYPE)
+	{
+	  while (TREE_CODE (TREE_TYPE (basetype)) == ARRAY_TYPE)
+	    basetype = TREE_TYPE (basetype);
+
+	  layout_type (basetype);
+	}
+
+      relayout_decl (field);
+    }
+
+  /* No more forward references to process.  */
+  TYPE_FORWARD_REFERENCES (type) = NULL_TREE;
+}
+
 /* Given a record type TYPE, whose size and alignment are determined by
    STRUCTSIZE and ALIGNSIZE.  Apply any type attributes ATTRS and compute
    the finalized record mode.  */
@@ -601,7 +618,51 @@  finish_aggregate_type (unsigned structsize, unsigned alignsize, tree type)
   /* Set the back-end type mode.  */
   compute_record_mode (type);
 
-  /* Fix up all variants of this aggregate type.  */
+  /* Layout all fields now the type is complete.  */
+  for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+    {
+      /* If the field type is still being constructed because of recursive
+	 references, attach it to that class/struct type, so we can go back
+	 and complete the field later.  */
+      if (!COMPLETE_TYPE_P (TREE_TYPE (field)))
+	{
+	  tree basetype = TREE_TYPE (field);
+	  while (TREE_CODE (basetype) == ARRAY_TYPE)
+	    basetype = TREE_TYPE (basetype);
+
+	  basetype = TYPE_MAIN_VARIANT (basetype);
+	  if (RECORD_OR_UNION_TYPE_P (basetype)
+	      || TREE_CODE (basetype) == ENUMERAL_TYPE)
+	    {
+	      gcc_assert (!COMPLETE_TYPE_P (basetype));
+	      tree fwdrefs = tree_cons (NULL_TREE, field,
+					TYPE_FORWARD_REFERENCES (basetype));
+	      TYPE_FORWARD_REFERENCES (basetype) = fwdrefs;
+	    }
+
+	  continue;
+	}
+
+      layout_decl (field, 0);
+
+      /* Give bit-field its proper type after layout_decl.  */
+      if (DECL_BIT_FIELD (field))
+	{
+	  tree orig_type = DECL_BIT_FIELD_TYPE (field);
+	  unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_SIZE (field));
+
+	  if (width != TYPE_PRECISION (orig_type))
+	    {
+	      bool unsignedp = TYPE_UNSIGNED (orig_type);
+
+	      TREE_TYPE (field)
+		= d_build_bitfield_integer_type (width, unsignedp);
+	      SET_DECL_MODE (field, TYPE_MODE (TREE_TYPE (field)));
+	    }
+	}
+    }
+
+  /* Fix up all forward-referenced variants of this aggregate type.  */
   for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
     {
       if (t == type)
@@ -609,10 +670,21 @@  finish_aggregate_type (unsigned structsize, unsigned alignsize, tree type)
 
       TYPE_FIELDS (t) = TYPE_FIELDS (type);
       TYPE_LANG_SPECIFIC (t) = TYPE_LANG_SPECIFIC (type);
+      TYPE_SIZE (t) = TYPE_SIZE (type);
+      TYPE_SIZE_UNIT (t) = TYPE_SIZE_UNIT (type);
+      TYPE_PACKED (type) = TYPE_PACKED (type);
+      SET_TYPE_MODE (t, TYPE_MODE (type));
       SET_TYPE_ALIGN (t, TYPE_ALIGN (type));
       TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (type);
-      gcc_assert (TYPE_MODE (t) == TYPE_MODE (type));
     }
+
+  /* Finish debugging output for this type.  */
+  rest_of_type_compilation (type, TYPE_FILE_SCOPE_P (type));
+  finish_incomplete_fields (type);
+
+  /* Finish processing of TYPE_DECL.  */
+  rest_of_decl_compilation (TYPE_NAME (type),
+			    DECL_FILE_SCOPE_P (TYPE_NAME (type)), 0);
 }
 
 /* Returns true if the class or struct type TYPE has already been layed out by
@@ -1021,13 +1093,6 @@  public:
 	if (flag_short_enums)
 	  TYPE_PACKED (t->ctype) = 1;
 
-	TYPE_PRECISION (t->ctype) = t->size (t->sym->loc) * 8;
-	TYPE_SIZE (t->ctype) = 0;
-
-	TYPE_MIN_VALUE (t->ctype) = TYPE_MIN_VALUE (basetype);
-	TYPE_MAX_VALUE (t->ctype) = TYPE_MAX_VALUE (basetype);
-	layout_type (t->ctype);
-
 	tree values = NULL_TREE;
 	if (t->sym->members)
 	  {
@@ -1057,11 +1122,31 @@  public:
 	  }
 
 	TYPE_VALUES (t->ctype) = values;
-	TYPE_UNSIGNED (t->ctype) = TYPE_UNSIGNED (basetype);
 	build_type_decl (t->ctype, t->sym);
       }
 
     apply_user_attributes (t->sym, t->ctype);
+
+    /* Finish the enumeration type.  */
+    if (TREE_CODE (t->ctype) == ENUMERAL_TYPE)
+      {
+	TYPE_MIN_VALUE (t->ctype) = TYPE_MIN_VALUE (basetype);
+	TYPE_MAX_VALUE (t->ctype) = TYPE_MAX_VALUE (basetype);
+	TYPE_UNSIGNED (t->ctype) = TYPE_UNSIGNED (basetype);
+	SET_TYPE_ALIGN (t->ctype, TYPE_ALIGN (basetype));
+	TYPE_SIZE (t->ctype) = NULL_TREE;
+	TYPE_PRECISION (t->ctype) = t->size (t->sym->loc) * 8;
+
+	layout_type (t->ctype);
+
+	/* Finish debugging output for this type.  */
+	rest_of_type_compilation (t->ctype, TYPE_FILE_SCOPE_P (t->ctype));
+	finish_incomplete_fields (t->ctype);
+
+	/* Finish processing of TYPE_DECL.  */
+	rest_of_decl_compilation (TYPE_NAME (t->ctype),
+				  DECL_FILE_SCOPE_P (TYPE_NAME (t->ctype)), 0);
+      }
   }
 
   /* Build a struct or union type.  Layout should be exactly represented
@@ -1092,21 +1177,13 @@  public:
 	unsigned alignsize = t->sym->alignment.isDefault ()
 	  ? t->sym->alignsize : t->sym->alignment.get ();
 
-	TYPE_SIZE (t->ctype) = bitsize_int (structsize * BITS_PER_UNIT);
-	TYPE_SIZE_UNIT (t->ctype) = size_int (structsize);
-	SET_TYPE_ALIGN (t->ctype, alignsize * BITS_PER_UNIT);
-	TYPE_PACKED (t->ctype) = (alignsize == 1);
-	compute_record_mode (t->ctype);
-
 	/* Put out all fields.  */
 	layout_aggregate_type (t->sym, t->ctype, t->sym);
+	build_type_decl (t->ctype, t->sym);
 	apply_user_attributes (t->sym, t->ctype);
 	finish_aggregate_type (structsize, alignsize, t->ctype);
       }
 
-    TYPE_CONTEXT (t->ctype) = d_decl_context (t->sym);
-    build_type_decl (t->ctype, t->sym);
-
     /* For structs with a user defined postblit, copy constructor, or a
        destructor, also set TREE_ADDRESSABLE on the type and all variants.
        This will make the struct be passed around by reference.  */
@@ -1146,6 +1223,7 @@  public:
 
     /* Put out all fields, including from each base class.  */
     layout_aggregate_type (t->sym, basetype, t->sym);
+    build_type_decl (basetype, t->sym);
     apply_user_attributes (t->sym, basetype);
     finish_aggregate_type (t->sym->structsize, t->sym->alignsize, basetype);
 
@@ -1183,9 +1261,6 @@  public:
 	    && !chain_member (method, TYPE_FIELDS (basetype)))
 	  TYPE_FIELDS (basetype) = chainon (TYPE_FIELDS (basetype), method);
       }
-
-    TYPE_CONTEXT (basetype) = d_decl_context (t->sym);
-    build_type_decl (basetype, t->sym);
   }
 };