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