From 1f59030b3af81efe67139ecb0c7d3f6e2312d5a7 Mon Sep 17 00:00:00 2001 From: k-hara Date: Tue, 6 Oct 2015 23:10:55 +0900 Subject: [PATCH] fix Issue 15149 - Linker error with separate compilation --- src/dstruct.d | 60 +++++++++++++++++++------ test/runnable/imports/link15194b.d | 7 +++ test/runnable/imports/link15194std.d | 67 ++++++++++++++++++++++++++++ test/runnable/link15149.d | 16 +++++++ 4 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 test/runnable/imports/link15194b.d create mode 100644 test/runnable/imports/link15194std.d create mode 100644 test/runnable/link15149.d diff --git a/src/dstruct.d b/src/dstruct.d index 93175f49c82c..ec2ba7878132 100644 --- a/src/dstruct.d +++ b/src/dstruct.d @@ -8,6 +8,7 @@ module ddmd.dstruct; +import core.stdc.stdio; import ddmd.aggregate; import ddmd.argtypes; import ddmd.arraytypes; @@ -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); @@ -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) @@ -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); @@ -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(). */ diff --git a/test/runnable/imports/link15194b.d b/test/runnable/imports/link15194b.d new file mode 100644 index 000000000000..fdba76902e83 --- /dev/null +++ b/test/runnable/imports/link15194b.d @@ -0,0 +1,7 @@ +module imports.link15194b; + +auto fun() +{ + import imports.link15194std; + return new RedBlackTree!int; +} diff --git a/test/runnable/imports/link15194std.d b/test/runnable/imports/link15194std.d new file mode 100644 index 000000000000..95c63ce99c9a --- /dev/null +++ b/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(); + } +} diff --git a/test/runnable/link15149.d b/test/runnable/link15149.d new file mode 100644 index 000000000000..6293ecf144e3 --- /dev/null +++ b/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); +}