d: Fix ICE force_type_die, at dwarf2out.c using nested types

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
This commit is contained in:
Iain Buclaw 2019-03-20 23:52:48 +00:00 committed by Iain Buclaw
parent 5d2df818b7
commit 9dddefefdf
5 changed files with 103 additions and 7 deletions

View 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

View 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;

View 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;

View 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

View File

@ -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);
}