2 * Defines a `class` declaration.
4 * Specification: $(LINK2 https://dlang.org/spec/class.html, Classes)
6 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d, _dclass.d)
10 * Documentation: https://dlang.org/phobos/dmd_dclass.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dclass.d
16 import core.stdc.stdio;
17 import core.stdc.string;
21 import dmd.arraytypes;
25 import dmd.declaration;
28 import dmd.dsymbolsem;
32 import dmd.identifier;
39 /***********************************************************
41 extern (C++) struct BaseClass
43 Type type; // (before semantic processing)
46 uint offset; // 'this' pointer offset
48 // for interfaces: Array of FuncDeclaration's making up the vtbl[]
49 FuncDeclarations vtbl;
51 // if BaseClass is an interface, these
52 // are a copy of the InterfaceDeclaration.interfaces
53 BaseClass[] baseInterfaces;
55 extern (D) this(Type type)
57 //printf("BaseClass(this = %p, '%s')\n", this, type.toChars());
61 /****************************************
62 * Fill in vtbl[] for base class based on member functions of class cd.
64 * vtbl if !=NULL, fill it in
65 * newinstance !=0 means all entries must be filled in by members
66 * of cd, not members of any base classes of cd.
68 * true if any entries were filled in by members of cd (not exclusively
71 extern (C++) bool fillVtbl(ClassDeclaration cd, FuncDeclarations* vtbl, int newinstance)
75 //printf("BaseClass.fillVtbl(this='%s', cd='%s')\n", sym.toChars(), cd.toChars());
77 vtbl.setDim(sym.vtbl.dim);
79 // first entry is ClassInfo reference
80 for (size_t j = sym.vtblOffset(); j < sym.vtbl.dim; j++)
82 FuncDeclaration ifd = sym.vtbl[j].isFuncDeclaration();
84 //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd.toChars() : "null");
87 // Find corresponding function in this class
88 auto tf = ifd.type.toTypeFunction();
89 auto fd = cd.findFunc(ifd.ident, tf);
90 if (fd && !fd.isAbstract())
92 if (fd.toParent() == cd)
103 extern (D) void copyBaseInterfaces(BaseClasses* vtblInterfaces)
105 //printf("+copyBaseInterfaces(), %s\n", sym.toChars());
106 // if (baseInterfaces.length)
108 auto bc = cast(BaseClass*)mem.xcalloc(sym.interfaces.length, BaseClass.sizeof);
109 baseInterfaces = bc[0 .. sym.interfaces.length];
110 //printf("%s.copyBaseInterfaces()\n", sym.toChars());
111 for (size_t i = 0; i < baseInterfaces.length; i++)
113 BaseClass* b = &baseInterfaces[i];
114 BaseClass* b2 = sym.interfaces[i];
116 assert(b2.vtbl.dim == 0); // should not be filled yet
117 memcpy(b, b2, BaseClass.sizeof);
119 if (i) // single inheritance is i==0
120 vtblInterfaces.push(b); // only need for M.I.
121 b.copyBaseInterfaces(vtblInterfaces);
123 //printf("-copyBaseInterfaces\n");
127 enum ClassFlags : uint
134 hasGetMembers = 0x10,
141 /***********************************************************
143 extern (C++) class ClassDeclaration : AggregateDeclaration
145 extern (C++) __gshared
147 // Names found by reading object.d in druntime
148 ClassDeclaration object;
149 ClassDeclaration throwable;
150 ClassDeclaration exception;
151 ClassDeclaration errorException;
152 ClassDeclaration cpp_type_info_ptr; // Object.__cpp_type_info_ptr
155 ClassDeclaration baseClass; // NULL only if this is Object
156 FuncDeclaration staticCtor;
157 FuncDeclaration staticDtor;
158 Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[]
159 Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[]
161 // Array of BaseClass's; first is super, rest are Interface's
162 BaseClasses* baseclasses;
164 /* Slice of baseclasses[] that does not include baseClass
166 BaseClass*[] interfaces;
168 // array of base interfaces that have their own vtbl[]
169 BaseClasses* vtblInterfaces;
171 // the ClassInfo object for this ClassDeclaration
172 TypeInfoClassDeclaration vclassinfo;
174 // true if this is a COM class
177 /// true if this is a scope class
180 /// if this is a C++ class, this is the slot reserved for the virtual destructor
181 int cppDtorVtblIndex = -1;
183 /// to prevent recursive attempts
186 ThreeState isabstract;
188 /// set the progress of base classes resolving
192 * Data for a class declaration that is needed for the Objective-C
195 ObjcClassDeclaration objc;
197 Symbol* cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr
199 final extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
201 objc = ObjcClassDeclaration(this);
204 id = Identifier.generateAnonymousId("class");
208 __gshared const(char)* msg = "only object.d can define this reserved class name";
212 // Actually, this is a transfer
213 this.baseclasses = baseclasses;
216 this.baseclasses = new BaseClasses();
218 this.members = members;
220 //printf("ClassDeclaration(%s), dim = %d\n", ident.toChars(), this.baseclasses.dim);
222 // For forward references
223 type = new TypeClass(this);
225 // Look for special class names
226 if (id == Id.__sizeof || id == Id.__xalignof || id == Id._mangleof)
227 error("illegal class name");
229 // BUG: What if this is the wrong TypeInfo, i.e. it is nested?
230 if (id.toChars()[0] == 'T')
232 if (id == Id.TypeInfo)
236 Type.dtypeinfo = this;
238 if (id == Id.TypeInfo_Class)
242 Type.typeinfoclass = this;
244 if (id == Id.TypeInfo_Interface)
248 Type.typeinfointerface = this;
250 if (id == Id.TypeInfo_Struct)
254 Type.typeinfostruct = this;
256 if (id == Id.TypeInfo_Pointer)
260 Type.typeinfopointer = this;
262 if (id == Id.TypeInfo_Array)
266 Type.typeinfoarray = this;
268 if (id == Id.TypeInfo_StaticArray)
271 // Type.typeinfostaticarray.error("%s", msg);
272 Type.typeinfostaticarray = this;
274 if (id == Id.TypeInfo_AssociativeArray)
278 Type.typeinfoassociativearray = this;
280 if (id == Id.TypeInfo_Enum)
284 Type.typeinfoenum = this;
286 if (id == Id.TypeInfo_Function)
290 Type.typeinfofunction = this;
292 if (id == Id.TypeInfo_Delegate)
296 Type.typeinfodelegate = this;
298 if (id == Id.TypeInfo_Tuple)
302 Type.typeinfotypelist = this;
304 if (id == Id.TypeInfo_Const)
308 Type.typeinfoconst = this;
310 if (id == Id.TypeInfo_Invariant)
314 Type.typeinfoinvariant = this;
316 if (id == Id.TypeInfo_Shared)
320 Type.typeinfoshared = this;
322 if (id == Id.TypeInfo_Wild)
326 Type.typeinfowild = this;
328 if (id == Id.TypeInfo_Vector)
332 Type.typeinfovector = this;
343 if (id == Id.Throwable)
349 if (id == Id.Exception)
359 errorException = this;
361 if (id == Id.cpp_type_info_ptr)
365 cpp_type_info_ptr = this;
368 baseok = Baseok.none;
371 static ClassDeclaration create(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
373 return new ClassDeclaration(loc, id, baseclasses, members, inObject);
376 override const(char)* toPrettyChars(bool qualifyTypes = false)
379 return .objc.toPrettyChars(this, qualifyTypes);
381 return super.toPrettyChars(qualifyTypes);
384 override ClassDeclaration syntaxCopy(Dsymbol s)
386 //printf("ClassDeclaration.syntaxCopy('%s')\n", toChars());
387 ClassDeclaration cd =
388 s ? cast(ClassDeclaration)s
389 : new ClassDeclaration(loc, ident, null, null, false);
391 cd.storage_class |= storage_class;
393 cd.baseclasses.setDim(this.baseclasses.dim);
394 for (size_t i = 0; i < cd.baseclasses.dim; i++)
396 BaseClass* b = (*this.baseclasses)[i];
397 auto b2 = new BaseClass(b.type.syntaxCopy());
398 (*cd.baseclasses)[i] = b2;
401 ScopeDsymbol.syntaxCopy(cd);
405 override Scope* newScope(Scope* sc)
407 auto sc2 = super.newScope(sc);
410 /* This enables us to use COM objects under Linux and
411 * work with things like XPCOM
413 sc2.linkage = target.systemLinkage();
418 /*********************************************
419 * Determine if 'this' is a base class of cd.
420 * This is used to detect circular inheritance only.
422 final bool isBaseOf2(ClassDeclaration cd) pure nothrow @nogc
426 //printf("ClassDeclaration.isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
427 for (size_t i = 0; i < cd.baseclasses.dim; i++)
429 BaseClass* b = (*cd.baseclasses)[i];
430 if (b.sym == this || isBaseOf2(b.sym))
436 enum OFFSET_RUNTIME = 0x76543210;
437 enum OFFSET_FWDREF = 0x76543211;
439 /*******************************************
440 * Determine if 'this' is a base class of cd.
442 bool isBaseOf(ClassDeclaration cd, int* poffset) pure nothrow @nogc
444 //printf("ClassDeclaration.isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
449 if (this == cd.baseClass)
457 /*********************************************
458 * Determine if 'this' has complete base class information.
459 * This is used to detect forward references in covariant overloads.
461 final bool isBaseInfoComplete() const
463 return baseok >= Baseok.done;
466 override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
468 //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
469 //if (_scope) printf("%s baseok = %d\n", toChars(), baseok);
470 if (_scope && baseok < Baseok.done)
474 // must semantic on base class/interfaces
476 dsymbolSemantic(this, null);
481 if (!members || !symtab) // opaque or addMember is not yet done
483 // .stringof is always defined (but may be hidden by some other symbol)
484 if (ident != Id.stringof && !(flags & IgnoreErrors) && semanticRun < PASS.semanticdone)
485 error("is forward referenced when looking for `%s`", ident.toChars());
490 auto s = ScopeDsymbol.search(loc, ident, flags);
492 // don't search imports of base classes
493 if (flags & SearchImportsOnly)
499 // Search bases classes in depth-first, left to right order
500 foreach (b; (*baseclasses)[])
507 error("base `%s` is forward referenced", b.sym.ident.toChars());
511 import dmd.access : symbolIsVisible;
513 s = b.sym.search(loc, ident, flags);
516 else if (s == this) // happens if s is nested in this and derives from this
518 else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(this, s))
527 /************************************
528 * Search base classes in depth-first, left-to-right order for
529 * a class or interface named 'ident'.
530 * Stops at first found. Does not look for additional matches.
532 * ident = identifier to search for
534 * ClassDeclaration if found, null if not
536 final ClassDeclaration searchBase(Identifier ident)
538 foreach (b; *baseclasses)
540 auto cdb = b.type.isClassHandle();
541 if (!cdb) // https://issues.dlang.org/show_bug.cgi?id=10616
543 if (cdb.ident.equals(ident))
545 auto result = cdb.searchBase(ident);
552 final override void finalizeSize()
554 assert(sizeok != Sizeok.done);
556 // Set the offsets of the fields and determine the size of the class
559 assert(baseClass.sizeok == Sizeok.done);
561 alignsize = baseClass.alignsize;
562 if (classKind == ClassKind.cpp)
563 structsize = target.cpp.derivedClassOffset(baseClass);
565 structsize = baseClass.structsize;
567 else if (classKind == ClassKind.objc)
568 structsize = 0; // no hidden member for an Objective-C class
569 else if (isInterfaceDeclaration())
571 if (interfaces.length == 0)
573 alignsize = target.ptrsize;
574 structsize = target.ptrsize; // allow room for __vptr
579 alignsize = target.ptrsize;
580 structsize = target.ptrsize; // allow room for __vptr
582 structsize += target.ptrsize; // allow room for __monitor
585 //printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
586 size_t bi = 0; // index into vtblInterfaces[]
589 * Runs through the inheritance graph to set the BaseClass.offset fields.
590 * Recursive in order to account for the size of the interface classes, if they are
591 * more than just interfaces.
593 * cd = interface to look at
594 * baseOffset = offset of where cd will be placed
596 * subset of instantiated size used by cd for interfaces
598 uint membersPlace(ClassDeclaration cd, uint baseOffset)
600 //printf(" membersPlace(%s, %d)\n", cd.toChars(), baseOffset);
601 uint offset = baseOffset;
603 foreach (BaseClass* b; cd.interfaces)
605 if (b.sym.sizeok != Sizeok.done)
606 b.sym.finalizeSize();
607 assert(b.sym.sizeok == Sizeok.done);
609 if (!b.sym.alignsize)
610 b.sym.alignsize = target.ptrsize;
611 alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, &offset);
612 assert(bi < vtblInterfaces.dim);
614 BaseClass* bv = (*vtblInterfaces)[bi];
615 if (b.sym.interfaces.length == 0)
617 //printf("\tvtblInterfaces[%d] b=%p b.sym = %s, offset = %d\n", bi, bv, bv.sym.toChars(), offset);
620 // All the base interfaces down the left side share the same offset
621 for (BaseClass* b2 = bv; b2.baseInterfaces.length; )
623 b2 = &b2.baseInterfaces[0];
625 //printf("\tvtblInterfaces[%d] b=%p sym = %s, offset = %d\n", bi, b2, b2.sym.toChars(), b2.offset);
628 membersPlace(b.sym, offset);
629 //printf(" %s size = %d\n", b.sym.toChars(), b.sym.structsize);
630 offset += b.sym.structsize;
631 if (alignsize < b.sym.alignsize)
632 alignsize = b.sym.alignsize;
634 return offset - baseOffset;
637 structsize += membersPlace(this, structsize);
639 if (isInterfaceDeclaration())
641 sizeok = Sizeok.done;
645 // FIXME: Currently setFieldOffset functions need to increase fields
646 // to calculate each variable offsets. It can be improved later.
649 FieldState fieldState;
650 fieldState.offset = structsize;
651 foreach (s; *members)
653 s.setFieldOffset(this, fieldState, false);
656 sizeok = Sizeok.done;
658 // Calculate fields[i].overlapped
659 checkOverlappedFields();
663 * Returns: true if there's a __monitor field
665 final bool hasMonitor()
667 return classKind == ClassKind.d;
670 final bool isFuncHidden(FuncDeclaration fd)
672 //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars());
673 Dsymbol s = search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors);
676 //printf("not found\n");
677 /* Because, due to a hack, if there are multiple definitions
678 * of fd.ident, NULL is returned.
683 if (auto os = s.isOverloadSet())
687 auto fm = sm.isFuncDeclaration();
688 if (overloadApply(fm, s => fd == s.isFuncDeclaration()))
695 auto f = s.isFuncDeclaration();
696 //printf("%s fdstart = %p\n", s.kind(), fdstart);
697 if (overloadApply(f, s => fd == s.isFuncDeclaration()))
699 return !fd.parent.isTemplateMixin();
704 * Find virtual function matching identifier and type.
705 * Used to build virtual function tables for interface implementations.
707 * ident = function's identifier
708 * tf = function's type
710 * function symbol if found, null if not
712 * prints error message if more than one match
714 final FuncDeclaration findFunc(Identifier ident, TypeFunction tf)
716 //printf("ClassDeclaration.findFunc(%s, %s) %s\n", ident.toChars(), tf.toChars(), toChars());
717 FuncDeclaration fdmatch = null;
718 FuncDeclaration fdambig = null;
720 void updateBestMatch(FuncDeclaration fd)
724 //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch.toChars(), fdmatch.type.toChars(), fdmatch.loc.toChars());
727 void searchVtbl(ref Dsymbols vtbl)
729 bool seenInterfaceVirtual;
732 auto fd = s.isFuncDeclaration();
736 // the first entry might be a ClassInfo
737 //printf("\t[%d] = %s\n", i, fd.toChars());
738 if (ident != fd.ident || fd.type.covariant(tf) != Covariant.yes)
740 //printf("\t\t%d\n", fd.type.covariant(tf));
744 //printf("fd.parent.isClassDeclaration() = %p\n", fd.parent.isClassDeclaration());
753 /* Functions overriding interface functions for extern(C++) with VC++
754 * are not in the normal vtbl, but in vtblFinal. If the implementation
755 * is again overridden in a child class, both would be found here.
756 * The function in the child class should override the function
757 * in the base class, which is done here, because searchVtbl is first
758 * called for the child class. Checking seenInterfaceVirtual makes
759 * sure, that the compared functions are not in the same vtbl.
761 if (fd.interfaceVirtual &&
762 fd.interfaceVirtual is fdmatch.interfaceVirtual &&
763 !seenInterfaceVirtual &&
764 fdmatch.type.covariant(fd.type) == Covariant.yes)
766 seenInterfaceVirtual = true;
771 // Function type matching: exact > covariant
772 MATCH m1 = tf.equals(fd.type) ? MATCH.exact : MATCH.nomatch;
773 MATCH m2 = tf.equals(fdmatch.type) ? MATCH.exact : MATCH.nomatch;
783 MATCH m1 = (tf.mod == fd.type.mod) ? MATCH.exact : MATCH.nomatch;
784 MATCH m2 = (tf.mod == fdmatch.type.mod) ? MATCH.exact : MATCH.nomatch;
794 // The way of definition: non-mixin > mixin
795 MATCH m1 = fd.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
796 MATCH m2 = fdmatch.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
807 //printf("Lambig fdambig = %s %s [%s]\n", fdambig.toChars(), fdambig.type.toChars(), fdambig.loc.toChars());
812 for (auto cd = this; cd; cd = cd.baseClass)
814 searchVtbl(cd.vtblFinal);
818 error("ambiguous virtual function `%s`", fdambig.toChars());
823 /****************************************
825 final bool isCOMclass() const
830 bool isCOMinterface() const
835 final bool isCPPclass() const
837 return classKind == ClassKind.cpp;
840 bool isCPPinterface() const
845 /****************************************
847 final bool isAbstract()
850 if (isabstract != ThreeState.none)
851 return isabstract == ThreeState.yes;
853 if (log) printf("isAbstract(%s)\n", toChars());
855 bool no() { if (log) printf("no\n"); isabstract = ThreeState.no; return false; }
856 bool yes() { if (log) printf("yes\n"); isabstract = ThreeState.yes; return true; }
858 if (storage_class & STC.abstract_ || _scope && _scope.stc & STC.abstract_)
864 /* https://issues.dlang.org/show_bug.cgi?id=11169
865 * Resolve forward references to all class member functions,
866 * and determine whether this class is abstract.
868 static int func(Dsymbol s)
870 auto fd = s.isFuncDeclaration();
873 if (fd.storage_class & STC.static_)
881 for (size_t i = 0; i < members.dim; i++)
883 auto s = (*members)[i];
890 /* If the base class is not abstract, then this class cannot
893 if (!isInterfaceDeclaration() && (!baseClass || !baseClass.isAbstract()))
896 /* If any abstract functions are inherited, but not overridden,
897 * then the class is abstract. Do this by checking the vtbl[].
898 * Need to do semantic() on class to fill the vtbl[].
900 this.dsymbolSemantic(null);
902 /* The next line should work, but does not because when ClassDeclaration.dsymbolSemantic()
903 * is called recursively it can set PASS.semanticdone without finishing it.
905 //if (semanticRun < PASS.semanticdone)
907 /* Could not complete semantic(). Try running semantic() on
908 * each of the virtual functions,
909 * which will fill in the vtbl[] overrides.
911 static int virtualSemantic(Dsymbol s)
913 auto fd = s.isFuncDeclaration();
914 if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration())
915 fd.dsymbolSemantic(null);
919 for (size_t i = 0; i < members.dim; i++)
921 auto s = (*members)[i];
922 s.apply(&virtualSemantic);
926 /* Finally, check the vtbl[]
928 foreach (i; 1 .. vtbl.dim)
930 auto fd = vtbl[i].isFuncDeclaration();
931 //if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd.loc.toChars(), fd.toPrettyChars());
932 if (!fd || fd.isAbstract())
941 /****************************************
942 * Determine if slot 0 of the vtbl[] is reserved for something else.
943 * For class objects, yes, this is where the classinfo ptr goes.
944 * For COM interfaces, no.
945 * For non-COM interfaces, yes, this is where the Interface ptr goes.
947 * 0 vtbl[0] is first virtual function pointer
948 * 1 vtbl[0] is classinfo/interfaceinfo pointer
950 int vtblOffset() const
952 return classKind == ClassKind.cpp ? 0 : 1;
955 /****************************************
957 override const(char)* kind() const
962 /****************************************
964 override final void addLocalClass(ClassDeclarations* aclasses)
966 if (classKind != ClassKind.objc)
970 override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
972 .objc.addSymbols(this, classes, categories);
978 final Dsymbol vtblSymbol()
982 auto vtype = Type.tvoidptr.immutableOf().sarrayOf(vtbl.dim);
983 auto var = new VarDeclaration(loc, vtype, Identifier.idPool("__vtbl"), null, STC.immutable_ | STC.static_);
984 var.addMember(null, this);
986 var.linkage = LINK.d;
987 var.semanticRun = PASS.semanticdone; // no more semantic wanted
993 override final inout(ClassDeclaration) isClassDeclaration() inout @nogc nothrow pure @safe
998 override void accept(Visitor v)
1004 /***********************************************************
1006 extern (C++) final class InterfaceDeclaration : ClassDeclaration
1008 extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses)
1010 super(loc, id, baseclasses, null, false);
1011 if (id == Id.IUnknown) // IUnknown is the root of all COM interfaces
1014 classKind = ClassKind.cpp; // IUnknown is also a C++ interface
1018 override InterfaceDeclaration syntaxCopy(Dsymbol s)
1020 InterfaceDeclaration id =
1021 s ? cast(InterfaceDeclaration)s
1022 : new InterfaceDeclaration(loc, ident, null);
1023 ClassDeclaration.syntaxCopy(id);
1028 override Scope* newScope(Scope* sc)
1030 auto sc2 = super.newScope(sc);
1032 sc2.linkage = LINK.windows;
1033 else if (classKind == ClassKind.cpp)
1034 sc2.linkage = LINK.cpp;
1035 else if (classKind == ClassKind.objc)
1036 sc2.linkage = LINK.objc;
1040 /*******************************************
1041 * Determine if 'this' is a base class of cd.
1042 * (Actually, if it is an interface supported by cd)
1044 * *poffset offset to start of class
1045 * OFFSET_RUNTIME must determine offset at runtime
1050 override bool isBaseOf(ClassDeclaration cd, int* poffset) pure nothrow @nogc
1052 //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars());
1054 foreach (b; cd.interfaces)
1056 //printf("\tX base %s\n", b.sym.toChars());
1059 //printf("\tfound at offset %d\n", b.offset);
1062 // don't return incorrect offsets
1063 // https://issues.dlang.org/show_bug.cgi?id=16980
1064 *poffset = cd.sizeok == Sizeok.done ? b.offset : OFFSET_FWDREF;
1066 // printf("\tfound at offset %d\n", b.offset);
1069 if (baseClassImplementsInterface(this, b, poffset))
1072 if (cd.baseClass && isBaseOf(cd.baseClass, poffset))
1080 /*******************************************
1082 override const(char)* kind() const
1087 /****************************************
1088 * Determine if slot 0 of the vtbl[] is reserved for something else.
1089 * For class objects, yes, this is where the ClassInfo ptr goes.
1090 * For COM interfaces, no.
1091 * For non-COM interfaces, yes, this is where the Interface ptr goes.
1093 override int vtblOffset() const
1095 if (isCOMinterface() || isCPPinterface())
1100 override bool isCPPinterface() const
1102 return classKind == ClassKind.cpp;
1105 override bool isCOMinterface() const
1110 override inout(InterfaceDeclaration) isInterfaceDeclaration() inout
1115 override void accept(Visitor v)
1122 * Returns whether `bc` implements `id`, including indirectly (`bc` implements an interfaces
1123 * that inherits from `id`)
1126 * id = the interface
1127 * bc = the base class
1128 * poffset = out parameter, offset of the interface in an object
1131 * true if the `bc` implements `id`, false otherwise
1133 private bool baseClassImplementsInterface(InterfaceDeclaration id, BaseClass* bc, int* poffset) pure nothrow @nogc
1135 //printf("%s.InterfaceDeclaration.isBaseOf(bc = '%s')\n", id.toChars(), bc.sym.toChars());
1136 for (size_t j = 0; j < bc.baseInterfaces.length; j++)
1138 BaseClass* b = &bc.baseInterfaces[j];
1139 //printf("\tY base %s\n", b.sym.toChars());
1142 //printf("\tfound at offset %d\n", b.offset);
1145 *poffset = b.offset;
1149 if (baseClassImplementsInterface(id, b, poffset))