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