d: Fix ICE force_type_die, at dwarf2out.c using nested types
authorIain Buclaw <ibuclaw@gdcproject.org>
Wed, 20 Mar 2019 23:52:48 +0000 (23:52 +0000)
committerIain Buclaw <ibuclaw@gcc.gnu.org>
Wed, 20 Mar 2019 23:52:48 +0000 (23:52 +0000)
In functions whose return type is instantiated from a nested template,
make sure that all members of the instance are emitted before finishing
the outer function, otherwise they will be removed during the
prune_unused_types pass.

gcc/d/ChangeLog:

2019-03-21  Iain Buclaw  <ibuclaw@gdcproject.org>

PR d/89017
* d-codegen.cc (d_decl_context): Skip over template instances when
finding the context.
* decl.cc (DeclVisitor::visit(TemplateDeclaration)): New override.
(build_type_decl): Include parameters in name of template types.

gcc/testsuite/ChangeLog:

2019-03-21  Iain Buclaw  <ibuclaw@gdcproject.org>

PR d/89017
* gdc.dg/pr89017.d: New test.

From-SVN: r269828

gcc/d/ChangeLog
gcc/d/d-codegen.cc
gcc/d/decl.cc
gcc/testsuite/ChangeLog
gcc/testsuite/gdc.dg/pr89017.d [new file with mode: 0644]

index 8e45c7ffff73d4f25e829eb585fe3c8d2b3b865d..39df9b8aac0ad21f694c170ef78cf7eb97f9675b 100644 (file)
@@ -1,3 +1,11 @@
+2019-03-21  Iain Buclaw  <ibuclaw@gdcproject.org>
+
+       PR d/89017
+       * d-codegen.cc (d_decl_context): Skip over template instances when
+       finding the context.
+       * decl.cc (DeclVisitor::visit(TemplateDeclaration)): New override.
+       (build_type_decl): Include parameters in name of template types.
+
 2019-03-13  Iain Buclaw  <ibuclaw@gdcproject.org>
 
        PR d/88957
index e8233b43c67198a10e8c7c15e07e6b23cb7a951c..26929109b486c4376306a5f66c52c978c3561e35 100644 (file)
@@ -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;
index 7edfe523d3e92be0276a0806ec00c3b39b5e07a4..fffed97727f186c9a237fa41b267cc3541288bac 100644 (file)
@@ -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;
index 2a7a379c5dc384fec62143ec49276610530a3047..7487e91a95485cb13848cf83f490cb70988f4ed2 100644 (file)
@@ -1,3 +1,8 @@
+2019-03-21  Iain Buclaw  <ibuclaw@gdcproject.org>
+
+       PR d/89017
+       * gdc.dg/pr89017.d: New test.
+
 2019-03-20  Janus Weil  <janus@gcc.gnu.org>
 
        PR fortran/71861
diff --git a/gcc/testsuite/gdc.dg/pr89017.d b/gcc/testsuite/gdc.dg/pr89017.d
new file mode 100644 (file)
index 0000000..b796e62
--- /dev/null
@@ -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);
+}