From 9dddefefdf407376ed3a0bba09a14f65b194898d Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Wed, 20 Mar 2019 23:52:48 +0000 Subject: [PATCH] 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 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 PR d/89017 * gdc.dg/pr89017.d: New test. From-SVN: r269828 --- gcc/d/ChangeLog | 8 ++++++ gcc/d/d-codegen.cc | 7 +---- gcc/d/decl.cc | 41 +++++++++++++++++++++++++++- gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/gdc.dg/pr89017.d | 49 ++++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gdc.dg/pr89017.d diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 8e45c7ffff7..39df9b8aac0 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,11 @@ +2019-03-21 Iain Buclaw + + 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 PR d/88957 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/ChangeLog b/gcc/testsuite/ChangeLog index 2a7a379c5dc..7487e91a954 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-03-21 Iain Buclaw + + PR d/89017 + * gdc.dg/pr89017.d: New test. + 2019-03-20 Janus Weil PR fortran/71861 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); +} -- 2.30.2