diff mbox series

[PR,d/89017] Committed fix for ICE in force_type_die, at dwarf2out.c

Message ID CABOHX+fgRzZoA4bhdQBJw+NzQ6CegOkCyxBtviSQDOuuAi-R7Q@mail.gmail.com
State New
Headers show
Series [PR,d/89017] Committed fix for ICE in force_type_die, at dwarf2out.c | expand

Commit Message

Iain Buclaw March 20, 2019, 11:53 p.m. UTC
Hi,

This patch adds a new visit method in the decl walker to handle
functions whose return type is instantiated from a nested template (a
voldemort type), as it needs to be ensured that all members of the
instance are emitted before finishing the outer function, otherwise
they will be removed during the prune_unused_types pass.  Fixing PR
d/89017.

Bootstrapped and regression tested on x86_64-linux-gnu.

Committed to trunk as r269828.
diff mbox series

Patch

diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index e8233b43c67..26929109b48 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -67,7 +67,7 @@  d_decl_context (Dsymbol *dsym)
   Dsymbol *parent = dsym;
   Declaration *decl = dsym->isDeclaration ();
 
-  while ((parent = parent->toParent ()))
+  while ((parent = parent->toParent2 ()))
     {
       /* We've reached the top-level module namespace.
 	 Set DECL_CONTEXT as the NAMESPACE_DECL of the enclosing module,
@@ -101,11 +101,6 @@  d_decl_context (Dsymbol *dsym)
 
 	  return context;
 	}
-
-      /* Instantiated types are given the context of their template.  */
-      TemplateInstance *ti = parent->isTemplateInstance ();
-      if (ti != NULL && decl == NULL)
-	parent = ti->tempdecl;
     }
 
   return NULL_TREE;
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 7edfe523d3e..fffed97727f 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -255,6 +255,40 @@  public:
       }
   }
 
+  /* Templates are D's approach to generic programming.  They have no members
+     that can be emitted, however if the template is nested and used as a
+     voldemort type, then it's members must be compiled before the parent
+     function finishes.  */
+
+  void visit (TemplateDeclaration *d)
+  {
+    /* Type cannot be directly named outside of the scope it's declared in, so
+       the only way it can be escaped is if the function has auto return.  */
+    FuncDeclaration *fd = d_function_chain ? d_function_chain->function : NULL;
+
+    if (!fd || !fd->isAuto ())
+      return;
+
+    /* Check if the function returns an instantiated type that may contain
+       nested members.  Only applies to classes or structs.  */
+    Type *tb = fd->type->nextOf ()->baseElemOf ();
+
+    while (tb->ty == Tarray || tb->ty == Tpointer)
+      tb = tb->nextOf ()->baseElemOf ();
+
+    TemplateInstance *ti = NULL;
+
+    if (tb->ty == Tstruct)
+      ti = ((TypeStruct *) tb)->sym->isInstantiated ();
+    else if (tb->ty == Tclass)
+      ti = ((TypeClass *) tb)->sym->isInstantiated ();
+
+    /* Return type is instantiated from this template declaration, walk over
+       all members of the instance.  */
+    if (ti && ti->tempdecl == d)
+      ti->accept (this);
+  }
+
   /* Walk over all members in the instantiated template.  */
 
   void visit (TemplateInstance *d)
@@ -2228,8 +2262,13 @@  build_type_decl (tree type, Dsymbol *dsym)
 
   gcc_assert (!POINTER_TYPE_P (type));
 
+  /* If a templated type, use the template instance name, as that includes all
+     template parameters.  */
+  const char *name = dsym->parent->isTemplateInstance ()
+    ? ((TemplateInstance *) dsym->parent)->toChars () : dsym->ident->toChars ();
+
   tree decl = build_decl (make_location_t (dsym->loc), TYPE_DECL,
-			  get_identifier (dsym->ident->toChars ()), type);
+			  get_identifier (name), type);
   SET_DECL_ASSEMBLER_NAME (decl, get_identifier (mangle_decl (dsym)));
   TREE_PUBLIC (decl) = 1;
   DECL_ARTIFICIAL (decl) = 1;
diff --git a/gcc/testsuite/gdc.dg/pr89017.d b/gcc/testsuite/gdc.dg/pr89017.d
new file mode 100644
index 00000000000..b796e6246e8
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr89017.d
@@ -0,0 +1,49 @@ 
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89017
+// { dg-do compile }
+
+enum Type
+{
+    Struct,
+    Class,
+    Pointer,
+    Array,
+}
+
+auto f89017(Type type)()
+{
+    static if (type == Type.Class)
+    {
+        class C(S)
+        {
+            struct S
+            {
+                void fn(){}
+            }
+        }
+    }
+    else
+    {
+        struct C(S)
+        {
+            struct S
+            {
+                void fn(){}
+            }
+        }
+    }
+
+    static if (type == Type.Struct)
+        return C!Type();
+    static if (type == Type.Class || type == Type.Pointer)
+        return new C!Type();
+    static if (type == Type.Array)
+        return new C!Type[2];
+}
+
+void test89017()
+{
+    f89017!(Type.Class);
+    f89017!(Type.Struct);
+    f89017!(Type.Pointer);
+    f89017!(Type.Array);
+}