From a16826730fb7987d2012144cf7eaf46c53ae3735 Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Wed, 22 Nov 2017 13:29:18 +0200 Subject: [PATCH] Fix Issue 17371 - [REG 2.074.0] di generation broken for anonymous classes --- src/ddmd/aggregate.h | 19 ++++++-- src/ddmd/dclass.d | 58 +++++++++++++++++++------ src/ddmd/declaration.d | 2 +- src/ddmd/dsymbolsem.d | 24 +++++----- src/ddmd/e2ir.d | 4 +- src/ddmd/hdrgen.d | 5 ++- src/ddmd/mtype.d | 2 +- src/ddmd/objc.d | 4 +- src/ddmd/opover.d | 2 +- src/ddmd/tocvdebug.d | 2 +- src/ddmd/todt.d | 2 +- src/ddmd/toobj.d | 2 +- test/compilable/extra-files/header2.d | 12 +++++ test/compilable/extra-files/header2.di | 17 ++++++++ test/compilable/extra-files/header2i.di | 17 ++++++++ 15 files changed, 130 insertions(+), 42 deletions(-) diff --git a/src/ddmd/aggregate.h b/src/ddmd/aggregate.h index d484ff153688..4fd413d7dcae 100644 --- a/src/ddmd/aggregate.h +++ b/src/ddmd/aggregate.h @@ -247,6 +247,18 @@ struct ClassFlags }; }; +enum ClassKind +{ + /// the class is a d(efault) class + d, + /// the class is a C++ interface + cpp, + /// the class is an Objective-C class/interface + objc, + /// the class is anonymous + anonymous, +}; + class ClassDeclaration : public AggregateDeclaration { public: @@ -273,11 +285,10 @@ class ClassDeclaration : public AggregateDeclaration TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration bool com; // true if this is a COM class (meaning it derives from IUnknown) - bool cpp; // true if this is a C++ interface - bool isobjc; // true if this is an Objective-C class/interface - bool isscope; // true if this is a scope class + bool stack; // true if this is a scope class + ClassKind classKind; // specifies the linkage type + Abstract isabstract; // 0: fwdref, 1: is abstract class, 2: not abstract - int inuse; // to prevent recursive attempts Baseok baseok; // set the progress of base classes resolving Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr diff --git a/src/ddmd/dclass.d b/src/ddmd/dclass.d index 18bee52d1b0e..53d2aaa294c8 100644 --- a/src/ddmd/dclass.d +++ b/src/ddmd/dclass.d @@ -179,6 +179,24 @@ struct ClassFlags alias hasDtor = Enum.hasDtor; } +/** + * The ClassKind enum is used in ClassDeclaration AST nodes + * to specify the linkage type of the class or if it is an + * anonymous class. If the class is anonymous it is also + * considered to be a D class. + */ +enum ClassKind : int +{ + /// the class is a d(efault) class + d, + /// the class is a C++ interface + cpp, + /// the class is an Objective-C class/interface + objc, + /// the class is anonymous + anonymous, +} + /*********************************************************** */ extern (C++) class ClassDeclaration : AggregateDeclaration @@ -212,20 +230,32 @@ extern (C++) class ClassDeclaration : AggregateDeclaration // the ClassInfo object for this ClassDeclaration TypeInfoClassDeclaration vclassinfo; - bool com; // true if this is a COM class (meaning it derives from IUnknown) - bool cpp; // true if this is a C++ interface - bool isobjc; // true if this is an Objective-C class/interface - bool isscope; // true if this is a scope class - private bool inuse; // to prevent recursive attempts + // true if this is a COM class + bool com; + + /// true if this is a scope class + bool stack; + + /// specifies whether this is a D, C++, Objective-C or anonymous class/interface + ClassKind classKind; + + /// to prevent recursive attempts + private bool inuse; + Abstract isabstract; - Baseok baseok; // set the progress of base classes resolving + + /// set the progress of base classes resolving + Baseok baseok; Symbol* cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr final extern (D) this(Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject) { if (!id) + { id = Identifier.generateId("__anonclass"); + classKind = ClassKind.anonymous; + } assert(id); super(loc, id); @@ -584,7 +614,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration alignsize = baseClass.alignsize; structsize = baseClass.structsize; - if (cpp && global.params.isWindows) + if (classKind == ClassKind.cpp && global.params.isWindows) structsize = (structsize + alignsize - 1) & ~(alignsize - 1); } else if (isInterfaceDeclaration()) @@ -599,7 +629,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration { alignsize = Target.ptrsize; structsize = Target.ptrsize; // allow room for __vptr - if (!cpp) + if (classKind != ClassKind.cpp) structsize += Target.ptrsize; // allow room for __monitor } @@ -817,7 +847,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration final bool isCPPclass() const { - return cpp; + return classKind == ClassKind.cpp; } bool isCPPinterface() const @@ -932,7 +962,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration */ int vtblOffset() const { - return cpp ? 0 : 1; + return classKind == ClassKind.cpp ? 0 : 1; } /**************************************** @@ -973,7 +1003,7 @@ extern (C++) final class InterfaceDeclaration : ClassDeclaration if (id == Id.IUnknown) // IUnknown is the root of all COM interfaces { com = true; - cpp = true; // IUnknown is also a C++ interface + classKind = ClassKind.cpp; // IUnknown is also a C++ interface } } @@ -991,9 +1021,9 @@ extern (C++) final class InterfaceDeclaration : ClassDeclaration auto sc2 = super.newScope(sc); if (com) sc2.linkage = LINKwindows; - else if (cpp) + else if (classKind == ClassKind.cpp) sc2.linkage = LINKcpp; - else if (isobjc) + else if (classKind == ClassKind.objc) sc2.linkage = LINKobjc; return sc2; } @@ -1087,7 +1117,7 @@ extern (C++) final class InterfaceDeclaration : ClassDeclaration override bool isCPPinterface() const { - return cpp; + return classKind == ClassKind.cpp; } override bool isCOMinterface() const diff --git a/src/ddmd/declaration.d b/src/ddmd/declaration.d index 4bb810a0fe2c..cc32ec56a27c 100644 --- a/src/ddmd/declaration.d +++ b/src/ddmd/declaration.d @@ -1343,7 +1343,7 @@ extern (C++) class VarDeclaration : Declaration // Destroying C++ scope classes crashes currently. Since C++ class dtors are not currently supported, simply do not run dtors for them. // See https://issues.dlang.org/show_bug.cgi?id=13182 - if (cd.cpp) + if (cd.classKind == ClassKind.cpp) { break; } diff --git a/src/ddmd/dsymbolsem.d b/src/ddmd/dsymbolsem.d index 34e825aba28e..af6e801b6cf8 100644 --- a/src/ddmd/dsymbolsem.d +++ b/src/ddmd/dsymbolsem.d @@ -4497,7 +4497,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor /* These quirky conditions mimic what VC++ appears to do */ - if (global.params.mscoff && cd.cpp && + if (global.params.mscoff && cd.classKind == ClassKind.cpp && cd.baseClass && cd.baseClass.vtbl.dim) { /* if overriding an interface function, then this is not @@ -4523,7 +4523,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { //printf("\tintroducing function %s\n", toChars()); funcdecl.introducing = 1; - if (cd.cpp && Target.reverseCppOverloads) + if (cd.classKind == ClassKind.cpp && Target.reverseCppOverloads) { // with dmc, overloaded functions are grouped and in reverse order funcdecl.vtblIndex = cast(int)cd.vtbl.dim; @@ -5594,14 +5594,14 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (cldec.storage_class & STCauto) cldec.error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?"); if (cldec.storage_class & STCscope) - cldec.isscope = true; + cldec.stack = true; if (cldec.storage_class & STCabstract) cldec.isabstract = ABSyes; cldec.userAttribDecl = sc.userAttribDecl; if (sc.linkage == LINKcpp) - cldec.cpp = true; + cldec.classKind = ClassKind.cpp; if (sc.linkage == LINKobjc) objc.setObjc(cldec); } @@ -5795,7 +5795,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor cldec.baseok = BASEOKdone; // If no base class, and this is not an Object, use Object as base class - if (!cldec.baseClass && cldec.ident != Id.Object && !cldec.cpp) + if (!cldec.baseClass && cldec.ident != Id.Object && !cldec.classKind == ClassKind.cpp) { void badObjectDotD() { @@ -5829,9 +5829,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (cldec.baseClass.isCOMclass()) cldec.com = true; if (cldec.baseClass.isCPPclass()) - cldec.cpp = true; - if (cldec.baseClass.isscope) - cldec.isscope = true; + cldec.classKind = ClassKind.cpp; + if (cldec.baseClass.stack) + cldec.stack = true; cldec.enclosing = cldec.baseClass.enclosing; cldec.storage_class |= cldec.baseClass.storage_class & STC_TYPECTOR; } @@ -5843,7 +5843,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // then this is a COM interface too. if (b.sym.isCOMinterface()) cldec.com = true; - if (cldec.cpp && !b.sym.isCPPinterface()) + if (cldec.classKind == ClassKind.cpp && !b.sym.isCPPinterface()) { error(cldec.loc, "C++ class '%s' cannot implement D interface '%s'", cldec.toPrettyChars(), b.sym.toPrettyChars()); @@ -5917,7 +5917,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // initialize vtbl if (cldec.baseClass) { - if (cldec.cpp && cldec.baseClass.vtbl.dim == 0) + if (cldec.classKind == ClassKind.cpp && cldec.baseClass.vtbl.dim == 0) { cldec.error("C++ base class %s needs at least one virtual function", cldec.baseClass.toChars()); } @@ -6256,7 +6256,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } if (!idec.baseclasses.dim && sc.linkage == LINKcpp) - idec.cpp = true; + idec.classKind = ClassKind.cpp; if (sc.linkage == LINKobjc) objc.setObjc(idec); @@ -6333,7 +6333,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (b.sym.isCOMinterface()) idec.com = true; if (b.sym.isCPPinterface()) - idec.cpp = true; + idec.classKind = ClassKind.cpp; } interfaceSemantic(idec); diff --git a/src/ddmd/e2ir.d b/src/ddmd/e2ir.d index 97a29edada65..7780d6b9ef6a 100644 --- a/src/ddmd/e2ir.d +++ b/src/ddmd/e2ir.d @@ -4179,9 +4179,9 @@ elem *toElem(Expression e, IRState *irs) // Casting from derived class to base class is a no-op } } - else if (cdfrom.cpp) + else if (cdfrom.classKind == ClassKind.cpp) { - if (cdto.cpp) + if (cdto.classKind == ClassKind.cpp) { /* Casting from a C++ interface to a C++ interface * is always a 'paint' operation diff --git a/src/ddmd/hdrgen.d b/src/ddmd/hdrgen.d index 178bbd5b3860..448d81402bc0 100644 --- a/src/ddmd/hdrgen.d +++ b/src/ddmd/hdrgen.d @@ -1754,7 +1754,7 @@ public: override void visit(ClassDeclaration d) { - if (!d.isAnonymous()) + if (d.classKind != ClassKind.anonymous) { buf.writestring(d.kind()); buf.writeByte(' '); @@ -1781,7 +1781,8 @@ public: { if (!d || !d.baseclasses.dim) return; - buf.writestring(" : "); + if (d.classKind != ClassKind.anonymous) + buf.writestring(" : "); foreach (i, b; *d.baseclasses) { if (i) diff --git a/src/ddmd/mtype.d b/src/ddmd/mtype.d index 2f51206375da..97a76e5fdcc2 100644 --- a/src/ddmd/mtype.d +++ b/src/ddmd/mtype.d @@ -8534,7 +8534,7 @@ extern (C++) final class TypeClass : Type override bool isscope() const { - return sym.isscope; + return sym.stack; } override bool isBoolean() const diff --git a/src/ddmd/objc.d b/src/ddmd/objc.d index d2d0a376ce64..590d25b4af79 100644 --- a/src/ddmd/objc.d +++ b/src/ddmd/objc.d @@ -188,12 +188,12 @@ extern(C++) private final class Supported : Objc override void setObjc(ClassDeclaration cd) { - cd.isobjc = true; + cd.classKind = ClassKind.objc; } override void setObjc(InterfaceDeclaration id) { - id.isobjc = true; + id.classKind = ClassKind.objc; } override void setSelector(FuncDeclaration fd, Scope* sc) diff --git a/src/ddmd/opover.d b/src/ddmd/opover.d index 5862730478cd..ab9bf45bd997 100644 --- a/src/ddmd/opover.d +++ b/src/ddmd/opover.d @@ -1145,7 +1145,7 @@ extern (C++) Expression op_overload(Expression e, Scope* sc) { ClassDeclaration cd1 = t1.isClassHandle(); ClassDeclaration cd2 = t2.isClassHandle(); - if (!(cd1.cpp || cd2.cpp)) + if (!(cd1.classKind == ClassKind.cpp || cd2.classKind == ClassKind.cpp)) { /* Rewrite as: * .object.opEquals(e1, e2) diff --git a/src/ddmd/tocvdebug.d b/src/ddmd/tocvdebug.d index 5371b9d66a2c..d15c9a625ef3 100644 --- a/src/ddmd/tocvdebug.d +++ b/src/ddmd/tocvdebug.d @@ -538,7 +538,7 @@ void toDebug(ClassDeclaration cd) //printf("ClassDeclaration::toDebug('%s')\n", cd.toChars()); assert(config.fulltypes >= CV4); - if (cd.isAnonymous()) + if (cd.classKind == ClassKind.anonymous) return /*0*/; if (typidx) // if reference already generated diff --git a/src/ddmd/todt.d b/src/ddmd/todt.d index a9ac50001b99..2d912629c4a8 100644 --- a/src/ddmd/todt.d +++ b/src/ddmd/todt.d @@ -719,7 +719,7 @@ private void membersToDt(AggregateDeclaration ad, DtBuilder dtb, { dtb.xoff(toVtblSymbol(concreteType), 0); // __vptr offset = Target.ptrsize; - if (!cd.cpp) + if (!cd.classKind == ClassKind.cpp) { dtb.size(0); // __monitor offset += Target.ptrsize; diff --git a/src/ddmd/toobj.d b/src/ddmd/toobj.d index bb88610b6218..94efd6c398d2 100644 --- a/src/ddmd/toobj.d +++ b/src/ddmd/toobj.d @@ -421,7 +421,7 @@ void toObjFile(Dsymbol ds, bool multiobj) dtb.size(0); // monitor // m_init[] - assert(cd.structsize >= 8 || (cd.cpp && cd.structsize >= 4)); + assert(cd.structsize >= 8 || (cd.classKind == ClassKind.cpp && cd.structsize >= 4)); dtb.size(cd.structsize); // size dtb.xoff(sinit, 0, TYnptr); // initializer diff --git a/test/compilable/extra-files/header2.d b/test/compilable/extra-files/header2.d index 5ef68fae4c0d..d7adc45b46d0 100644 --- a/test/compilable/extra-files/header2.d +++ b/test/compilable/extra-files/header2.d @@ -158,3 +158,15 @@ void leFoo()() sign = a == 2 ? false : sign ^ (y < 0); sign = 2 + 3 | 7 + 5; } + +// 17371 +interface LeInterface +{} +class LeClass +{ + this() + { + auto foo = new class () LeInterface {}; + } +} +const levar = new class LeClass, LeInterface {}; diff --git a/test/compilable/extra-files/header2.di b/test/compilable/extra-files/header2.di index aaf60ed8b371..239197b309b4 100644 --- a/test/compilable/extra-files/header2.di +++ b/test/compilable/extra-files/header2.di @@ -114,3 +114,20 @@ void leFoo()() sign = a == 2 ? false : sign ^ (y < 0); sign = 2 + 3 | 7 + 5; } +interface LeInterface +{ +} +class LeClass +{ + this() + { + auto foo = new class LeInterface + { + } + ; + } +} +const levar = new class LeClass, LeInterface +{ +} +; diff --git a/test/compilable/extra-files/header2i.di b/test/compilable/extra-files/header2i.di index 70f2abbe42d3..0e0026c1fa5c 100644 --- a/test/compilable/extra-files/header2i.di +++ b/test/compilable/extra-files/header2i.di @@ -216,3 +216,20 @@ void leFoo()() sign = a == 2 ? false : sign ^ (y < 0); sign = 2 + 3 | 7 + 5; } +interface LeInterface +{ +} +class LeClass +{ + this() + { + auto foo = new class LeInterface + { + } + ; + } +} +const levar = new class LeClass, LeInterface +{ +} +;