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