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