1 /**
2  * Defines a `class` declaration.
3  *
4  * Specification: $(LINK2 https://dlang.org/spec/class.html, Classes)
5  *
6  * Copyright:   Copyright (C) 1999-2020 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 : int
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 : int
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 Dsymbol syntaxCopy(Dsymbol s)
384     {
385         //printf("ClassDeclaration.syntaxCopy('%s')\n", toChars());
386         ClassDeclaration cd =
387             s ? cast(ClassDeclaration)s
388               : new ClassDeclaration(loc, ident, null, null, false);
389 
390         cd.storage_class |= storage_class;
391 
392         cd.baseclasses.setDim(this.baseclasses.dim);
393         for (size_t i = 0; i < cd.baseclasses.dim; i++)
394         {
395             BaseClass* b = (*this.baseclasses)[i];
396             auto b2 = new BaseClass(b.type.syntaxCopy());
397             (*cd.baseclasses)[i] = b2;
398         }
399 
400         return ScopeDsymbol.syntaxCopy(cd);
401     }
402 
403     override Scope* newScope(Scope* sc)
404     {
405         auto sc2 = super.newScope(sc);
406         if (isCOMclass())
407         {
408             /* This enables us to use COM objects under Linux and
409              * work with things like XPCOM
410              */
411             sc2.linkage = target.systemLinkage();
412         }
413         return sc2;
414     }
415 
416     /*********************************************
417      * Determine if 'this' is a base class of cd.
418      * This is used to detect circular inheritance only.
419      */
420     final bool isBaseOf2(ClassDeclaration cd)
421     {
422         if (!cd)
423             return false;
424         //printf("ClassDeclaration.isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
425         for (size_t i = 0; i < cd.baseclasses.dim; i++)
426         {
427             BaseClass* b = (*cd.baseclasses)[i];
428             if (b.sym == this || isBaseOf2(b.sym))
429                 return true;
430         }
431         return false;
432     }
433 
434     enum OFFSET_RUNTIME = 0x76543210;
435     enum OFFSET_FWDREF = 0x76543211;
436 
437     /*******************************************
438      * Determine if 'this' is a base class of cd.
439      */
440     bool isBaseOf(ClassDeclaration cd, int* poffset)
441     {
442         //printf("ClassDeclaration.isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
443         if (poffset)
444             *poffset = 0;
445         while (cd)
446         {
447             /* cd.baseClass might not be set if cd is forward referenced.
448              */
449             if (!cd.baseClass && cd.semanticRun < PASS.semanticdone && !cd.isInterfaceDeclaration())
450             {
451                 cd.dsymbolSemantic(null);
452                 if (!cd.baseClass && cd.semanticRun < PASS.semanticdone)
453                     cd.error("base class is forward referenced by `%s`", toChars());
454             }
455 
456             if (this == cd.baseClass)
457                 return true;
458 
459             cd = cd.baseClass;
460         }
461         return false;
462     }
463 
464     /*********************************************
465      * Determine if 'this' has complete base class information.
466      * This is used to detect forward references in covariant overloads.
467      */
468     final bool isBaseInfoComplete() const
469     {
470         return baseok >= Baseok.done;
471     }
472 
473     override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
474     {
475         //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
476         //if (_scope) printf("%s baseok = %d\n", toChars(), baseok);
477         if (_scope && baseok < Baseok.done)
478         {
479             if (!inuse)
480             {
481                 // must semantic on base class/interfaces
482                 inuse = true;
483                 dsymbolSemantic(this, null);
484                 inuse = false;
485             }
486         }
487 
488         if (!members || !symtab) // opaque or addMember is not yet done
489         {
490             // .stringof is always defined (but may be hidden by some other symbol)
491             if (ident != Id.stringof)
492                 error("is forward referenced when looking for `%s`", ident.toChars());
493             //*(char*)0=0;
494             return null;
495         }
496 
497         auto s = ScopeDsymbol.search(loc, ident, flags);
498 
499         // don't search imports of base classes
500         if (flags & SearchImportsOnly)
501             return s;
502 
503         if (!s)
504         {
505             // Search bases classes in depth-first, left to right order
506             for (size_t i = 0; i < baseclasses.dim; i++)
507             {
508                 BaseClass* b = (*baseclasses)[i];
509                 if (b.sym)
510                 {
511                     if (!b.sym.symtab)
512                         error("base `%s` is forward referenced", b.sym.ident.toChars());
513                     else
514                     {
515                         import dmd.access : symbolIsVisible;
516 
517                         s = b.sym.search(loc, ident, flags);
518                         if (!s)
519                             continue;
520                         else if (s == this) // happens if s is nested in this and derives from this
521                             s = null;
522                         else if (!(flags & IgnoreSymbolVisibility) && !(s.prot().kind == Prot.Kind.protected_) && !symbolIsVisible(this, s))
523                             s = null;
524                         else
525                             break;
526                     }
527                 }
528             }
529         }
530         return s;
531     }
532 
533     /************************************
534      * Search base classes in depth-first, left-to-right order for
535      * a class or interface named 'ident'.
536      * Stops at first found. Does not look for additional matches.
537      * Params:
538      *  ident = identifier to search for
539      * Returns:
540      *  ClassDeclaration if found, null if not
541      */
542     final ClassDeclaration searchBase(Identifier ident)
543     {
544         foreach (b; *baseclasses)
545         {
546             auto cdb = b.type.isClassHandle();
547             if (!cdb) // https://issues.dlang.org/show_bug.cgi?id=10616
548                 return null;
549             if (cdb.ident.equals(ident))
550                 return cdb;
551             auto result = cdb.searchBase(ident);
552             if (result)
553                 return result;
554         }
555         return null;
556     }
557 
558     final override void finalizeSize()
559     {
560         assert(sizeok != Sizeok.done);
561 
562         // Set the offsets of the fields and determine the size of the class
563         if (baseClass)
564         {
565             assert(baseClass.sizeok == Sizeok.done);
566 
567             alignsize = baseClass.alignsize;
568             structsize = baseClass.structsize;
569             if (classKind == ClassKind.cpp && global.params.isWindows)
570                 structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
571         }
572         else if (isInterfaceDeclaration())
573         {
574             if (interfaces.length == 0)
575             {
576                 alignsize = target.ptrsize;
577                 structsize = target.ptrsize;      // allow room for __vptr
578             }
579         }
580         else
581         {
582             alignsize = target.ptrsize;
583             structsize = target.ptrsize;      // allow room for __vptr
584             if (hasMonitor())
585                 structsize += target.ptrsize; // allow room for __monitor
586         }
587 
588         //printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
589         size_t bi = 0;                  // index into vtblInterfaces[]
590 
591         /****
592          * Runs through the inheritance graph to set the BaseClass.offset fields.
593          * Recursive in order to account for the size of the interface classes, if they are
594          * more than just interfaces.
595          * Params:
596          *      cd = interface to look at
597          *      baseOffset = offset of where cd will be placed
598          * Returns:
599          *      subset of instantiated size used by cd for interfaces
600          */
601         uint membersPlace(ClassDeclaration cd, uint baseOffset)
602         {
603             //printf("    membersPlace(%s, %d)\n", cd.toChars(), baseOffset);
604             uint offset = baseOffset;
605 
606             foreach (BaseClass* b; cd.interfaces)
607             {
608                 if (b.sym.sizeok != Sizeok.done)
609                     b.sym.finalizeSize();
610                 assert(b.sym.sizeok == Sizeok.done);
611 
612                 if (!b.sym.alignsize)
613                     b.sym.alignsize = target.ptrsize;
614                 alignmember(b.sym.alignsize, b.sym.alignsize, &offset);
615                 assert(bi < vtblInterfaces.dim);
616 
617                 BaseClass* bv = (*vtblInterfaces)[bi];
618                 if (b.sym.interfaces.length == 0)
619                 {
620                     //printf("\tvtblInterfaces[%d] b=%p b.sym = %s, offset = %d\n", bi, bv, bv.sym.toChars(), offset);
621                     bv.offset = offset;
622                     ++bi;
623                     // All the base interfaces down the left side share the same offset
624                     for (BaseClass* b2 = bv; b2.baseInterfaces.length; )
625                     {
626                         b2 = &b2.baseInterfaces[0];
627                         b2.offset = offset;
628                         //printf("\tvtblInterfaces[%d] b=%p   sym = %s, offset = %d\n", bi, b2, b2.sym.toChars(), b2.offset);
629                     }
630                 }
631                 membersPlace(b.sym, offset);
632                 //printf(" %s size = %d\n", b.sym.toChars(), b.sym.structsize);
633                 offset += b.sym.structsize;
634                 if (alignsize < b.sym.alignsize)
635                     alignsize = b.sym.alignsize;
636             }
637             return offset - baseOffset;
638         }
639 
640         structsize += membersPlace(this, structsize);
641 
642         if (isInterfaceDeclaration())
643         {
644             sizeok = Sizeok.done;
645             return;
646         }
647 
648         // FIXME: Currently setFieldOffset functions need to increase fields
649         // to calculate each variable offsets. It can be improved later.
650         fields.setDim(0);
651 
652         uint offset = structsize;
653         foreach (s; *members)
654         {
655             s.setFieldOffset(this, &offset, 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             foreach (s; vtbl)
732             {
733                 auto fd = s.isFuncDeclaration();
734                 if (!fd)
735                     continue;
736 
737                 // the first entry might be a ClassInfo
738                 //printf("\t[%d] = %s\n", i, fd.toChars());
739                 if (ident == fd.ident && fd.type.covariant(tf) == 1)
740                 {
741                     //printf("fd.parent.isClassDeclaration() = %p\n", fd.parent.isClassDeclaration());
742                     if (!fdmatch)
743                     {
744                         updateBestMatch(fd);
745                         continue;
746                     }
747                     if (fd == fdmatch)
748                         continue;
749 
750                     {
751                     // Function type matching: exact > covariant
752                     MATCH m1 = tf.equals(fd.type) ? MATCH.exact : MATCH.nomatch;
753                     MATCH m2 = tf.equals(fdmatch.type) ? MATCH.exact : MATCH.nomatch;
754                     if (m1 > m2)
755                     {
756                         updateBestMatch(fd);
757                         continue;
758                     }
759                     else if (m1 < m2)
760                         continue;
761                     }
762                     {
763                     MATCH m1 = (tf.mod == fd.type.mod) ? MATCH.exact : MATCH.nomatch;
764                     MATCH m2 = (tf.mod == fdmatch.type.mod) ? 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                     // The way of definition: non-mixin > mixin
775                     MATCH m1 = fd.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
776                     MATCH m2 = fdmatch.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
777                     if (m1 > m2)
778                     {
779                         updateBestMatch(fd);
780                         continue;
781                     }
782                     else if (m1 < m2)
783                         continue;
784                     }
785 
786                     fdambig = fd;
787                     //printf("Lambig fdambig = %s %s [%s]\n", fdambig.toChars(), fdambig.type.toChars(), fdambig.loc.toChars());
788                 }
789                 //else printf("\t\t%d\n", fd.type.covariant(tf));
790             }
791         }
792 
793         searchVtbl(vtbl);
794         for (auto cd = this; cd; cd = cd.baseClass)
795         {
796             searchVtbl(cd.vtblFinal);
797         }
798 
799         if (fdambig)
800             error("ambiguous virtual function `%s`", fdambig.toChars());
801 
802         return fdmatch;
803     }
804 
805     /****************************************
806      */
807     final bool isCOMclass() const
808     {
809         return com;
810     }
811 
812     bool isCOMinterface() const
813     {
814         return false;
815     }
816 
817     final bool isCPPclass() const
818     {
819         return classKind == ClassKind.cpp;
820     }
821 
822     bool isCPPinterface() const
823     {
824         return false;
825     }
826 
827     /****************************************
828      */
829     final bool isAbstract()
830     {
831         enum log = false;
832         if (isabstract != Abstract.fwdref)
833             return isabstract == Abstract.yes;
834 
835         if (log) printf("isAbstract(%s)\n", toChars());
836 
837         bool no()  { if (log) printf("no\n");  isabstract = Abstract.no;  return false; }
838         bool yes() { if (log) printf("yes\n"); isabstract = Abstract.yes; return true;  }
839 
840         if (storage_class & STC.abstract_ || _scope && _scope.stc & STC.abstract_)
841             return yes();
842 
843         if (errors)
844             return no();
845 
846         /* https://issues.dlang.org/show_bug.cgi?id=11169
847          * Resolve forward references to all class member functions,
848          * and determine whether this class is abstract.
849          */
850         static int func(Dsymbol s)
851         {
852             auto fd = s.isFuncDeclaration();
853             if (!fd)
854                 return 0;
855             if (fd.storage_class & STC.static_)
856                 return 0;
857 
858             if (fd.isAbstract())
859                 return 1;
860             return 0;
861         }
862 
863         for (size_t i = 0; i < members.dim; i++)
864         {
865             auto s = (*members)[i];
866             if (s.apply(&func))
867             {
868                 return yes();
869             }
870         }
871 
872         /* If the base class is not abstract, then this class cannot
873          * be abstract.
874          */
875         if (!isInterfaceDeclaration() && (!baseClass || !baseClass.isAbstract()))
876             return no();
877 
878         /* If any abstract functions are inherited, but not overridden,
879          * then the class is abstract. Do this by checking the vtbl[].
880          * Need to do semantic() on class to fill the vtbl[].
881          */
882         this.dsymbolSemantic(null);
883 
884         /* The next line should work, but does not because when ClassDeclaration.dsymbolSemantic()
885          * is called recursively it can set PASS.semanticdone without finishing it.
886          */
887         //if (semanticRun < PASS.semanticdone)
888         {
889             /* Could not complete semantic(). Try running semantic() on
890              * each of the virtual functions,
891              * which will fill in the vtbl[] overrides.
892              */
893             static int virtualSemantic(Dsymbol s)
894             {
895                 auto fd = s.isFuncDeclaration();
896                 if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration())
897                     fd.dsymbolSemantic(null);
898                 return 0;
899             }
900 
901             for (size_t i = 0; i < members.dim; i++)
902             {
903                 auto s = (*members)[i];
904                 s.apply(&virtualSemantic);
905             }
906         }
907 
908         /* Finally, check the vtbl[]
909          */
910         foreach (i; 1 .. vtbl.dim)
911         {
912             auto fd = vtbl[i].isFuncDeclaration();
913             //if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd.loc.toChars(), fd.toPrettyChars());
914             if (!fd || fd.isAbstract())
915             {
916                 return yes();
917             }
918         }
919 
920         return no();
921     }
922 
923     /****************************************
924      * Determine if slot 0 of the vtbl[] is reserved for something else.
925      * For class objects, yes, this is where the classinfo ptr goes.
926      * For COM interfaces, no.
927      * For non-COM interfaces, yes, this is where the Interface ptr goes.
928      * Returns:
929      *      0       vtbl[0] is first virtual function pointer
930      *      1       vtbl[0] is classinfo/interfaceinfo pointer
931      */
932     int vtblOffset() const
933     {
934         return classKind == ClassKind.cpp ? 0 : 1;
935     }
936 
937     /****************************************
938      */
939     override const(char)* kind() const
940     {
941         return "class";
942     }
943 
944     /****************************************
945      */
946     override final void addLocalClass(ClassDeclarations* aclasses)
947     {
948         if (classKind != ClassKind.objc)
949             aclasses.push(this);
950     }
951 
952     override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
953     {
954         .objc.addSymbols(this, classes, categories);
955     }
956 
957     // Back end
958     Dsymbol vtblsym;
959 
960     final Dsymbol vtblSymbol()
961     {
962         if (!vtblsym)
963         {
964             auto vtype = Type.tvoidptr.immutableOf().sarrayOf(vtbl.dim);
965             auto var = new VarDeclaration(loc, vtype, Identifier.idPool("__vtbl"), null, STC.immutable_ | STC.static_);
966             var.addMember(null, this);
967             var.isdataseg = 1;
968             var.linkage = LINK.d;
969             var.semanticRun = PASS.semanticdone; // no more semantic wanted
970             vtblsym = var;
971         }
972         return vtblsym;
973     }
974 
975     override final inout(ClassDeclaration) isClassDeclaration() inout
976     {
977         return this;
978     }
979 
980     override void accept(Visitor v)
981     {
982         v.visit(this);
983     }
984 }
985 
986 /***********************************************************
987  */
988 extern (C++) final class InterfaceDeclaration : ClassDeclaration
989 {
990     extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses)
991     {
992         super(loc, id, baseclasses, null, false);
993         if (id == Id.IUnknown) // IUnknown is the root of all COM interfaces
994         {
995             com = true;
996             classKind = ClassKind.cpp; // IUnknown is also a C++ interface
997         }
998     }
999 
1000     override Dsymbol syntaxCopy(Dsymbol s)
1001     {
1002         InterfaceDeclaration id =
1003             s ? cast(InterfaceDeclaration)s
1004               : new InterfaceDeclaration(loc, ident, null);
1005         return ClassDeclaration.syntaxCopy(id);
1006     }
1007 
1008 
1009     override Scope* newScope(Scope* sc)
1010     {
1011         auto sc2 = super.newScope(sc);
1012         if (com)
1013             sc2.linkage = LINK.windows;
1014         else if (classKind == ClassKind.cpp)
1015             sc2.linkage = LINK.cpp;
1016         else if (classKind == ClassKind.objc)
1017             sc2.linkage = LINK.objc;
1018         return sc2;
1019     }
1020 
1021     /*******************************************
1022      * Determine if 'this' is a base class of cd.
1023      * (Actually, if it is an interface supported by cd)
1024      * Output:
1025      *      *poffset        offset to start of class
1026      *                      OFFSET_RUNTIME  must determine offset at runtime
1027      * Returns:
1028      *      false   not a base
1029      *      true    is a base
1030      */
1031     override bool isBaseOf(ClassDeclaration cd, int* poffset)
1032     {
1033         //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars());
1034         assert(!baseClass);
1035         foreach (b; cd.interfaces)
1036         {
1037             //printf("\tX base %s\n", b.sym.toChars());
1038             if (this == b.sym)
1039             {
1040                 //printf("\tfound at offset %d\n", b.offset);
1041                 if (poffset)
1042                 {
1043                     // don't return incorrect offsets
1044                     // https://issues.dlang.org/show_bug.cgi?id=16980
1045                     *poffset = cd.sizeok == Sizeok.done ? b.offset : OFFSET_FWDREF;
1046                 }
1047                 // printf("\tfound at offset %d\n", b.offset);
1048                 return true;
1049             }
1050             if (isBaseOf(b, poffset))
1051                 return true;
1052         }
1053         if (cd.baseClass && isBaseOf(cd.baseClass, poffset))
1054             return true;
1055 
1056         if (poffset)
1057             *poffset = 0;
1058         return false;
1059     }
1060 
1061     bool isBaseOf(BaseClass* bc, int* poffset)
1062     {
1063         //printf("%s.InterfaceDeclaration.isBaseOf(bc = '%s')\n", toChars(), bc.sym.toChars());
1064         for (size_t j = 0; j < bc.baseInterfaces.length; j++)
1065         {
1066             BaseClass* b = &bc.baseInterfaces[j];
1067             //printf("\tY base %s\n", b.sym.toChars());
1068             if (this == b.sym)
1069             {
1070                 //printf("\tfound at offset %d\n", b.offset);
1071                 if (poffset)
1072                 {
1073                     *poffset = b.offset;
1074                 }
1075                 return true;
1076             }
1077             if (isBaseOf(b, poffset))
1078             {
1079                 return true;
1080             }
1081         }
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 }