d: Merge upstream dmd, druntime f1a045928e
[official-gcc.git] / gcc / d / dmd / dclass.d
blobe066d877e8aaaa0271ec7493c4ad370c71d94fe9
1 /**
2 * Defines a `class` declaration.
4 * Specification: $(LINK2 https://dlang.org/spec/class.html, Classes)
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
14 module dmd.dclass;
16 import core.stdc.stdio;
17 import core.stdc.string;
19 import dmd.aggregate;
20 import dmd.arraytypes;
21 import dmd.astenums;
22 import dmd.gluelayer;
23 import dmd.declaration;
24 import dmd.dscope;
25 import dmd.dsymbol;
26 import dmd.dsymbolsem;
27 import dmd.errors;
28 import dmd.func;
29 import dmd.id;
30 import dmd.identifier;
31 import dmd.location;
32 import dmd.mtype;
33 import dmd.objc;
34 import dmd.root.rmem;
35 import dmd.target;
36 import dmd.visitor;
38 /***********************************************************
40 extern (C++) struct BaseClass
42 Type type; // (before semantic processing)
44 ClassDeclaration sym;
45 uint offset; // 'this' pointer offset
47 // for interfaces: Array of FuncDeclaration's making up the vtbl[]
48 FuncDeclarations vtbl;
50 // if BaseClass is an interface, these
51 // are a copy of the InterfaceDeclaration.interfaces
52 BaseClass[] baseInterfaces;
54 extern (D) this(Type type)
56 //printf("BaseClass(this = %p, '%s')\n", this, type.toChars());
57 this.type = type;
60 /****************************************
61 * Fill in vtbl[] for base class based on member functions of class cd.
62 * Input:
63 * vtbl if !=NULL, fill it in
64 * newinstance !=0 means all entries must be filled in by members
65 * of cd, not members of any base classes of cd.
66 * Returns:
67 * true if any entries were filled in by members of cd (not exclusively
68 * by base classes)
70 extern (C++) bool fillVtbl(ClassDeclaration cd, FuncDeclarations* vtbl, int newinstance)
72 bool result = false;
74 //printf("BaseClass.fillVtbl(this='%s', cd='%s')\n", sym.toChars(), cd.toChars());
75 if (vtbl)
76 vtbl.setDim(sym.vtbl.length);
78 // first entry is ClassInfo reference
79 for (size_t j = sym.vtblOffset(); j < sym.vtbl.length; j++)
81 FuncDeclaration ifd = sym.vtbl[j].isFuncDeclaration();
83 //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd.toChars() : "null");
84 assert(ifd);
86 // Find corresponding function in this class
87 auto tf = ifd.type.toTypeFunction();
88 auto fd = cd.findFunc(ifd.ident, tf);
89 if (fd && !fd.isAbstract())
91 if (fd.toParent() == cd)
92 result = true;
94 else
95 fd = null;
96 if (vtbl)
97 (*vtbl)[j] = fd;
99 return result;
102 extern (D) void copyBaseInterfaces(BaseClasses* vtblInterfaces)
104 //printf("+copyBaseInterfaces(), %s\n", sym.toChars());
105 // if (baseInterfaces.length)
106 // return;
107 auto bc = cast(BaseClass*)mem.xcalloc(sym.interfaces.length, BaseClass.sizeof);
108 baseInterfaces = bc[0 .. sym.interfaces.length];
109 //printf("%s.copyBaseInterfaces()\n", sym.toChars());
110 for (size_t i = 0; i < baseInterfaces.length; i++)
112 BaseClass* b = &baseInterfaces[i];
113 BaseClass* b2 = sym.interfaces[i];
115 assert(b2.vtbl.length == 0); // should not be filled yet
116 memcpy(b, b2, BaseClass.sizeof);
118 if (i) // single inheritance is i==0
119 vtblInterfaces.push(b); // only need for M.I.
120 b.copyBaseInterfaces(vtblInterfaces);
122 //printf("-copyBaseInterfaces\n");
126 enum ClassFlags : uint
128 none = 0x0,
129 isCOMclass = 0x1,
130 noPointers = 0x2,
131 hasOffTi = 0x4,
132 hasCtor = 0x8,
133 hasGetMembers = 0x10,
134 hasTypeInfo = 0x20,
135 isAbstract = 0x40,
136 isCPPclass = 0x80,
137 hasDtor = 0x100,
140 /***********************************************************
142 extern (C++) class ClassDeclaration : AggregateDeclaration
144 extern (C++) __gshared
146 // Names found by reading object.d in druntime
147 ClassDeclaration object;
148 ClassDeclaration throwable;
149 ClassDeclaration exception;
150 ClassDeclaration errorException;
151 ClassDeclaration cpp_type_info_ptr; // Object.__cpp_type_info_ptr
154 ClassDeclaration baseClass; // NULL only if this is Object
155 FuncDeclaration staticCtor;
156 FuncDeclaration staticDtor;
157 Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[]
158 Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[]
160 // Array of BaseClass's; first is super, rest are Interface's
161 BaseClasses* baseclasses;
163 /* Slice of baseclasses[] that does not include baseClass
165 BaseClass*[] interfaces;
167 // array of base interfaces that have their own vtbl[]
168 BaseClasses* vtblInterfaces;
170 // the ClassInfo object for this ClassDeclaration
171 TypeInfoClassDeclaration vclassinfo;
173 // true if this is a COM class
174 bool com;
176 /// true if this is a scope class
177 bool stack;
179 /// if this is a C++ class, this is the slot reserved for the virtual destructor
180 int cppDtorVtblIndex = -1;
182 /// to prevent recursive attempts
183 bool inuse;
185 ThreeState isabstract;
187 /// set the progress of base classes resolving
188 Baseok baseok;
191 * Data for a class declaration that is needed for the Objective-C
192 * integration.
194 ObjcClassDeclaration objc;
196 Symbol* cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr
198 final extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
200 objc = ObjcClassDeclaration(this);
202 if (!id)
203 id = Identifier.generateAnonymousId("class");
205 super(loc, id);
207 static immutable msg = "only object.d can define this reserved class name";
209 if (baseclasses)
211 // Actually, this is a transfer
212 this.baseclasses = baseclasses;
214 else
215 this.baseclasses = new BaseClasses();
217 this.members = members;
219 //printf("ClassDeclaration(%s), dim = %d\n", ident.toChars(), this.baseclasses.length);
221 // For forward references
222 type = new TypeClass(this);
224 // Look for special class names
225 if (id == Id.__sizeof || id == Id.__xalignof || id == Id._mangleof)
226 classError("%s `%s` illegal class name", null);
228 // BUG: What if this is the wrong TypeInfo, i.e. it is nested?
229 if (id.toChars()[0] == 'T')
231 if (id == Id.TypeInfo)
233 if (!inObject)
234 classError("%s `%s` %s", msg.ptr);
235 Type.dtypeinfo = this;
237 if (id == Id.TypeInfo_Class)
239 if (!inObject)
240 classError("%s `%s` %s", msg.ptr);
241 Type.typeinfoclass = this;
243 if (id == Id.TypeInfo_Interface)
245 if (!inObject)
246 classError("%s `%s` %s", msg.ptr);
247 Type.typeinfointerface = this;
249 if (id == Id.TypeInfo_Struct)
251 if (!inObject)
252 classError("%s `%s` %s", msg.ptr);
253 Type.typeinfostruct = this;
255 if (id == Id.TypeInfo_Pointer)
257 if (!inObject)
258 classError("%s `%s` %s", msg.ptr);
259 Type.typeinfopointer = this;
261 if (id == Id.TypeInfo_Array)
263 if (!inObject)
264 classError("%s `%s` %s", msg.ptr);
265 Type.typeinfoarray = this;
267 if (id == Id.TypeInfo_StaticArray)
269 //if (!inObject)
270 // Type.typeinfostaticarray.classError("%s `%s` %s", msg);
271 Type.typeinfostaticarray = this;
273 if (id == Id.TypeInfo_AssociativeArray)
275 if (!inObject)
276 classError("%s `%s` %s", msg.ptr);
277 Type.typeinfoassociativearray = this;
279 if (id == Id.TypeInfo_Enum)
281 if (!inObject)
282 classError("%s `%s` %s", msg.ptr);
283 Type.typeinfoenum = this;
285 if (id == Id.TypeInfo_Function)
287 if (!inObject)
288 classError("%s `%s` %s", msg.ptr);
289 Type.typeinfofunction = this;
291 if (id == Id.TypeInfo_Delegate)
293 if (!inObject)
294 classError("%s `%s` %s", msg.ptr);
295 Type.typeinfodelegate = this;
297 if (id == Id.TypeInfo_Tuple)
299 if (!inObject)
300 classError("%s `%s` %s", msg.ptr);
301 Type.typeinfotypelist = this;
303 if (id == Id.TypeInfo_Const)
305 if (!inObject)
306 classError("%s `%s` %s", msg.ptr);
307 Type.typeinfoconst = this;
309 if (id == Id.TypeInfo_Invariant)
311 if (!inObject)
312 classError("%s `%s` %s", msg.ptr);
313 Type.typeinfoinvariant = this;
315 if (id == Id.TypeInfo_Shared)
317 if (!inObject)
318 classError("%s `%s` %s", msg.ptr);
319 Type.typeinfoshared = this;
321 if (id == Id.TypeInfo_Wild)
323 if (!inObject)
324 classError("%s `%s` %s", msg.ptr);
325 Type.typeinfowild = this;
327 if (id == Id.TypeInfo_Vector)
329 if (!inObject)
330 classError("%s `%s` %s", msg.ptr);
331 Type.typeinfovector = this;
335 if (id == Id.Object)
337 if (!inObject)
338 classError("%s `%s` %s", msg.ptr);
339 object = this;
342 if (id == Id.Throwable)
344 if (!inObject)
345 classError("%s `%s` %s", msg.ptr);
346 throwable = this;
348 if (id == Id.Exception)
350 if (!inObject)
351 classError("%s `%s` %s", msg.ptr);
352 exception = this;
354 if (id == Id.Error)
356 if (!inObject)
357 classError("%s `%s` %s", msg.ptr);
358 errorException = this;
360 if (id == Id.cpp_type_info_ptr)
362 if (!inObject)
363 classError("%s `%s` %s", msg.ptr);
364 cpp_type_info_ptr = this;
367 baseok = Baseok.none;
370 extern (D) final void classError(const(char)* fmt, const(char)* arg)
372 .error(loc, fmt, kind, toPrettyChars, arg);
375 static ClassDeclaration create(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
377 return new ClassDeclaration(loc, id, baseclasses, members, inObject);
380 override const(char)* toPrettyChars(bool qualifyTypes = false)
382 if (objc.isMeta)
383 return .objc.toPrettyChars(this, qualifyTypes);
385 return super.toPrettyChars(qualifyTypes);
388 override ClassDeclaration syntaxCopy(Dsymbol s)
390 //printf("ClassDeclaration.syntaxCopy('%s')\n", toChars());
391 ClassDeclaration cd =
392 s ? cast(ClassDeclaration)s
393 : new ClassDeclaration(loc, ident, null, null, false);
395 cd.storage_class |= storage_class;
397 cd.baseclasses.setDim(this.baseclasses.length);
398 for (size_t i = 0; i < cd.baseclasses.length; i++)
400 BaseClass* b = (*this.baseclasses)[i];
401 auto b2 = new BaseClass(b.type.syntaxCopy());
402 (*cd.baseclasses)[i] = b2;
405 ScopeDsymbol.syntaxCopy(cd);
406 return cd;
409 override Scope* newScope(Scope* sc)
411 auto sc2 = super.newScope(sc);
412 if (isCOMclass())
414 /* This enables us to use COM objects under Linux and
415 * work with things like XPCOM
417 sc2.linkage = target.systemLinkage();
419 return sc2;
422 /*********************************************
423 * Determine if 'this' is a base class of cd.
424 * This is used to detect circular inheritance only.
426 extern (D) final bool isBaseOf2(ClassDeclaration cd) pure nothrow @nogc
428 if (!cd)
429 return false;
430 //printf("ClassDeclaration.isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
431 for (size_t i = 0; i < cd.baseclasses.length; i++)
433 BaseClass* b = (*cd.baseclasses)[i];
434 if (b.sym == this || isBaseOf2(b.sym))
435 return true;
437 return false;
440 enum OFFSET_RUNTIME = 0x76543210;
441 enum OFFSET_FWDREF = 0x76543211;
443 /*******************************************
444 * Determine if 'this' is a base class of cd.
446 bool isBaseOf(ClassDeclaration cd, int* poffset) pure nothrow @nogc
448 //printf("ClassDeclaration.isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
449 if (poffset)
450 *poffset = 0;
451 while (cd)
453 assert(cd.baseClass || cd.semanticRun >= PASS.semanticdone || cd.isInterfaceDeclaration());
454 if (this == cd.baseClass)
455 return true;
457 cd = cd.baseClass;
459 return false;
462 /*********************************************
463 * Determine if 'this' has complete base class information.
464 * This is used to detect forward references in covariant overloads.
466 final bool isBaseInfoComplete() const
468 return baseok >= Baseok.done;
471 /************************************
472 * Search base classes in depth-first, left-to-right order for
473 * a class or interface named 'ident'.
474 * Stops at first found. Does not look for additional matches.
475 * Params:
476 * ident = identifier to search for
477 * Returns:
478 * ClassDeclaration if found, null if not
480 extern (D) final ClassDeclaration searchBase(Identifier ident)
482 foreach (b; *baseclasses)
484 auto cdb = b.type.isClassHandle();
485 if (!cdb) // https://issues.dlang.org/show_bug.cgi?id=10616
486 return null;
487 if (cdb.ident.equals(ident))
488 return cdb;
489 auto result = cdb.searchBase(ident);
490 if (result)
491 return result;
493 return null;
496 final override void finalizeSize()
498 assert(sizeok != Sizeok.done);
500 // Set the offsets of the fields and determine the size of the class
501 if (baseClass)
503 assert(baseClass.sizeok == Sizeok.done);
505 alignsize = baseClass.alignsize;
506 if (classKind == ClassKind.cpp)
507 structsize = target.cpp.derivedClassOffset(baseClass);
508 else
509 structsize = baseClass.structsize;
511 else if (classKind == ClassKind.objc)
512 structsize = 0; // no hidden member for an Objective-C class
513 else if (isInterfaceDeclaration())
515 if (interfaces.length == 0)
517 alignsize = target.ptrsize;
518 structsize = target.ptrsize; // allow room for __vptr
521 else
523 alignsize = target.ptrsize;
524 structsize = target.ptrsize; // allow room for __vptr
525 if (hasMonitor())
526 structsize += target.ptrsize; // allow room for __monitor
529 //printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
530 size_t bi = 0; // index into vtblInterfaces[]
532 /****
533 * Runs through the inheritance graph to set the BaseClass.offset fields.
534 * Recursive in order to account for the size of the interface classes, if they are
535 * more than just interfaces.
536 * Params:
537 * cd = interface to look at
538 * baseOffset = offset of where cd will be placed
539 * Returns:
540 * subset of instantiated size used by cd for interfaces
542 uint membersPlace(ClassDeclaration cd, uint baseOffset)
544 //printf(" membersPlace(%s, %d)\n", cd.toChars(), baseOffset);
545 uint offset = baseOffset;
547 foreach (BaseClass* b; cd.interfaces)
549 if (b.sym.sizeok != Sizeok.done)
550 b.sym.finalizeSize();
551 assert(b.sym.sizeok == Sizeok.done);
553 if (!b.sym.alignsize)
554 b.sym.alignsize = target.ptrsize;
555 offset = alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, offset);
556 assert(bi < vtblInterfaces.length);
558 BaseClass* bv = (*vtblInterfaces)[bi];
559 if (b.sym.interfaces.length == 0)
561 //printf("\tvtblInterfaces[%d] b=%p b.sym = %s, offset = %d\n", bi, bv, bv.sym.toChars(), offset);
562 bv.offset = offset;
563 ++bi;
564 // All the base interfaces down the left side share the same offset
565 for (BaseClass* b2 = bv; b2.baseInterfaces.length; )
567 b2 = &b2.baseInterfaces[0];
568 b2.offset = offset;
569 //printf("\tvtblInterfaces[%d] b=%p sym = %s, offset = %d\n", bi, b2, b2.sym.toChars(), b2.offset);
572 membersPlace(b.sym, offset);
573 //printf(" %s size = %d\n", b.sym.toChars(), b.sym.structsize);
574 offset += b.sym.structsize;
575 if (alignsize < b.sym.alignsize)
576 alignsize = b.sym.alignsize;
578 return offset - baseOffset;
581 structsize += membersPlace(this, structsize);
583 if (isInterfaceDeclaration())
585 sizeok = Sizeok.done;
586 return;
589 // FIXME: Currently setFieldOffset functions need to increase fields
590 // to calculate each variable offsets. It can be improved later.
591 fields.setDim(0);
593 FieldState fieldState;
594 fieldState.offset = structsize;
595 foreach (s; *members)
597 s.setFieldOffset(this, &fieldState, false);
600 sizeok = Sizeok.done;
602 // Calculate fields[i].overlapped
603 checkOverlappedFields();
606 /**************
607 * Returns: true if there's a __monitor field
609 final bool hasMonitor()
611 return classKind == ClassKind.d;
614 final bool isFuncHidden(FuncDeclaration fd)
616 //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars());
617 Dsymbol s = this.search(Loc.initial, fd.ident, SearchOpt.ignoreAmbiguous | SearchOpt.ignoreErrors);
618 if (!s)
620 //printf("not found\n");
621 /* Because, due to a hack, if there are multiple definitions
622 * of fd.ident, NULL is returned.
624 return false;
626 s = s.toAlias();
627 if (auto os = s.isOverloadSet())
629 foreach (sm; os.a)
631 auto fm = sm.isFuncDeclaration();
632 if (overloadApply(fm, s => fd == s.isFuncDeclaration()))
633 return false;
635 return true;
637 else
639 auto f = s.isFuncDeclaration();
640 //printf("%s fdstart = %p\n", s.kind(), fdstart);
641 if (overloadApply(f, s => fd == s.isFuncDeclaration()))
642 return false;
643 return !fd.parent.isTemplateMixin();
647 /****************
648 * Find virtual function matching identifier and type.
649 * Used to build virtual function tables for interface implementations.
650 * Params:
651 * ident = function's identifier
652 * tf = function's type
653 * Returns:
654 * function symbol if found, null if not
655 * Errors:
656 * prints error message if more than one match
658 extern (D) final FuncDeclaration findFunc(Identifier ident, TypeFunction tf)
660 //printf("ClassDeclaration.findFunc(%s, %s) %s\n", ident.toChars(), tf.toChars(), toChars());
661 FuncDeclaration fdmatch = null;
662 FuncDeclaration fdambig = null;
664 void updateBestMatch(FuncDeclaration fd)
666 fdmatch = fd;
667 fdambig = null;
668 //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch.toChars(), fdmatch.type.toChars(), fdmatch.loc.toChars());
671 void searchVtbl(ref Dsymbols vtbl)
673 import dmd.typesem : covariant;
674 bool seenInterfaceVirtual;
675 foreach (s; vtbl)
677 auto fd = s.isFuncDeclaration();
678 if (!fd)
679 continue;
681 // the first entry might be a ClassInfo
682 //printf("\t[%d] = %s\n", i, fd.toChars());
683 if (ident != fd.ident || fd.type.covariant(tf) != Covariant.yes)
685 //printf("\t\t%d\n", fd.type.covariant(tf));
686 continue;
689 //printf("fd.parent.isClassDeclaration() = %p\n", fd.parent.isClassDeclaration());
690 if (!fdmatch)
692 updateBestMatch(fd);
693 continue;
695 if (fd == fdmatch)
696 continue;
698 /* Functions overriding interface functions for extern(C++) with VC++
699 * are not in the normal vtbl, but in vtblFinal. If the implementation
700 * is again overridden in a child class, both would be found here.
701 * The function in the child class should override the function
702 * in the base class, which is done here, because searchVtbl is first
703 * called for the child class. Checking seenInterfaceVirtual makes
704 * sure, that the compared functions are not in the same vtbl.
706 if (fd.interfaceVirtual &&
707 fd.interfaceVirtual is fdmatch.interfaceVirtual &&
708 !seenInterfaceVirtual &&
709 fdmatch.type.covariant(fd.type) == Covariant.yes)
711 seenInterfaceVirtual = true;
712 continue;
716 // Function type matching: exact > covariant
717 MATCH m1 = tf.equals(fd.type) ? MATCH.exact : MATCH.nomatch;
718 MATCH m2 = tf.equals(fdmatch.type) ? MATCH.exact : MATCH.nomatch;
719 if (m1 > m2)
721 updateBestMatch(fd);
722 continue;
724 else if (m1 < m2)
725 continue;
728 MATCH m1 = (tf.mod == fd.type.mod) ? MATCH.exact : MATCH.nomatch;
729 MATCH m2 = (tf.mod == fdmatch.type.mod) ? MATCH.exact : MATCH.nomatch;
730 if (m1 > m2)
732 updateBestMatch(fd);
733 continue;
735 else if (m1 < m2)
736 continue;
739 // The way of definition: non-mixin > mixin
740 MATCH m1 = fd.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
741 MATCH m2 = fdmatch.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
742 if (m1 > m2)
744 updateBestMatch(fd);
745 continue;
747 else if (m1 < m2)
748 continue;
751 fdambig = fd;
752 //printf("Lambig fdambig = %s %s [%s]\n", fdambig.toChars(), fdambig.type.toChars(), fdambig.loc.toChars());
756 searchVtbl(vtbl);
757 for (auto cd = this; cd; cd = cd.baseClass)
759 searchVtbl(cd.vtblFinal);
762 if (fdambig)
763 classError("%s `%s` ambiguous virtual function `%s`", fdambig.toChars());
765 return fdmatch;
768 /****************************************
770 final bool isCOMclass() const
772 return com;
775 bool isCOMinterface() const
777 return false;
780 final bool isCPPclass() const
782 return classKind == ClassKind.cpp;
785 bool isCPPinterface() const
787 return false;
790 /****************************************
792 final bool isAbstract()
794 enum log = false;
795 if (isabstract != ThreeState.none)
796 return isabstract == ThreeState.yes;
798 if (log) printf("isAbstract(%s)\n", toChars());
800 bool no() { if (log) printf("no\n"); isabstract = ThreeState.no; return false; }
801 bool yes() { if (log) printf("yes\n"); isabstract = ThreeState.yes; return true; }
803 if (storage_class & STC.abstract_ || _scope && _scope.stc & STC.abstract_)
804 return yes();
806 if (errors)
807 return no();
809 /* https://issues.dlang.org/show_bug.cgi?id=11169
810 * Resolve forward references to all class member functions,
811 * and determine whether this class is abstract.
813 static int func(Dsymbol s, void*)
815 auto fd = s.isFuncDeclaration();
816 if (!fd)
817 return 0;
818 if (fd.storage_class & STC.static_)
819 return 0;
821 if (fd.isAbstract())
822 return 1;
823 return 0;
826 // opaque class is not abstract if it is not declared abstract
827 if (!members)
828 return no();
830 for (size_t i = 0; i < members.length; i++)
832 auto s = (*members)[i];
833 if (s.apply(&func, null))
835 return yes();
839 /* If the base class is not abstract, then this class cannot
840 * be abstract.
842 if (!isInterfaceDeclaration() && (!baseClass || !baseClass.isAbstract()))
843 return no();
845 /* If any abstract functions are inherited, but not overridden,
846 * then the class is abstract. Do this by checking the vtbl[].
847 * Need to do semantic() on class to fill the vtbl[].
849 this.dsymbolSemantic(null);
851 /* The next line should work, but does not because when ClassDeclaration.dsymbolSemantic()
852 * is called recursively it can set PASS.semanticdone without finishing it.
854 //if (semanticRun < PASS.semanticdone)
856 /* Could not complete semantic(). Try running semantic() on
857 * each of the virtual functions,
858 * which will fill in the vtbl[] overrides.
860 static int virtualSemantic(Dsymbol s, void*)
862 auto fd = s.isFuncDeclaration();
863 if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration())
864 fd.dsymbolSemantic(null);
865 return 0;
868 for (size_t i = 0; i < members.length; i++)
870 auto s = (*members)[i];
871 s.apply(&virtualSemantic,null);
875 /* Finally, check the vtbl[]
877 foreach (i; 1 .. vtbl.length)
879 auto fd = vtbl[i].isFuncDeclaration();
880 //if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd.loc.toChars(), fd.toPrettyChars());
881 if (!fd || fd.isAbstract())
883 return yes();
887 return no();
890 /****************************************
891 * Determine if slot 0 of the vtbl[] is reserved for something else.
892 * For class objects, yes, this is where the classinfo ptr goes.
893 * For COM interfaces, no.
894 * For non-COM interfaces, yes, this is where the Interface ptr goes.
895 * Returns:
896 * 0 vtbl[0] is first virtual function pointer
897 * 1 vtbl[0] is classinfo/interfaceinfo pointer
899 int vtblOffset() const
901 return classKind == ClassKind.cpp ? 0 : 1;
904 /****************************************
906 override const(char)* kind() const
908 return "class";
911 /****************************************
913 override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
915 .objc.addSymbols(this, classes, categories);
918 // Back end
919 Dsymbol vtblsym;
921 final Dsymbol vtblSymbol()
923 if (!vtblsym)
925 auto vtype = Type.tvoidptr.immutableOf().sarrayOf(vtbl.length);
926 auto var = new VarDeclaration(loc, vtype, Identifier.idPool("__vtbl"), null, STC.immutable_ | STC.static_);
927 var.addMember(null, this);
928 var.isdataseg = 1;
929 var._linkage = LINK.d;
930 var.semanticRun = PASS.semanticdone; // no more semantic wanted
931 vtblsym = var;
933 return vtblsym;
936 extern (D) final bool isErrorException()
938 return errorException && (this == errorException || errorException.isBaseOf(this, null));
941 override final inout(ClassDeclaration) isClassDeclaration() inout @nogc nothrow pure @safe
943 return this;
946 override void accept(Visitor v)
948 v.visit(this);
952 /***********************************************************
954 extern (C++) final class InterfaceDeclaration : ClassDeclaration
956 extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses)
958 super(loc, id, baseclasses, null, false);
959 if (id == Id.IUnknown) // IUnknown is the root of all COM interfaces
961 com = true;
962 classKind = ClassKind.cpp; // IUnknown is also a C++ interface
966 override InterfaceDeclaration syntaxCopy(Dsymbol s)
968 InterfaceDeclaration id =
969 s ? cast(InterfaceDeclaration)s
970 : new InterfaceDeclaration(loc, ident, null);
971 ClassDeclaration.syntaxCopy(id);
972 return id;
976 override Scope* newScope(Scope* sc)
978 auto sc2 = super.newScope(sc);
979 if (com)
980 sc2.linkage = LINK.windows;
981 else if (classKind == ClassKind.cpp)
982 sc2.linkage = LINK.cpp;
983 else if (classKind == ClassKind.objc)
984 sc2.linkage = LINK.objc;
985 return sc2;
988 /*******************************************
989 * Determine if 'this' is a base class of cd.
990 * (Actually, if it is an interface supported by cd)
991 * Output:
992 * *poffset offset to start of class
993 * OFFSET_RUNTIME must determine offset at runtime
994 * Returns:
995 * false not a base
996 * true is a base
998 override bool isBaseOf(ClassDeclaration cd, int* poffset) pure nothrow @nogc
1000 //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars());
1001 assert(!baseClass);
1002 foreach (b; cd.interfaces)
1004 //printf("\tX base %s\n", b.sym.toChars());
1005 if (this == b.sym)
1007 //printf("\tfound at offset %d\n", b.offset);
1008 if (poffset)
1010 // don't return incorrect offsets
1011 // https://issues.dlang.org/show_bug.cgi?id=16980
1012 *poffset = cd.sizeok == Sizeok.done ? b.offset : OFFSET_FWDREF;
1014 // printf("\tfound at offset %d\n", b.offset);
1015 return true;
1017 if (baseClassImplementsInterface(this, b, poffset))
1018 return true;
1020 if (cd.baseClass && isBaseOf(cd.baseClass, poffset))
1021 return true;
1023 if (poffset)
1024 *poffset = 0;
1025 return false;
1028 /*******************************************
1030 override const(char)* kind() const
1032 return "interface";
1035 /****************************************
1036 * Determine if slot 0 of the vtbl[] is reserved for something else.
1037 * For class objects, yes, this is where the ClassInfo ptr goes.
1038 * For COM interfaces, no.
1039 * For non-COM interfaces, yes, this is where the Interface ptr goes.
1041 override int vtblOffset() const
1043 if (isCOMinterface() || isCPPinterface())
1044 return 0;
1045 return 1;
1048 override bool isCPPinterface() const
1050 return classKind == ClassKind.cpp;
1053 override bool isCOMinterface() const
1055 return com;
1058 override inout(InterfaceDeclaration) isInterfaceDeclaration() inout
1060 return this;
1063 override void accept(Visitor v)
1065 v.visit(this);
1070 * Returns whether `bc` implements `id`, including indirectly (`bc` implements an interfaces
1071 * that inherits from `id`)
1073 * Params:
1074 * id = the interface
1075 * bc = the base class
1076 * poffset = out parameter, offset of the interface in an object
1078 * Returns:
1079 * true if the `bc` implements `id`, false otherwise
1081 private bool baseClassImplementsInterface(InterfaceDeclaration id, BaseClass* bc, int* poffset) pure nothrow @nogc @safe
1083 //printf("%s.InterfaceDeclaration.isBaseOf(bc = '%s')\n", id.toChars(), bc.sym.toChars());
1084 for (size_t j = 0; j < bc.baseInterfaces.length; j++)
1086 BaseClass* b = &bc.baseInterfaces[j];
1087 //printf("\tY base %s\n", b.sym.toChars());
1088 if (id == b.sym)
1090 //printf("\tfound at offset %d\n", b.offset);
1091 if (poffset)
1093 *poffset = b.offset;
1095 return true;
1097 if (baseClassImplementsInterface(id, b, poffset))
1099 return true;
1103 if (poffset)
1104 *poffset = 0;
1105 return false;