1 /**
2  * Defines a `class` declaration.
3  *
4  * Specification: $(LINK2 https://dlang.org/spec/class.html, Classes)
5  *
6  * Copyright:   Copyright (C) 1999-2023 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
12  */
13 
14 module dmd.dclass;
15 
16 import core.stdc.stdio;
17 import core.stdc.string;
18 
19 import dmd.aggregate;
20 import dmd.apply;
21 import dmd.arraytypes;
22 import dmd.astenums;
23 import dmd.attrib;
24 import dmd.gluelayer;
25 import dmd.declaration;
26 import dmd.dscope;
27 import dmd.dsymbol;
28 import dmd.dsymbolsem;
29 import dmd.func;
30 import dmd.globals;
31 import dmd.id;
32 import dmd.identifier;
33 import dmd.location;
34 import dmd.mtype;
35 import dmd.objc;
36 import dmd.root.rmem;
37 import dmd.target;
38 import dmd.visitor;
39 
40 /***********************************************************
41  */
42 extern (C++) struct BaseClass
43 {
44     Type type;          // (before semantic processing)
45 
46     ClassDeclaration sym;
47     uint offset;        // 'this' pointer offset
48 
49     // for interfaces: Array of FuncDeclaration's making up the vtbl[]
50     FuncDeclarations vtbl;
51 
52     // if BaseClass is an interface, these
53     // are a copy of the InterfaceDeclaration.interfaces
54     BaseClass[] baseInterfaces;
55 
56     extern (D) this(Type type)
57     {
58         //printf("BaseClass(this = %p, '%s')\n", this, type.toChars());
59         this.type = type;
60     }
61 
62     /****************************************
63      * Fill in vtbl[] for base class based on member functions of class cd.
64      * Input:
65      *      vtbl            if !=NULL, fill it in
66      *      newinstance     !=0 means all entries must be filled in by members
67      *                      of cd, not members of any base classes of cd.
68      * Returns:
69      *      true if any entries were filled in by members of cd (not exclusively
70      *      by base classes)
71      */
72     extern (C++) bool fillVtbl(ClassDeclaration cd, FuncDeclarations* vtbl, int newinstance)
73     {
74         bool result = false;
75 
76         //printf("BaseClass.fillVtbl(this='%s', cd='%s')\n", sym.toChars(), cd.toChars());
77         if (vtbl)
78             vtbl.setDim(sym.vtbl.length);
79 
80         // first entry is ClassInfo reference
81         for (size_t j = sym.vtblOffset(); j < sym.vtbl.length; j++)
82         {
83             FuncDeclaration ifd = sym.vtbl[j].isFuncDeclaration();
84 
85             //printf("        vtbl[%d] is '%s'\n", j, ifd ? ifd.toChars() : "null");
86             assert(ifd);
87 
88             // Find corresponding function in this class
89             auto tf = ifd.type.toTypeFunction();
90             auto fd = cd.findFunc(ifd.ident, tf);
91             if (fd && !fd.isAbstract())
92             {
93                 if (fd.toParent() == cd)
94                     result = true;
95             }
96             else
97                 fd = null;
98             if (vtbl)
99                 (*vtbl)[j] = fd;
100         }
101         return result;
102     }
103 
104     extern (D) void copyBaseInterfaces(BaseClasses* vtblInterfaces)
105     {
106         //printf("+copyBaseInterfaces(), %s\n", sym.toChars());
107         //    if (baseInterfaces.length)
108         //      return;
109         auto bc = cast(BaseClass*)mem.xcalloc(sym.interfaces.length, BaseClass.sizeof);
110         baseInterfaces = bc[0 .. sym.interfaces.length];
111         //printf("%s.copyBaseInterfaces()\n", sym.toChars());
112         for (size_t i = 0; i < baseInterfaces.length; i++)
113         {
114             BaseClass* b = &baseInterfaces[i];
115             BaseClass* b2 = sym.interfaces[i];
116 
117             assert(b2.vtbl.length == 0); // should not be filled yet
118             memcpy(b, b2, BaseClass.sizeof);
119 
120             if (i) // single inheritance is i==0
121                 vtblInterfaces.push(b); // only need for M.I.
122             b.copyBaseInterfaces(vtblInterfaces);
123         }
124         //printf("-copyBaseInterfaces\n");
125     }
126 }
127 
128 enum ClassFlags : uint
129 {
130     none          = 0x0,
131     isCOMclass    = 0x1,
132     noPointers    = 0x2,
133     hasOffTi      = 0x4,
134     hasCtor       = 0x8,
135     hasGetMembers = 0x10,
136     hasTypeInfo   = 0x20,
137     isAbstract    = 0x40,
138     isCPPclass    = 0x80,
139     hasDtor       = 0x100,
140 }
141 
142 /***********************************************************
143  */
144 extern (C++) class ClassDeclaration : AggregateDeclaration
145 {
146     extern (C++) __gshared
147     {
148         // Names found by reading object.d in druntime
149         ClassDeclaration object;
150         ClassDeclaration throwable;
151         ClassDeclaration exception;
152         ClassDeclaration errorException;
153         ClassDeclaration cpp_type_info_ptr;   // Object.__cpp_type_info_ptr
154     }
155 
156     ClassDeclaration baseClass; // NULL only if this is Object
157     FuncDeclaration staticCtor;
158     FuncDeclaration staticDtor;
159     Dsymbols vtbl;              // Array of FuncDeclaration's making up the vtbl[]
160     Dsymbols vtblFinal;         // More FuncDeclaration's that aren't in vtbl[]
161 
162     // Array of BaseClass's; first is super, rest are Interface's
163     BaseClasses* baseclasses;
164 
165     /* Slice of baseclasses[] that does not include baseClass
166      */
167     BaseClass*[] interfaces;
168 
169     // array of base interfaces that have their own vtbl[]
170     BaseClasses* vtblInterfaces;
171 
172     // the ClassInfo object for this ClassDeclaration
173     TypeInfoClassDeclaration vclassinfo;
174 
175     // true if this is a COM class
176     bool com;
177 
178     /// true if this is a scope class
179     bool stack;
180 
181     /// if this is a C++ class, this is the slot reserved for the virtual destructor
182     int cppDtorVtblIndex = -1;
183 
184     /// to prevent recursive attempts
185     private bool inuse;
186 
187     ThreeState isabstract;
188 
189     /// set the progress of base classes resolving
190     Baseok baseok;
191 
192     /**
193      * Data for a class declaration that is needed for the Objective-C
194      * integration.
195      */
196     ObjcClassDeclaration objc;
197 
198     Symbol* cpp_type_info_ptr_sym;      // cached instance of class Id.cpp_type_info_ptr
199 
200     final extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
201     {
202         objc = ObjcClassDeclaration(this);
203 
204         if (!id)
205             id = Identifier.generateAnonymousId("class");
206 
207         super(loc, id);
208 
209         static immutable msg = "only object.d can define this reserved class name";
210 
211         if (baseclasses)
212         {
213             // Actually, this is a transfer
214             this.baseclasses = baseclasses;
215         }
216         else
217             this.baseclasses = new BaseClasses();
218 
219         this.members = members;
220 
221         //printf("ClassDeclaration(%s), dim = %d\n", ident.toChars(), this.baseclasses.length);
222 
223         // For forward references
224         type = new TypeClass(this);
225 
226         // Look for special class names
227         if (id == Id.__sizeof || id == Id.__xalignof || id == Id._mangleof)
228             error("illegal class name");
229 
230         // BUG: What if this is the wrong TypeInfo, i.e. it is nested?
231         if (id.toChars()[0] == 'T')
232         {
233             if (id == Id.TypeInfo)
234             {
235                 if (!inObject)
236                     error("%s", msg.ptr);
237                 Type.dtypeinfo = this;
238             }
239             if (id == Id.TypeInfo_Class)
240             {
241                 if (!inObject)
242                     error("%s", msg.ptr);
243                 Type.typeinfoclass = this;
244             }
245             if (id == Id.TypeInfo_Interface)
246             {
247                 if (!inObject)
248                     error("%s", msg.ptr);
249                 Type.typeinfointerface = this;
250             }
251             if (id == Id.TypeInfo_Struct)
252             {
253                 if (!inObject)
254                     error("%s", msg.ptr);
255                 Type.typeinfostruct = this;
256             }
257             if (id == Id.TypeInfo_Pointer)
258             {
259                 if (!inObject)
260                     error("%s", msg.ptr);
261                 Type.typeinfopointer = this;
262             }
263             if (id == Id.TypeInfo_Array)
264             {
265                 if (!inObject)
266                     error("%s", msg.ptr);
267                 Type.typeinfoarray = this;
268             }
269             if (id == Id.TypeInfo_StaticArray)
270             {
271                 //if (!inObject)
272                 //    Type.typeinfostaticarray.error("%s", msg);
273                 Type.typeinfostaticarray = this;
274             }
275             if (id == Id.TypeInfo_AssociativeArray)
276             {
277                 if (!inObject)
278                     error("%s", msg.ptr);
279                 Type.typeinfoassociativearray = this;
280             }
281             if (id == Id.TypeInfo_Enum)
282             {
283                 if (!inObject)
284                     error("%s", msg.ptr);
285                 Type.typeinfoenum = this;
286             }
287             if (id == Id.TypeInfo_Function)
288             {
289                 if (!inObject)
290                     error("%s", msg.ptr);
291                 Type.typeinfofunction = this;
292             }
293             if (id == Id.TypeInfo_Delegate)
294             {
295                 if (!inObject)
296                     error("%s", msg.ptr);
297                 Type.typeinfodelegate = this;
298             }
299             if (id == Id.TypeInfo_Tuple)
300             {
301                 if (!inObject)
302                     error("%s", msg.ptr);
303                 Type.typeinfotypelist = this;
304             }
305             if (id == Id.TypeInfo_Const)
306             {
307                 if (!inObject)
308                     error("%s", msg.ptr);
309                 Type.typeinfoconst = this;
310             }
311             if (id == Id.TypeInfo_Invariant)
312             {
313                 if (!inObject)
314                     error("%s", msg.ptr);
315                 Type.typeinfoinvariant = this;
316             }
317             if (id == Id.TypeInfo_Shared)
318             {
319                 if (!inObject)
320                     error("%s", msg.ptr);
321                 Type.typeinfoshared = this;
322             }
323             if (id == Id.TypeInfo_Wild)
324             {
325                 if (!inObject)
326                     error("%s", msg.ptr);
327                 Type.typeinfowild = this;
328             }
329             if (id == Id.TypeInfo_Vector)
330             {
331                 if (!inObject)
332                     error("%s", msg.ptr);
333                 Type.typeinfovector = this;
334             }
335         }
336 
337         if (id == Id.Object)
338         {
339             if (!inObject)
340                 error("%s", msg.ptr);
341             object = this;
342         }
343 
344         if (id == Id.Throwable)
345         {
346             if (!inObject)
347                 error("%s", msg.ptr);
348             throwable = this;
349         }
350         if (id == Id.Exception)
351         {
352             if (!inObject)
353                 error("%s", msg.ptr);
354             exception = this;
355         }
356         if (id == Id.Error)
357         {
358             if (!inObject)
359                 error("%s", msg.ptr);
360             errorException = this;
361         }
362         if (id == Id.cpp_type_info_ptr)
363         {
364             if (!inObject)
365                 error("%s", msg.ptr);
366             cpp_type_info_ptr = this;
367         }
368 
369         baseok = Baseok.none;
370     }
371 
372     static ClassDeclaration create(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
373     {
374         return new ClassDeclaration(loc, id, baseclasses, members, inObject);
375     }
376 
377     override const(char)* toPrettyChars(bool qualifyTypes = false)
378     {
379         if (objc.isMeta)
380             return .objc.toPrettyChars(this, qualifyTypes);
381 
382         return super.toPrettyChars(qualifyTypes);
383     }
384 
385     override ClassDeclaration syntaxCopy(Dsymbol s)
386     {
387         //printf("ClassDeclaration.syntaxCopy('%s')\n", toChars());
388         ClassDeclaration cd =
389             s ? cast(ClassDeclaration)s
390               : new ClassDeclaration(loc, ident, null, null, false);
391 
392         cd.storage_class |= storage_class;
393 
394         cd.baseclasses.setDim(this.baseclasses.length);
395         for (size_t i = 0; i < cd.baseclasses.length; i++)
396         {
397             BaseClass* b = (*this.baseclasses)[i];
398             auto b2 = new BaseClass(b.type.syntaxCopy());
399             (*cd.baseclasses)[i] = b2;
400         }
401 
402         ScopeDsymbol.syntaxCopy(cd);
403         return cd;
404     }
405 
406     override Scope* newScope(Scope* sc)
407     {
408         auto sc2 = super.newScope(sc);
409         if (isCOMclass())
410         {
411             /* This enables us to use COM objects under Linux and
412              * work with things like XPCOM
413              */
414             sc2.linkage = target.systemLinkage();
415         }
416         return sc2;
417     }
418 
419     /*********************************************
420      * Determine if 'this' is a base class of cd.
421      * This is used to detect circular inheritance only.
422      */
423     final bool isBaseOf2(ClassDeclaration cd) pure nothrow @nogc
424     {
425         if (!cd)
426             return false;
427         //printf("ClassDeclaration.isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
428         for (size_t i = 0; i < cd.baseclasses.length; i++)
429         {
430             BaseClass* b = (*cd.baseclasses)[i];
431             if (b.sym == this || isBaseOf2(b.sym))
432                 return true;
433         }
434         return false;
435     }
436 
437     enum OFFSET_RUNTIME = 0x76543210;
438     enum OFFSET_FWDREF = 0x76543211;
439 
440     /*******************************************
441      * Determine if 'this' is a base class of cd.
442      */
443     bool isBaseOf(ClassDeclaration cd, int* poffset) pure nothrow @nogc
444     {
445         //printf("ClassDeclaration.isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
446         if (poffset)
447             *poffset = 0;
448         while (cd)
449         {
450             assert(cd.baseClass || cd.semanticRun >= PASS.semanticdone || cd.isInterfaceDeclaration());
451             if (this == cd.baseClass)
452                 return true;
453 
454             cd = cd.baseClass;
455         }
456         return false;
457     }
458 
459     /*********************************************
460      * Determine if 'this' has complete base class information.
461      * This is used to detect forward references in covariant overloads.
462      */
463     final bool isBaseInfoComplete() const
464     {
465         return baseok >= Baseok.done;
466     }
467 
468     override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
469     {
470         //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
471         //if (_scope) printf("%s baseok = %d\n", toChars(), baseok);
472         if (_scope && baseok < Baseok.semanticdone)
473         {
474             if (!inuse)
475             {
476                 // must semantic on base class/interfaces
477                 inuse = true;
478                 dsymbolSemantic(this, null);
479                 inuse = false;
480             }
481         }
482 
483         if (!members || !symtab) // opaque or addMember is not yet done
484         {
485             // .stringof is always defined (but may be hidden by some other symbol)
486             if (ident != Id.stringof && !(flags & IgnoreErrors) && semanticRun < PASS.semanticdone)
487                 error("is forward referenced when looking for `%s`", ident.toChars());
488             //*(char*)0=0;
489             return null;
490         }
491 
492         auto s = ScopeDsymbol.search(loc, ident, flags);
493 
494         // don't search imports of base classes
495         if (flags & SearchImportsOnly)
496             return s;
497 
498         if (s)
499             return s;
500 
501         // Search bases classes in depth-first, left to right order
502         foreach (b; (*baseclasses)[])
503         {
504             if (!b.sym)
505                 continue;
506 
507             if (!b.sym.symtab)
508             {
509                 error("base `%s` is forward referenced", b.sym.ident.toChars());
510                 continue;
511             }
512 
513             import dmd.access : symbolIsVisible;
514 
515             s = b.sym.search(loc, ident, flags);
516             if (!s)
517                 continue;
518             else if (s == this) // happens if s is nested in this and derives from this
519                 s = null;
520             else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(this, s))
521                 s = null;
522             else
523                 break;
524         }
525 
526         return s;
527     }
528 
529     /************************************
530      * Search base classes in depth-first, left-to-right order for
531      * a class or interface named 'ident'.
532      * Stops at first found. Does not look for additional matches.
533      * Params:
534      *  ident = identifier to search for
535      * Returns:
536      *  ClassDeclaration if found, null if not
537      */
538     final ClassDeclaration searchBase(Identifier ident)
539     {
540         foreach (b; *baseclasses)
541         {
542             auto cdb = b.type.isClassHandle();
543             if (!cdb) // https://issues.dlang.org/show_bug.cgi?id=10616
544                 return null;
545             if (cdb.ident.equals(ident))
546                 return cdb;
547             auto result = cdb.searchBase(ident);
548             if (result)
549                 return result;
550         }
551         return null;
552     }
553 
554     final override void finalizeSize()
555     {
556         assert(sizeok != Sizeok.done);
557 
558         // Set the offsets of the fields and determine the size of the class
559         if (baseClass)
560         {
561             assert(baseClass.sizeok == Sizeok.done);
562 
563             alignsize = baseClass.alignsize;
564             if (classKind == ClassKind.cpp)
565                 structsize = target.cpp.derivedClassOffset(baseClass);
566             else
567                 structsize = baseClass.structsize;
568         }
569         else if (classKind == ClassKind.objc)
570             structsize = 0; // no hidden member for an Objective-C class
571         else if (isInterfaceDeclaration())
572         {
573             if (interfaces.length == 0)
574             {
575                 alignsize = target.ptrsize;
576                 structsize = target.ptrsize;      // allow room for __vptr
577             }
578         }
579         else
580         {
581             alignsize = target.ptrsize;
582             structsize = target.ptrsize;      // allow room for __vptr
583             if (hasMonitor())
584                 structsize += target.ptrsize; // allow room for __monitor
585         }
586 
587         //printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
588         size_t bi = 0;                  // index into vtblInterfaces[]
589 
590         /****
591          * Runs through the inheritance graph to set the BaseClass.offset fields.
592          * Recursive in order to account for the size of the interface classes, if they are
593          * more than just interfaces.
594          * Params:
595          *      cd = interface to look at
596          *      baseOffset = offset of where cd will be placed
597          * Returns:
598          *      subset of instantiated size used by cd for interfaces
599          */
600         uint membersPlace(ClassDeclaration cd, uint baseOffset)
601         {
602             //printf("    membersPlace(%s, %d)\n", cd.toChars(), baseOffset);
603             uint offset = baseOffset;
604 
605             foreach (BaseClass* b; cd.interfaces)
606             {
607                 if (b.sym.sizeok != Sizeok.done)
608                     b.sym.finalizeSize();
609                 assert(b.sym.sizeok == Sizeok.done);
610 
611                 if (!b.sym.alignsize)
612                     b.sym.alignsize = target.ptrsize;
613                 alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, &offset);
614                 assert(bi < vtblInterfaces.length);
615 
616                 BaseClass* bv = (*vtblInterfaces)[bi];
617                 if (b.sym.interfaces.length == 0)
618                 {
619                     //printf("\tvtblInterfaces[%d] b=%p b.sym = %s, offset = %d\n", bi, bv, bv.sym.toChars(), offset);
620                     bv.offset = offset;
621                     ++bi;
622                     // All the base interfaces down the left side share the same offset
623                     for (BaseClass* b2 = bv; b2.baseInterfaces.length; )
624                     {
625                         b2 = &b2.baseInterfaces[0];
626                         b2.offset = offset;
627                         //printf("\tvtblInterfaces[%d] b=%p   sym = %s, offset = %d\n", bi, b2, b2.sym.toChars(), b2.offset);
628                     }
629                 }
630                 membersPlace(b.sym, offset);
631                 //printf(" %s size = %d\n", b.sym.toChars(), b.sym.structsize);
632                 offset += b.sym.structsize;
633                 if (alignsize < b.sym.alignsize)
634                     alignsize = b.sym.alignsize;
635             }
636             return offset - baseOffset;
637         }
638 
639         structsize += membersPlace(this, structsize);
640 
641         if (isInterfaceDeclaration())
642         {
643             sizeok = Sizeok.done;
644             return;
645         }
646 
647         // FIXME: Currently setFieldOffset functions need to increase fields
648         // to calculate each variable offsets. It can be improved later.
649         fields.setDim(0);
650 
651         FieldState fieldState;
652         fieldState.offset = structsize;
653         foreach (s; *members)
654         {
655             s.setFieldOffset(this, fieldState, false);
656         }
657 
658         sizeok = Sizeok.done;
659 
660         // Calculate fields[i].overlapped
661         checkOverlappedFields();
662     }
663 
664     /**************
665      * Returns: true if there's a __monitor field
666      */
667     final bool hasMonitor()
668     {
669         return classKind == ClassKind.d;
670     }
671 
672     final bool isFuncHidden(FuncDeclaration fd)
673     {
674         //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars());
675         Dsymbol s = search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors);
676         if (!s)
677         {
678             //printf("not found\n");
679             /* Because, due to a hack, if there are multiple definitions
680              * of fd.ident, NULL is returned.
681              */
682             return false;
683         }
684         s = s.toAlias();
685         if (auto os = s.isOverloadSet())
686         {
687             foreach (sm; os.a)
688             {
689                 auto fm = sm.isFuncDeclaration();
690                 if (overloadApply(fm, s => fd == s.isFuncDeclaration()))
691                     return false;
692             }
693             return true;
694         }
695         else
696         {
697             auto f = s.isFuncDeclaration();
698             //printf("%s fdstart = %p\n", s.kind(), fdstart);
699             if (overloadApply(f, s => fd == s.isFuncDeclaration()))
700                 return false;
701             return !fd.parent.isTemplateMixin();
702         }
703     }
704 
705     /****************
706      * Find virtual function matching identifier and type.
707      * Used to build virtual function tables for interface implementations.
708      * Params:
709      *  ident = function's identifier
710      *  tf = function's type
711      * Returns:
712      *  function symbol if found, null if not
713      * Errors:
714      *  prints error message if more than one match
715      */
716     final FuncDeclaration findFunc(Identifier ident, TypeFunction tf)
717     {
718         //printf("ClassDeclaration.findFunc(%s, %s) %s\n", ident.toChars(), tf.toChars(), toChars());
719         FuncDeclaration fdmatch = null;
720         FuncDeclaration fdambig = null;
721 
722         void updateBestMatch(FuncDeclaration fd)
723         {
724             fdmatch = fd;
725             fdambig = null;
726             //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch.toChars(), fdmatch.type.toChars(), fdmatch.loc.toChars());
727         }
728 
729         void searchVtbl(ref Dsymbols vtbl)
730         {
731             bool seenInterfaceVirtual;
732             foreach (s; vtbl)
733             {
734                 auto fd = s.isFuncDeclaration();
735                 if (!fd)
736                     continue;
737 
738                 // the first entry might be a ClassInfo
739                 //printf("\t[%d] = %s\n", i, fd.toChars());
740                 if (ident != fd.ident || fd.type.covariant(tf) != Covariant.yes)
741                 {
742                     //printf("\t\t%d\n", fd.type.covariant(tf));
743                     continue;
744                 }
745 
746                 //printf("fd.parent.isClassDeclaration() = %p\n", fd.parent.isClassDeclaration());
747                 if (!fdmatch)
748                 {
749                     updateBestMatch(fd);
750                     continue;
751                 }
752                 if (fd == fdmatch)
753                     continue;
754 
755                 /* Functions overriding interface functions for extern(C++) with VC++
756                  * are not in the normal vtbl, but in vtblFinal. If the implementation
757                  * is again overridden in a child class, both would be found here.
758                  * The function in the child class should override the function
759                  * in the base class, which is done here, because searchVtbl is first
760                  * called for the child class. Checking seenInterfaceVirtual makes
761                  * sure, that the compared functions are not in the same vtbl.
762                  */
763                 if (fd.interfaceVirtual &&
764                     fd.interfaceVirtual is fdmatch.interfaceVirtual &&
765                     !seenInterfaceVirtual &&
766                     fdmatch.type.covariant(fd.type) == Covariant.yes)
767                 {
768                     seenInterfaceVirtual = true;
769                     continue;
770                 }
771 
772                 {
773                 // Function type matching: exact > covariant
774                 MATCH m1 = tf.equals(fd.type) ? MATCH.exact : MATCH.nomatch;
775                 MATCH m2 = tf.equals(fdmatch.type) ? MATCH.exact : MATCH.nomatch;
776                 if (m1 > m2)
777                 {
778                     updateBestMatch(fd);
779                     continue;
780                 }
781                 else if (m1 < m2)
782                     continue;
783                 }
784                 {
785                 MATCH m1 = (tf.mod == fd.type.mod) ? MATCH.exact : MATCH.nomatch;
786                 MATCH m2 = (tf.mod == fdmatch.type.mod) ? MATCH.exact : MATCH.nomatch;
787                 if (m1 > m2)
788                 {
789                     updateBestMatch(fd);
790                     continue;
791                 }
792                 else if (m1 < m2)
793                     continue;
794                 }
795                 {
796                 // The way of definition: non-mixin > mixin
797                 MATCH m1 = fd.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
798                 MATCH m2 = fdmatch.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
799                 if (m1 > m2)
800                 {
801                     updateBestMatch(fd);
802                     continue;
803                 }
804                 else if (m1 < m2)
805                     continue;
806                 }
807 
808                 fdambig = fd;
809                 //printf("Lambig fdambig = %s %s [%s]\n", fdambig.toChars(), fdambig.type.toChars(), fdambig.loc.toChars());
810             }
811         }
812 
813         searchVtbl(vtbl);
814         for (auto cd = this; cd; cd = cd.baseClass)
815         {
816             searchVtbl(cd.vtblFinal);
817         }
818 
819         if (fdambig)
820             error("ambiguous virtual function `%s`", fdambig.toChars());
821 
822         return fdmatch;
823     }
824 
825     /****************************************
826      */
827     final bool isCOMclass() const
828     {
829         return com;
830     }
831 
832     bool isCOMinterface() const
833     {
834         return false;
835     }
836 
837     final bool isCPPclass() const
838     {
839         return classKind == ClassKind.cpp;
840     }
841 
842     bool isCPPinterface() const
843     {
844         return false;
845     }
846 
847     /****************************************
848      */
849     final bool isAbstract()
850     {
851         enum log = false;
852         if (isabstract != ThreeState.none)
853             return isabstract == ThreeState.yes;
854 
855         if (log) printf("isAbstract(%s)\n", toChars());
856 
857         bool no()  { if (log) printf("no\n");  isabstract = ThreeState.no;  return false; }
858         bool yes() { if (log) printf("yes\n"); isabstract = ThreeState.yes; return true;  }
859 
860         if (storage_class & STC.abstract_ || _scope && _scope.stc & STC.abstract_)
861             return yes();
862 
863         if (errors)
864             return no();
865 
866         /* https://issues.dlang.org/show_bug.cgi?id=11169
867          * Resolve forward references to all class member functions,
868          * and determine whether this class is abstract.
869          */
870         static int func(Dsymbol s)
871         {
872             auto fd = s.isFuncDeclaration();
873             if (!fd)
874                 return 0;
875             if (fd.storage_class & STC.static_)
876                 return 0;
877 
878             if (fd.isAbstract())
879                 return 1;
880             return 0;
881         }
882 
883         for (size_t i = 0; i < members.length; i++)
884         {
885             auto s = (*members)[i];
886             if (s.apply(&func))
887             {
888                 return yes();
889             }
890         }
891 
892         /* If the base class is not abstract, then this class cannot
893          * be abstract.
894          */
895         if (!isInterfaceDeclaration() && (!baseClass || !baseClass.isAbstract()))
896             return no();
897 
898         /* If any abstract functions are inherited, but not overridden,
899          * then the class is abstract. Do this by checking the vtbl[].
900          * Need to do semantic() on class to fill the vtbl[].
901          */
902         this.dsymbolSemantic(null);
903 
904         /* The next line should work, but does not because when ClassDeclaration.dsymbolSemantic()
905          * is called recursively it can set PASS.semanticdone without finishing it.
906          */
907         //if (semanticRun < PASS.semanticdone)
908         {
909             /* Could not complete semantic(). Try running semantic() on
910              * each of the virtual functions,
911              * which will fill in the vtbl[] overrides.
912              */
913             static int virtualSemantic(Dsymbol s)
914             {
915                 auto fd = s.isFuncDeclaration();
916                 if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration())
917                     fd.dsymbolSemantic(null);
918                 return 0;
919             }
920 
921             for (size_t i = 0; i < members.length; i++)
922             {
923                 auto s = (*members)[i];
924                 s.apply(&virtualSemantic);
925             }
926         }
927 
928         /* Finally, check the vtbl[]
929          */
930         foreach (i; 1 .. vtbl.length)
931         {
932             auto fd = vtbl[i].isFuncDeclaration();
933             //if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd.loc.toChars(), fd.toPrettyChars());
934             if (!fd || fd.isAbstract())
935             {
936                 return yes();
937             }
938         }
939 
940         return no();
941     }
942 
943     /****************************************
944      * Determine if slot 0 of the vtbl[] is reserved for something else.
945      * For class objects, yes, this is where the classinfo ptr goes.
946      * For COM interfaces, no.
947      * For non-COM interfaces, yes, this is where the Interface ptr goes.
948      * Returns:
949      *      0       vtbl[0] is first virtual function pointer
950      *      1       vtbl[0] is classinfo/interfaceinfo pointer
951      */
952     int vtblOffset() const
953     {
954         return classKind == ClassKind.cpp ? 0 : 1;
955     }
956 
957     /****************************************
958      */
959     override const(char)* kind() const
960     {
961         return "class";
962     }
963 
964     /****************************************
965      */
966     override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
967     {
968         .objc.addSymbols(this, classes, categories);
969     }
970 
971     // Back end
972     Dsymbol vtblsym;
973 
974     final Dsymbol vtblSymbol()
975     {
976         if (!vtblsym)
977         {
978             auto vtype = Type.tvoidptr.immutableOf().sarrayOf(vtbl.length);
979             auto var = new VarDeclaration(loc, vtype, Identifier.idPool("__vtbl"), null, STC.immutable_ | STC.static_);
980             var.addMember(null, this);
981             var.isdataseg = 1;
982             var._linkage = LINK.d;
983             var.semanticRun = PASS.semanticdone; // no more semantic wanted
984             vtblsym = var;
985         }
986         return vtblsym;
987     }
988 
989     extern (D) final bool isErrorException()
990     {
991         return errorException && (this == errorException || errorException.isBaseOf(this, null));
992     }
993 
994     override final inout(ClassDeclaration) isClassDeclaration() inout @nogc nothrow pure @safe
995     {
996         return this;
997     }
998 
999     override void accept(Visitor v)
1000     {
1001         v.visit(this);
1002     }
1003 }
1004 
1005 /***********************************************************
1006  */
1007 extern (C++) final class InterfaceDeclaration : ClassDeclaration
1008 {
1009     extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses)
1010     {
1011         super(loc, id, baseclasses, null, false);
1012         if (id == Id.IUnknown) // IUnknown is the root of all COM interfaces
1013         {
1014             com = true;
1015             classKind = ClassKind.cpp; // IUnknown is also a C++ interface
1016         }
1017     }
1018 
1019     override InterfaceDeclaration syntaxCopy(Dsymbol s)
1020     {
1021         InterfaceDeclaration id =
1022             s ? cast(InterfaceDeclaration)s
1023               : new InterfaceDeclaration(loc, ident, null);
1024         ClassDeclaration.syntaxCopy(id);
1025         return id;
1026     }
1027 
1028 
1029     override Scope* newScope(Scope* sc)
1030     {
1031         auto sc2 = super.newScope(sc);
1032         if (com)
1033             sc2.linkage = LINK.windows;
1034         else if (classKind == ClassKind.cpp)
1035             sc2.linkage = LINK.cpp;
1036         else if (classKind == ClassKind.objc)
1037             sc2.linkage = LINK.objc;
1038         return sc2;
1039     }
1040 
1041     /*******************************************
1042      * Determine if 'this' is a base class of cd.
1043      * (Actually, if it is an interface supported by cd)
1044      * Output:
1045      *      *poffset        offset to start of class
1046      *                      OFFSET_RUNTIME  must determine offset at runtime
1047      * Returns:
1048      *      false   not a base
1049      *      true    is a base
1050      */
1051     override bool isBaseOf(ClassDeclaration cd, int* poffset) pure nothrow @nogc
1052     {
1053         //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars());
1054         assert(!baseClass);
1055         foreach (b; cd.interfaces)
1056         {
1057             //printf("\tX base %s\n", b.sym.toChars());
1058             if (this == b.sym)
1059             {
1060                 //printf("\tfound at offset %d\n", b.offset);
1061                 if (poffset)
1062                 {
1063                     // don't return incorrect offsets
1064                     // https://issues.dlang.org/show_bug.cgi?id=16980
1065                     *poffset = cd.sizeok == Sizeok.done ? b.offset : OFFSET_FWDREF;
1066                 }
1067                 // printf("\tfound at offset %d\n", b.offset);
1068                 return true;
1069             }
1070             if (baseClassImplementsInterface(this, b, poffset))
1071                 return true;
1072         }
1073         if (cd.baseClass && isBaseOf(cd.baseClass, poffset))
1074             return true;
1075 
1076         if (poffset)
1077             *poffset = 0;
1078         return false;
1079     }
1080 
1081     /*******************************************
1082      */
1083     override const(char)* kind() const
1084     {
1085         return "interface";
1086     }
1087 
1088     /****************************************
1089      * Determine if slot 0 of the vtbl[] is reserved for something else.
1090      * For class objects, yes, this is where the ClassInfo ptr goes.
1091      * For COM interfaces, no.
1092      * For non-COM interfaces, yes, this is where the Interface ptr goes.
1093      */
1094     override int vtblOffset() const
1095     {
1096         if (isCOMinterface() || isCPPinterface())
1097             return 0;
1098         return 1;
1099     }
1100 
1101     override bool isCPPinterface() const
1102     {
1103         return classKind == ClassKind.cpp;
1104     }
1105 
1106     override bool isCOMinterface() const
1107     {
1108         return com;
1109     }
1110 
1111     override inout(InterfaceDeclaration) isInterfaceDeclaration() inout
1112     {
1113         return this;
1114     }
1115 
1116     override void accept(Visitor v)
1117     {
1118         v.visit(this);
1119     }
1120 }
1121 
1122 /**
1123  * Returns whether `bc` implements `id`, including indirectly (`bc` implements an interfaces
1124  * that inherits from `id`)
1125  *
1126  * Params:
1127  *    id = the interface
1128  *    bc = the base class
1129  *    poffset = out parameter, offset of the interface in an object
1130  *
1131  * Returns:
1132  *    true if the `bc` implements `id`, false otherwise
1133  **/
1134 private bool baseClassImplementsInterface(InterfaceDeclaration id, BaseClass* bc, int* poffset) pure nothrow @nogc
1135 {
1136     //printf("%s.InterfaceDeclaration.isBaseOf(bc = '%s')\n", id.toChars(), bc.sym.toChars());
1137     for (size_t j = 0; j < bc.baseInterfaces.length; j++)
1138     {
1139         BaseClass* b = &bc.baseInterfaces[j];
1140         //printf("\tY base %s\n", b.sym.toChars());
1141         if (id == b.sym)
1142         {
1143             //printf("\tfound at offset %d\n", b.offset);
1144             if (poffset)
1145             {
1146                 *poffset = b.offset;
1147             }
1148             return true;
1149         }
1150         if (baseClassImplementsInterface(id, b, poffset))
1151         {
1152             return true;
1153         }
1154     }
1155 
1156     if (poffset)
1157         *poffset = 0;
1158     return false;
1159 }