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