Skip to content

Commit

Permalink
fix Issue 15149 - Linker error with separate compilation
Browse files Browse the repository at this point in the history
  • Loading branch information
9rnsr committed Oct 7, 2015
1 parent f8d24cd commit 1f59030
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 13 deletions.
60 changes: 47 additions & 13 deletions src/dstruct.d
Expand Up @@ -8,6 +8,7 @@

module ddmd.dstruct;

import core.stdc.stdio;
import ddmd.aggregate;
import ddmd.argtypes;
import ddmd.arraytypes;
Expand Down Expand Up @@ -104,15 +105,40 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t)
override void visit(TypeStruct t)
{
StructDeclaration sd = t.sym;

/* Step 1: create TypeInfoDeclaration
*/
if (!sc) // inline may request TypeInfo.
{
Scope scx;
scx._module = sd.getModule();
getTypeInfoType(t, &scx);
}
else
{
getTypeInfoType(t, sc);

// Bugzilla 15149, if the typeid operand type comes from a
// result of auto function, it may be yet speculative.
unSpeculative(sc, sd);
}
if (!sc || sc.minst)
sd.requestTypeInfo = true;

/* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
*/
if (!sd.members)
return; // opaque struct
if (sd.semanticRun >= PASSsemantic3)
return; // semantic3 will be done
if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.dtor && !sd.xhash && !search_toString(sd))
return; // none of TypeInfo-specific members

// If the struct is in a non-root module, run semantic3 to get
// correct symbols for the member function.
if (TemplateInstance ti = sd.isInstantiated())
if (sd.semanticRun >= PASSsemantic3)
{
// semantic3 is already done
}
else if (TemplateInstance ti = sd.isInstantiated())
{
if (ti.minst && !ti.minst.isRoot())
Module.addDeferredSemantic3(sd);
Expand All @@ -125,16 +151,6 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t)
Module.addDeferredSemantic3(sd);
}
}
if (!sc) // inline may request TypeInfo.
{
Scope scx;
scx._module = sd.getModule();
getTypeInfoType(t, &scx);
}
else
getTypeInfoType(t, sc);
if (!sc || sc.minst)
sd.requestTypeInfo = true;
}

override void visit(TypeClass t)
Expand All @@ -155,6 +171,19 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t)
}
}

if (sc)
{
if (!sc.func)
return;
if (sc.intypeof)
return;
if (sc.flags & (SCOPEctfe | SCOPEcompile))
return;

if (!sc.minst)
return; // don't have to generate TypeInfo inside speculative scope
}

scope FullTypeInfoVisitor v = new FullTypeInfoVisitor();
v.sc = sc;
t.accept(v);
Expand Down Expand Up @@ -371,19 +400,24 @@ public:
aggNew = cast(NewDeclaration)search(Loc(), Id.classNew);
aggDelete = cast(DeleteDeclaration)search(Loc(), Id.classDelete);
// this->ctor is already set in finalizeSize()

dtor = buildDtor(this, sc2);
postblit = buildPostBlit(this, sc2);

buildOpAssign(this, sc2);
buildOpEquals(this, sc2);

xeq = buildXopEquals(this, sc2);
xcmp = buildXopCmp(this, sc2);
xhash = buildXtoHash(this, sc2);

/* Even if the struct is merely imported and its semantic3 is not run,
* the TypeInfo object would be speculatively stored in each object
* files. To set correct function pointer, run semantic3 for xeq and xcmp.
*/
//if ((xeq && xeq != xerreq || xcmp && xcmp != xerrcmp) && isImportedSym(this))
// Module::addDeferredSemantic3(this);

/* Defer requesting semantic3 until TypeInfo generation is actually invoked.
* See semanticTypeInfo().
*/
Expand Down
7 changes: 7 additions & 0 deletions test/runnable/imports/link15194b.d
@@ -0,0 +1,7 @@
module imports.link15194b;

auto fun()
{
import imports.link15194std;
return new RedBlackTree!int;
}
67 changes: 67 additions & 0 deletions test/runnable/imports/link15194std.d
@@ -0,0 +1,67 @@
module imports.link15194std;

// std.algorithm.setopts

/* setUnion template function is instantiated in module link15194 as root,
* and linked into executable.
*
* - In "original case", due to link to typeid(const RBRange!(RBNode!int*)),
* unSpeculative should be called for the type of typeid operand.
*
* - In "additional case", typeid(const RBRange!(RBNode!int*)*) returns
* TypeInfo_Pointer instance. But later its 'next' field access will reference
* RBRange instance. Therefore typeid should also unSpeculative the bottom struct
* of operand type.
*/
version (A)
{
// additional case

TypeInfo setUnion(Rs...)(Rs )
{
return typeid(const Rs[0]*).next;

// semanticTypeInfo should also unSpaculate TypePointer.next.
}
}
else
{
// original case

struct SetUnion(Rs...)
{
pragma(msg, Rs);
Rs r;

// Rs[0] == RBRange!(RBNode!int*)
// Rs[1] == int[]

// size_t toHash() is implicitly generated by buildXtoHash.
// And from that,
// typeid(const RBRange!(RBNode!int*))
// and
// typeid(const int[])
// are referenced to invoke TypeInfo.getHash().
}

SetUnion!(Rs) setUnion(Rs...)(Rs )
{
return typeof(return)();
}
}

// std.container.rbtree

struct RBNode(V) {}

struct RBRange(N) {}

class RedBlackTree(Elem)
{
alias Range = RBRange!(RBNode!Elem*);

Range opSlice()
{
return Range();
}
}
16 changes: 16 additions & 0 deletions test/runnable/link15149.d
@@ -0,0 +1,16 @@
// REQUIRED_ARGS: -g
// PERMUTE_ARGS: -inline -version=A
// EXTRA_SOURCES: imports/link15194b.d imports/link15194std.d
// COMPILE_SEPARATELY: -g

import imports.link15194std;
import imports.link15194b;

void main()
{
int[] foo;

// fun() returns new RedBlackTree!int. But it's instantiated in
// non-template non-root function, so it's left as speculative.
setUnion(fun()[], foo);
}

0 comments on commit 1f59030

Please sign in to comment.