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:
parent
14e19b82c1
commit
e419ede891
9 changed files with 216 additions and 4 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
4
gcc/testsuite/gdc.test/compilable/test21299a.d
Normal file
4
gcc/testsuite/gdc.test/compilable/test21299a.d
Normal file
|
@ -0,0 +1,4 @@
|
|||
// EXTRA_SOURCES: imports/test21299/mtype.d imports/test21299/rootstringtable.d
|
||||
// REQUIRED_ARGS: -main
|
||||
// LINK
|
||||
module test21299a;
|
4
gcc/testsuite/gdc.test/compilable/test21299b.d
Normal file
4
gcc/testsuite/gdc.test/compilable/test21299b.d
Normal file
|
@ -0,0 +1,4 @@
|
|||
// EXTRA_SOURCES: imports/test21299/func.d imports/test21299/rootstringtable.d
|
||||
// REQUIRED_ARGS: -main
|
||||
// LINK:
|
||||
module test21299b;
|
5
gcc/testsuite/gdc.test/compilable/test21299c.d
Normal file
5
gcc/testsuite/gdc.test/compilable/test21299c.d
Normal 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() {}
|
27
gcc/testsuite/gdc.test/compilable/test21299d.d
Normal file
27
gcc/testsuite/gdc.test/compilable/test21299d.d
Normal 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);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue