diff --git a/src/dmd/aggregate.d b/src/dmd/aggregate.d index f5cfc00d8fa0..225b9e990421 100644 --- a/src/dmd/aggregate.d +++ b/src/dmd/aggregate.d @@ -123,6 +123,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol DtorDeclaration tidtor; /// aggregate destructor used in TypeInfo (must have extern(D) ABI) FuncDeclaration fieldDtor; /// aggregate destructor for just the fields + Scope* rtInfoScope; /// save scope of declaration for RTInfo calculation Expression getRTInfo; /// pointer to GC info generated by object.RTInfo(this) Prot protection; /// visibility diff --git a/src/dmd/aggregate.h b/src/dmd/aggregate.h index 66cf0ec4ec41..80943cd33311 100644 --- a/src/dmd/aggregate.h +++ b/src/dmd/aggregate.h @@ -57,6 +57,13 @@ enum Abstract }; FuncDeclaration *search_toString(StructDeclaration *sd); +enum ZeroInit +{ + ZEROINITunknown = -1, // not computed yet + ZEROINITno = 0, // struct is not all zeroes + ZEROINITyes = 1 // struct is all zeroes +}; + struct ClassKind { @@ -113,6 +120,7 @@ class AggregateDeclaration : public ScopeDsymbol DtorDeclaration *tidtor; // aggregate destructor used in TypeInfo (must have extern(D) ABI) FuncDeclaration *fieldDtor; // aggregate destructor for just the fields + Scope* rtInfoScope; // save scope of declaration for RTInfo calculation Expression *getRTInfo; // pointer to GC info generated by object.RTInfo(this) Prot protection; @@ -159,7 +167,7 @@ struct StructFlags class StructDeclaration : public AggregateDeclaration { public: - bool zeroInit; // !=0 if initialize with 0 fill + ZeroInit zeroInit; // if struct is initialized to all zeroes bool hasIdentityAssign; // true if has identity opAssign bool hasBlitAssign; // true if opAssign is a blit bool hasIdentityEquals; // true if has identity opEquals @@ -193,6 +201,8 @@ class StructDeclaration : public AggregateDeclaration void finalizeSize(); bool fit(const Loc &loc, Scope *sc, Expressions *elements, Type *stype); bool isPOD(); + bool isZeroInit(); + ZeroInit calcZeroInit(); StructDeclaration *isStructDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } diff --git a/src/dmd/astbase.d b/src/dmd/astbase.d index 605f98436a03..0c6c4f3d8215 100644 --- a/src/dmd/astbase.d +++ b/src/dmd/astbase.d @@ -281,6 +281,13 @@ struct ASTBase fwd, // POD not yet computed } + enum ZeroInit : byte + { + unknown = -1, // not computed yet + no = 0, // struct is not all zeroes + yes = 1, // struct is all zeroes + }; + enum TRUST : ubyte { default_ = 0, @@ -1512,13 +1519,13 @@ struct ASTBase extern (C++) class StructDeclaration : AggregateDeclaration { - int zeroInit; + ZeroInit zeroInit; StructPOD ispod; final extern (D) this(const ref Loc loc, Identifier id, bool inObject) { super(loc, id); - zeroInit = 0; + zeroInit = ZeroInit.unknown; ispod = StructPOD.fwd; type = new TypeStruct(this); if (inObject) diff --git a/src/dmd/cond.d b/src/dmd/cond.d index 70da1d466a57..b3155a64fdcc 100644 --- a/src/dmd/cond.d +++ b/src/dmd/cond.d @@ -447,14 +447,15 @@ extern (C++) final class StaticForeach : RootObject } } - if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Terror) + auto ty = aggrfe ? aggrfe.aggr.type.toBasetype().ty : TMAX; + if (ty == Terror) { return; } if (!ready()) { - if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Tarray) + if (ty == Tarray || ty == Tsarray) { lowerArrayAggregate(sc); } diff --git a/src/dmd/dcast.d b/src/dmd/dcast.d index df4120cd7bd4..b3f39155bcf4 100644 --- a/src/dmd/dcast.d +++ b/src/dmd/dcast.d @@ -185,6 +185,18 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t) semanticTypeInfo(sc, ta.next); } + override void visit(AssocArrayLiteralExp e) + { + visit(cast(Expression)e); + semanticTypeInfo(sc, result.type); + } + + override void visit(NewExp e) + { + visit(cast(Expression)e); + semanticTypeInfo(sc, result.type); + } + override void visit(SliceExp e) { visit(cast(Expression)e); @@ -1750,6 +1762,12 @@ Expression castTo(Expression e, Scope* sc, Type t) result = e; } + override void visit(NewExp e) + { + visit(cast(Expression)e); + semanticTypeInfo(sc, result.type); + } + override void visit(StructLiteralExp e) { visit(cast(Expression)e); @@ -2209,6 +2227,7 @@ Expression castTo(Expression e, Scope* sc, Type t) { ae = cast(ArrayLiteralExp)e.copy(); ae.type = tp; + semanticTypeInfo(sc, ae.type); } } else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) @@ -2242,6 +2261,7 @@ Expression castTo(Expression e, Scope* sc, Type t) } Expression ev = new VectorExp(e.loc, ae, tb); ev = ev.expressionSemantic(sc); + semanticTypeInfo(sc, ev.type); result = ev; return; } @@ -2279,6 +2299,7 @@ Expression castTo(Expression e, Scope* sc, Type t) (*ae.keys)[i] = ex; } ae.type = t; + ae.verifyTypeInfo(sc); result = ae; return; } diff --git a/src/dmd/dstruct.d b/src/dmd/dstruct.d index e1ea4d16dbfe..7b976f4812df 100644 --- a/src/dmd/dstruct.d +++ b/src/dmd/dstruct.d @@ -70,6 +70,9 @@ extern (C++) FuncDeclaration search_toString(StructDeclaration sd) */ extern (C++) void semanticTypeInfo(Scope* sc, Type t) { + if (!global.params.useTypeInfo || !Type.dtypeinfo) + return; // not expected to be used with -betterC + if (sc) { if (sc.intypeof) @@ -128,7 +131,7 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t) */ if (!sd.members) return; // opaque struct - if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.dtor && !sd.xhash && !search_toString(sd)) + if (!Type.rtinfo && !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 @@ -166,7 +169,7 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t) /* Note structural similarity of this Type walker to that in isSpeculativeType() */ - Type tb = t.toBasetype(); + Type tb = t.toBasetype().mutableOf().unSharedOf(); // remove modifiers switch (tb.ty) { case Tvector: visitVector(tb.isTypeVector()); break; @@ -194,12 +197,19 @@ enum StructPOD : int fwd, // POD not yet computed } +private enum ZeroInit : byte +{ + unknown = -1, // not computed yet + no = 0, // struct is not all zeroes + yes = 1, // struct is all zeroes +}; + /*********************************************************** * All `struct` declarations are an instance of this. */ extern (C++) class StructDeclaration : AggregateDeclaration { - bool zeroInit; // !=0 if initialize with 0 fill + ZeroInit zeroInit; // if struct is initialized to all zeroes bool hasIdentityAssign; // true if has identity opAssign bool hasBlitAssign; // true if opAssign is a blit bool hasIdentityEquals; // true if has identity opEquals @@ -228,7 +238,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration extern (D) this(const ref Loc loc, Identifier id, bool inObject) { super(loc, id); - zeroInit = false; // assume false until we do semantic processing + zeroInit = ZeroInit.unknown; ispod = StructPOD.fwd; // For forward references type = new TypeStruct(this); @@ -386,36 +396,8 @@ extern (C++) class StructDeclaration : AggregateDeclaration return; } - // Determine if struct is all zeros or not - zeroInit = true; - foreach (vd; fields) - { - if (vd._init) - { - if (vd._init.isVoidInitializer()) - /* Treat as 0 for the purposes of putting the initializer - * in the BSS segment, or doing a mass set to 0 - */ - continue; - - // Zero size fields are zero initialized - if (vd.type.size(vd.loc) == 0) - continue; - - // Examine init to see if it is all 0s. - auto exp = vd.getConstInitializer(); - if (!exp || !_isZeroInit(exp)) - { - zeroInit = false; - break; - } - } - else if (!vd.type.isZeroInit(loc)) - { - zeroInit = false; - break; - } - } + if (zeroInit == ZeroInit.unknown) + zeroInit = calcZeroInit(); argTypes = target.toArgTypes(type); } @@ -585,6 +567,52 @@ extern (C++) class StructDeclaration : AggregateDeclaration return (ispod == StructPOD.yes); } + /*************************************** + * Lazily determine whether a struct init value is a chunk of zeroes + * + * Returns: + * true if struct is all zeroes + */ + final bool isZeroInit() + { + if (zeroInit == ZeroInit.unknown) + if (semanticRun < PASS.semanticdone && _scope) + dsymbolSemantic(this, null); + if (zeroInit == ZeroInit.unknown) + zeroInit = calcZeroInit(); + return zeroInit == ZeroInit.yes; + } + + private final ZeroInit calcZeroInit() + { + // Determine if struct is all zeros or not + foreach (vd; fields) + { + if (vd._init) + { + if (vd._init.isVoidInitializer()) + /* Treat as 0 for the purposes of putting the initializer + * in the BSS segment, or doing a mass set to 0 + */ + continue; + + // Zero size fields are zero initialized + if (vd.type.size(vd.loc) == 0) + continue; + + // Examine init to see if it is all 0s. + auto exp = vd.getConstInitializer(); + if (!exp || !_isZeroInit(exp)) + return ZeroInit.no; + } + else if (!vd.type.isZeroInit(loc)) + { + return ZeroInit.no; + } + } + return ZeroInit.yes; + } + override final inout(StructDeclaration) isStructDeclaration() inout { return this; diff --git a/src/dmd/dsymbolsem.d b/src/dmd/dsymbolsem.d index 3ade244db26f..3834ecc0b32a 100644 --- a/src/dmd/dsymbolsem.d +++ b/src/dmd/dsymbolsem.d @@ -1310,7 +1310,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor dsym._init = new ExpInitializer(dsym.loc, e); goto Ldtor; } - if (tv.ty == Tstruct && (cast(TypeStruct)tv).sym.zeroInit) + if (tv.ty == Tstruct && (cast(TypeStruct)tv).sym.isZeroInit()) { /* If a struct is all zeros, as a special case * set it's initializer to the integer 0. @@ -4827,6 +4827,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } + if (!sc.nofree) + sc.setNoFree(); // may need it even after semantic() finishes + sd.rtInfoScope = sc; + if (sd.type.ty == Tstruct && (cast(TypeStruct)sd.type).sym != sd) { // https://issues.dlang.org/show_bug.cgi?id=19024 @@ -5488,7 +5492,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor cldec.semanticRun = PASS.semanticdone; //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); - sc2.pop(); + sc2 = sc2.pop(); + + if (!sc2.nofree) + sc2.setNoFree(); // may need it even after semantic() finishes + cldec.rtInfoScope = sc2; /* isAbstract() is undecidable in some cases because of circular dependencies. * Now that semantic is finished, get a definitive result, and error if it is not the same. @@ -5840,7 +5848,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor idec.semanticRun = PASS.semanticdone; //printf("-InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); - sc2.pop(); + sc2 = sc2.pop(); + + if (!sc2.nofree) + sc2.setNoFree(); // may need it even after semantic() finishes + idec.rtInfoScope = sc2; if (global.errors != errors) { diff --git a/src/dmd/expression.d b/src/dmd/expression.d index 5447e031da25..ba3a40f2fcfd 100644 --- a/src/dmd/expression.d +++ b/src/dmd/expression.d @@ -3107,6 +3107,23 @@ extern (C++) final class ArrayLiteralExp : Expression } } +/*********************************************************** + * verify that TypeInfo for the expression type exists or generate it + * if necessary, i.e. the current scope is not during CTFE, but + * the type info will be needed by the code generation later. + * + * Params: + * ae = the array literal to verify + * sc = the scope in which the type info should be analyzed. If null, + * the global scope of Module.rootModule is used + */ +void verifyTypeInfo(ArrayLiteralExp ae, Scope* sc) +{ + if (ae.elements && !ae.type.vtinfo) + if (!sc || !(sc.flags & SCOPE.ctfe)) + semanticTypeInfo(sc ? sc : Module.rootModule._scope, ae.type); +} + /*********************************************************** * [ key0 : value0, key1 : value1, ... ] * @@ -3173,6 +3190,24 @@ extern (C++) final class AssocArrayLiteralExp : Expression } } +/*********************************************************** + * verify that TypeInfo for a non-empty associative array + * literal expression exists + * + * Params: + * aae = the associative array literal to verify + * sc = the scope in which the type info should be analyzed. If null, + * the global scope of Module.rootModule is used + */ +void verifyTypeInfo(AssocArrayLiteralExp aae, Scope* sc) +{ + if (aae.keys.dim) + { + Type t = aae.type.toBasetype().mutableOf(); + semanticTypeInfo(sc, t); + } +} + enum stageScrub = 0x1; /// scrubReturnValue is running enum stageSearchPointers = 0x2; /// hasNonConstPointers is running enum stageOptimize = 0x4; /// optimize is running @@ -3293,7 +3328,9 @@ extern (C++) final class StructLiteralExp : Expression auto z = new Expressions(length); foreach (ref q; *z) q = e.copy(); - e = new ArrayLiteralExp(loc, type, z); + ArrayLiteralExp ae = new ArrayLiteralExp(loc, type, z); + ae.verifyTypeInfo(null); // no Scope available here, will use rootModule + e = ae; } else { @@ -6300,6 +6337,22 @@ extern (C++) final class CatExp : BinExp } } +/*********************************************************** + * verify that TypeInfo for a CatExp expression exists + * + * Params: + * ce = the expression to verify + * sc = the scope in which the type info should be analyzed. + */ +void verifyTypeInfo(CatExp ce, Scope* sc) +{ + Type tb1 = ce.e1.type.toBasetype(); + Type tb2 = ce.e2.type.toBasetype(); + + Type ta = (tb1.ty == Tarray || tb1.ty == Tsarray) ? tb1 : tb2; + semanticTypeInfo(sc, ta); +} + /*********************************************************** * http://dlang.org/spec/expression.html#mul_expressions */ @@ -6554,6 +6607,29 @@ extern (C++) final class EqualExp : BinExp } } +/*********************************************************** + * verify that TypeInfo for an EqualExp expression exists + * + * Params: + * ee = the expression to verify + * sc = the scope in which the type info should be analyzed. + */ +void verifyTypeInfo(EqualExp ee, Scope* sc) +{ + Type t1 = ee.e1.type.toBasetype(); + Type t2 = ee.e2.type.toBasetype(); + + if ((t1.ty == Tarray || t1.ty == Tsarray) && + (t2.ty == Tarray || t2.ty == Tsarray)) + { + Type telement = t1.nextOf().toBasetype(); + Type telement2 = t2.nextOf().toBasetype(); + semanticTypeInfo(sc, telement.arrayOf()); + } + else if (t1.ty == Taarray && t2.toBasetype().ty == Taarray) + semanticTypeInfo(sc, t1); +} + /*********************************************************** * `is` and `!is` * diff --git a/src/dmd/expressionsem.d b/src/dmd/expressionsem.d index db6ea3e2f935..16e934be774f 100644 --- a/src/dmd/expressionsem.d +++ b/src/dmd/expressionsem.d @@ -3058,6 +3058,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (e.type) { + e.verifyTypeInfo(sc); result = e; return; } @@ -8018,6 +8019,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } semanticTypeInfo(sc, taa); + semanticTypeInfo(sc, taa.index); exp.type = taa.next; break; @@ -9131,6 +9133,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression ce = new CallExp(ale.loc, id, arguments); auto res = ce.expressionSemantic(sc); + semanticTypeInfo(sc, ale.e1.type.toBasetype()); // if (global.params.verbose) // message("lowered %s =>\n %s", exp.toChars(), res.toChars()); return setResult(res); @@ -9669,6 +9672,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc)) return setError(); + if (tb1.ty == Tarray) + semanticTypeInfo(sc, tb1); + exp.type = exp.e1.type; auto res = exp.reorderSettingAAElem(sc); if ((exp.op == TOK.concatenateElemAssign || exp.op == TOK.concatenateDcharAssign) && global.params.vsafe) @@ -11016,6 +11022,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = ex; return; } + + Type tb = e.e1.type.toBasetype(); + assert(tb.ty == Taarray); + TypeAArray taa = cast(TypeAArray)tb; + semanticTypeInfo(sc, taa.index); // needed by toElem + result = e; } diff --git a/src/dmd/mtype.d b/src/dmd/mtype.d index b83c804459fd..5aa768f39e8b 100644 --- a/src/dmd/mtype.d +++ b/src/dmd/mtype.d @@ -3718,8 +3718,7 @@ extern (C++) final class TypeSArray : TypeArray auto elements = new Expressions(d); foreach (ref e; *elements) e = null; - auto ae = new ArrayLiteralExp(Loc.initial, this, elementinit, elements); - return ae; + return new ArrayLiteralExp(Loc.initial, this, elementinit, elements); } override bool hasPointers() @@ -5823,7 +5822,7 @@ extern (C++) final class TypeStruct : Type { // Determine zeroInit here, as this can be called before semantic2 sym.determineSize(sym.loc); - return sym.zeroInit; + return sym.isZeroInit(); } override bool isAssignable() diff --git a/src/dmd/semantic3.d b/src/dmd/semantic3.d index 982d1e365965..3f46944b96b5 100644 --- a/src/dmd/semantic3.d +++ b/src/dmd/semantic3.d @@ -1441,6 +1441,34 @@ private extern(C++) final class Semantic3Visitor : Visitor } } + final void generateRTInfo(AggregateDeclaration ad, Scope* sc) + { + // don't do it for or error types + if (!ad.getRTInfo && Type.rtinfo && !global.params.betterC && (ad.type && ad.type.ty != Terror)) + { + // Evaluate: RTinfo!type + auto tiargs = new Objects(); + tiargs.push(ad.type); + auto ti = Pool!TemplateInstance.make(ad.loc, Type.rtinfo, tiargs); + + Scope* sc3 = ti.tempdecl._scope.startCTFE(); + sc3.tinst = sc.tinst; + sc3.minst = sc.minst; + if (ad.isDeprecated()) + sc3.stc |= STC.deprecated_; + + ti.dsymbolSemantic(sc3); + ti.semantic2(sc3); + ti.semantic3(sc3); + auto e = symbolToExp(ti.toAlias(), Loc.initial, sc3, false); + + sc3.endCTFE(); + + e = e.ctfeInterpret(); + ad.getRTInfo = e; + } + } + override void visit(AggregateDeclaration ad) { //printf("AggregateDeclaration::semantic3(sc=%p, %s) type = %s, errors = %d\n", sc, toChars(), type.toChars(), errors); @@ -1452,6 +1480,8 @@ private extern(C++) final class Semantic3Visitor : Visitor { assert(sd); sd.semanticTypeInfoMembers(); + if (ad.rtInfoScope) + generateRTInfo(ad, ad.rtInfoScope); return; } @@ -1465,35 +1495,24 @@ private extern(C++) final class Semantic3Visitor : Visitor sc2.pop(); - // don't do it for unused deprecated types - // or error ypes - if (!ad.getRTInfo && Type.rtinfo && (!ad.isDeprecated() || global.params.useDeprecated != DiagnosticReporting.error) && (ad.type && ad.type.ty != Terror)) - { - // Evaluate: RTinfo!type - auto tiargs = new Objects(); - tiargs.push(ad.type); - auto ti = Pool!TemplateInstance.make(ad.loc, Type.rtinfo, tiargs); - - Scope* sc3 = ti.tempdecl._scope.startCTFE(); - sc3.tinst = sc.tinst; - sc3.minst = sc.minst; - if (ad.isDeprecated()) - sc3.stc |= STC.deprecated_; - - ti.dsymbolSemantic(sc3); - ti.semantic2(sc3); - ti.semantic3(sc3); - auto e = symbolToExp(ti.toAlias(), Loc.initial, sc3, false); - - sc3.endCTFE(); + if (ad.rtInfoScope) + generateRTInfo(ad, ad.rtInfoScope); - e = e.ctfeInterpret(); - ad.getRTInfo = e; - } if (sd) sd.semanticTypeInfoMembers(); ad.semanticRun = PASS.semantic3done; } + + override void visit(TypeInfoStructDeclaration tid) + { + StructDeclaration sd = tid.tinfo.isTypeStruct().sym; + if (sd.members) + { + sd.semanticTypeInfoMembers(); + if (sd.rtInfoScope) + generateRTInfo(sd, sd.rtInfoScope); + } + } } private struct FuncDeclSem3 diff --git a/src/dmd/todt.d b/src/dmd/todt.d index 27d8953b1a01..c48da8f00115 100644 --- a/src/dmd/todt.d +++ b/src/dmd/todt.d @@ -1261,7 +1261,7 @@ private extern (C++) class TypeInfoDtVisitor : Visitor // void[] init; dtb.size(sd.structsize); // init.length - if (sd.zeroInit) + if (sd.isZeroInit()) dtb.size(0); // null for 0 initialization else dtb.xoff(toInitializer(sd), 0); // init.ptr @@ -1344,6 +1344,9 @@ private extern (C++) class TypeInfoDtVisitor : Visitor } } + if (Type.rtinfo && !sd.getRTInfo) + error(sd.loc, "ICE: RTInfo not evaluated for %s", sd.toPrettyChars(true)); + // xgetRTInfo if (sd.getRTInfo) { diff --git a/src/dmd/toobj.d b/src/dmd/toobj.d index 61b40c3c4466..c2af6fb907b9 100644 --- a/src/dmd/toobj.d +++ b/src/dmd/toobj.d @@ -720,6 +720,24 @@ void toObjFile(Dsymbol ds, bool multiobj) objmod.export_symbol(s, 0); } + override void visit(TypeInfoStructDeclaration tid) + { + if (!isError((cast(TypeStruct)tid.tinfo).sym)) + visit(cast(TypeInfoDeclaration)tid); + } + + override void visit(TypeInfoClassDeclaration tid) + { + if (!isError((cast(TypeClass)tid.tinfo).sym)) + visit(cast(TypeInfoDeclaration)tid); + } + + override void visit(TypeInfoInterfaceDeclaration tid) + { + if (!isError((cast(TypeClass)tid.tinfo).sym)) + visit(cast(TypeInfoDeclaration)tid); + } + override void visit(AttribDeclaration ad) { Dsymbols *d = ad.include(null); @@ -1346,6 +1364,9 @@ Louter: else dtb.size(0); + if (Type.rtinfo && !cd.getRTInfo) + error(cd.loc, "ICE: RTInfo not evaluated for %s", cd.toPrettyChars(true)); + // m_RTInfo if (cd.getRTInfo) Expression_toDt(cd.getRTInfo, dtb); @@ -1540,6 +1561,9 @@ private void genClassInfoForInterface(InterfaceDeclaration id) // xgetMembers //dtb.size(0); + if (Type.rtinfo && !id.getRTInfo) + error(id.loc, "ICE: RTInfo not evaluated for %s", id.toPrettyChars(true)); + // m_RTInfo if (id.getRTInfo) Expression_toDt(id.getRTInfo, dtb); diff --git a/src/dmd/typinf.d b/src/dmd/typinf.d index d1a254f8b51c..97ff59ea8f27 100644 --- a/src/dmd/typinf.d +++ b/src/dmd/typinf.d @@ -16,6 +16,7 @@ import dmd.dmodule; import dmd.dscope; import dmd.dclass; import dmd.dstruct; +import dmd.dsymbol; import dmd.errors; import dmd.globals; import dmd.gluelayer; @@ -71,7 +72,9 @@ void genTypeInfo(Loc loc, Type torig, Scope* sc) /* If this has a custom implementation in std/typeinfo, then * do not generate a COMDAT for it. */ - if (!builtinTypeInfo(t)) + if (t.ty == Terror) + t.vtinfo.errors = true; + else if (!builtinTypeInfo(t)) { // Generate COMDAT if (sc) // if in semantic() pass @@ -79,6 +82,8 @@ void genTypeInfo(Loc loc, Type torig, Scope* sc) // Find module that will go all the way to an object file Module m = sc._module.importedFrom; m.members.push(t.vtinfo); + if (m.semanticRun >= PASS.semantic3done) + Module.addDeferredSemantic3(t.vtinfo); } else // if in obj generation pass { diff --git a/test/runnable/imports/test10442a.d b/test/runnable/imports/test10442a.d new file mode 100644 index 000000000000..3793c6dc90a9 --- /dev/null +++ b/test/runnable/imports/test10442a.d @@ -0,0 +1,7 @@ +module imports.test10442a; + +struct S +{ + int x; + void* p; +} diff --git a/test/runnable/test10442.d b/test/runnable/test10442.d new file mode 100644 index 000000000000..5ec3296cf373 --- /dev/null +++ b/test/runnable/test10442.d @@ -0,0 +1,15 @@ +module test10442; +import imports.test10442a; + +struct T +{ + int x; + void* p; +} + +void main() +{ + // assumes enum RTInfo(T) merges identical bitmaps + assert(typeid(T).rtInfo !is null); // ok + assert(typeid(S).rtInfo is typeid(T).rtInfo); // fails +}