d: Merge upstream dmd 0fcdaab32

Fixes a bug where there was undefined template references when compiling
upstream dmd mainline.

In `TemplateInstance::semantic`, there exists special handling of
matching template instances for the same template declaration to ensure
that only at most one instance gets codegen'd.

If the primary instance `inst` originated from a non-root module, the
`minst` field will be updated so it is now coming from a root module,
however all Dsymbol `inst->members` of the instance still have their
`_scope->minst` pointing at the original non-root module. We must now
propagate `minst` to all members so that forward referenced dependencies
that get instantiated will also be appended to the root module,
otherwise there will be undefined references at link-time.

This doesn't affect compilations where all modules are compiled
together, as every module is a root module in that situation.  What this
primarily affects are cases where there is a mix of root and non-root
modules, and a template was first instantiated in a non-root context,
then later instantiated again in a root context.

Reviewed-on: https://github.com/dlang/dmd/pull/11867

gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 0fcdaab32
This commit is contained in:
Iain Buclaw 2020-10-23 09:41:11 +02:00
parent 14e19b82c1
commit e419ede891
9 changed files with 216 additions and 4 deletions

View file

@ -1,4 +1,4 @@
70aabfb511d55f2bfbdccbac7868519d9d4b63da
0fcdaab32c7645820820f6e1474343ccfb7560e5
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.

View file

@ -33,6 +33,7 @@
#include "hdrgen.h"
#include "id.h"
#include "attrib.h"
#include "cond.h"
#include "tokens.h"
#define IDX_NOTFOUND (0x12345678) // index is not found
@ -6088,17 +6089,18 @@ Lerror:
if (minst && minst->isRoot() && !(inst->minst && inst->minst->isRoot()))
{
/* Swap the position of 'inst' and 'this' in the instantiation graph.
* Then, the primary instance `inst` will be changed to a root instance.
* Then, the primary instance `inst` will be changed to a root instance,
* along with all members of `inst` having their scopes updated.
*
* Before:
* non-root -> A!() -> B!()[inst] -> C!()
* non-root -> A!() -> B!()[inst] -> C!() { members[non-root] }
* |
* root -> D!() -> B!()[this]
*
* After:
* non-root -> A!() -> B!()[this]
* |
* root -> D!() -> B!()[inst] -> C!()
* root -> D!() -> B!()[inst] -> C!() { members[root] }
*/
Module *mi = minst;
TemplateInstance *ti = tinst;
@ -6107,6 +6109,64 @@ Lerror:
inst->minst = mi;
inst->tinst = ti;
/* https://issues.dlang.org/show_bug.cgi?id=21299
`minst` has been updated on the primary instance `inst` so it is
now coming from a root module, however all Dsymbol `inst.members`
of the instance still have their `_scope.minst` pointing at the
original non-root module. We must now propagate `minst` to all
members so that forward referenced dependencies that get
instantiated will also be appended to the root module, otherwise
there will be undefined references at link-time. */
class InstMemberWalker : public Visitor
{
public:
TemplateInstance *inst;
InstMemberWalker(TemplateInstance *inst)
: inst(inst) { }
void visit(Dsymbol *d)
{
if (d->_scope)
d->_scope->minst = inst->minst;
}
void visit(ScopeDsymbol *sds)
{
if (!sds->members)
return;
for (size_t i = 0; i < sds->members->length; i++)
{
Dsymbol *s = (*sds->members)[i];
s->accept(this);
}
visit((Dsymbol *)sds);
}
void visit(AttribDeclaration *ad)
{
Dsymbols *d = ad->include(NULL);
if (!d)
return;
for (size_t i = 0; i < d->length; i++)
{
Dsymbol *s = (*d)[i];
s->accept(this);
}
visit((Dsymbol *)ad);
}
void visit(ConditionalDeclaration *cd)
{
if (cd->condition->inc)
visit((AttribDeclaration *)cd);
else
visit((Dsymbol *)cd);
}
};
InstMemberWalker v(inst);
inst->accept(&v);
if (minst) // if inst was not speculative
{
/* Add 'inst' once again to the root module members[], then the

View file

@ -0,0 +1,8 @@
module imports.test21299.func;
import imports.test21299.mtype;
import imports.test21299.rootstringtable;
class FuncDeclaration {
StringTable!Type stringtable;
StringTable2!Type stringtable2;
StringTable3!Type stringtable3;
}

View file

@ -0,0 +1,8 @@
module imports.test21299.mtype;
import imports.test21299.func;
import imports.test21299.rootstringtable;
class Type {
StringTable!Type stringtable;
StringTable2!Type stringtable2;
StringTable3!Type stringtable3;
}

View file

@ -0,0 +1,96 @@
module imports.test21299.rootstringtable;
struct StringValue(T)
{
char* lstring()
{
return cast(char*)&this;
}
}
struct StringTable(T)
{
StringValue!T* insert()
{
allocValue;
return getValue;
}
uint allocValue()
{
StringValue!(T) sv;
sv.lstring[0] = 0;
return 0;
}
StringValue!T* getValue()
{
return cast(StringValue!T*)&this;
}
}
// Other tests are the same as the original issue, but use other kinds of
// nesting Dsymbols that need to be handled by templateInstanceSemantic().
struct StringValue2(T)
{
char* lstring()
{
return cast(char*)&this;
}
}
struct StringTable2(T)
{
@nogc // AttribDeclaration (also covers pragma, extern(), static foreach, ...)
{
StringValue2!T* insert()
{
allocValue;
return getValue;
}
uint allocValue()
{
StringValue2!(T) sv;
sv.lstring[0] = 0;
return 0;
}
StringValue2!T* getValue()
{
return cast(StringValue2!T*)&this;
}
}
}
//
struct StringValue3(T)
{
char* lstring()
{
return cast(char*)&this;
}
}
struct StringTable3(T)
{
static if (true) // ConditionalDeclaration (static if)
{
StringValue3!T* insert()
{
allocValue;
return getValue;
}
uint allocValue()
{
StringValue3!(T) sv;
sv.lstring[0] = 0;
return 0;
}
StringValue3!T* getValue()
{
return cast(StringValue3!T*)&this;
}
}
}

View file

@ -0,0 +1,4 @@
// EXTRA_SOURCES: imports/test21299/mtype.d imports/test21299/rootstringtable.d
// REQUIRED_ARGS: -main
// LINK
module test21299a;

View file

@ -0,0 +1,4 @@
// EXTRA_SOURCES: imports/test21299/func.d imports/test21299/rootstringtable.d
// REQUIRED_ARGS: -main
// LINK:
module test21299b;

View file

@ -0,0 +1,5 @@
// EXTRA_SOURCES: imports/test21299/mtype.d imports/test21299/func.d imports/test21299/rootstringtable.d
// COMPILE_SEPARATELY:
// LINK:
module test21299c;
void main() {}

View file

@ -0,0 +1,27 @@
// REQUIRED_ARGS: -main
// LINK:
module test21299d;
struct DefaultPredicates
{
struct IsEqual(T)
{
static opCall(in T, in T)
{
return 0;
}
}
}
void moveToEnd(T, Pred = DefaultPredicates.IsEqual!T)(T[] array, T element, Pred pred = Pred.init)
{
pred(array[0], element);
}
class Task
{
void removeTerminationHook(void delegate() hook)
{
moveToEnd([], hook);
}
}