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
16 import core
.stdc
.stdio
;
17 import core
.stdc
.string
;
20 import dmd
.arraytypes
;
23 import dmd
.declaration
;
26 import dmd
.dsymbolsem
;
30 import dmd
.identifier
;
38 /***********************************************************
40 extern (C
++) struct BaseClass
42 Type type
; // (before semantic processing)
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());
60 /****************************************
61 * Fill in vtbl[] for base class based on member functions of class cd.
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.
67 * true if any entries were filled in by members of cd (not exclusively
70 extern (C
++) bool fillVtbl(ClassDeclaration cd
, FuncDeclarations
* vtbl
, int newinstance
)
74 //printf("BaseClass.fillVtbl(this='%s', cd='%s')\n", sym.toChars(), cd.toChars());
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");
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
)
102 extern (D
) void copyBaseInterfaces(BaseClasses
* vtblInterfaces
)
104 //printf("+copyBaseInterfaces(), %s\n", sym.toChars());
105 // if (baseInterfaces.length)
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
133 hasGetMembers
= 0x10,
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
176 /// true if this is a scope class
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
185 ThreeState isabstract
;
187 /// set the progress of base classes resolving
191 * Data for a class declaration that is needed for the Objective-C
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);
203 id
= Identifier
.generateAnonymousId("class");
207 static immutable msg
= "only object.d can define this reserved class name";
211 // Actually, this is a transfer
212 this.baseclasses
= baseclasses
;
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
)
234 classError("%s `%s` %s", msg
.ptr
);
235 Type
.dtypeinfo
= this;
237 if (id
== Id
.TypeInfo_Class
)
240 classError("%s `%s` %s", msg
.ptr
);
241 Type
.typeinfoclass
= this;
243 if (id
== Id
.TypeInfo_Interface
)
246 classError("%s `%s` %s", msg
.ptr
);
247 Type
.typeinfointerface
= this;
249 if (id
== Id
.TypeInfo_Struct
)
252 classError("%s `%s` %s", msg
.ptr
);
253 Type
.typeinfostruct
= this;
255 if (id
== Id
.TypeInfo_Pointer
)
258 classError("%s `%s` %s", msg
.ptr
);
259 Type
.typeinfopointer
= this;
261 if (id
== Id
.TypeInfo_Array
)
264 classError("%s `%s` %s", msg
.ptr
);
265 Type
.typeinfoarray
= this;
267 if (id
== Id
.TypeInfo_StaticArray
)
270 // Type.typeinfostaticarray.classError("%s `%s` %s", msg);
271 Type
.typeinfostaticarray
= this;
273 if (id
== Id
.TypeInfo_AssociativeArray
)
276 classError("%s `%s` %s", msg
.ptr
);
277 Type
.typeinfoassociativearray
= this;
279 if (id
== Id
.TypeInfo_Enum
)
282 classError("%s `%s` %s", msg
.ptr
);
283 Type
.typeinfoenum
= this;
285 if (id
== Id
.TypeInfo_Function
)
288 classError("%s `%s` %s", msg
.ptr
);
289 Type
.typeinfofunction
= this;
291 if (id
== Id
.TypeInfo_Delegate
)
294 classError("%s `%s` %s", msg
.ptr
);
295 Type
.typeinfodelegate
= this;
297 if (id
== Id
.TypeInfo_Tuple
)
300 classError("%s `%s` %s", msg
.ptr
);
301 Type
.typeinfotypelist
= this;
303 if (id
== Id
.TypeInfo_Const
)
306 classError("%s `%s` %s", msg
.ptr
);
307 Type
.typeinfoconst
= this;
309 if (id
== Id
.TypeInfo_Invariant
)
312 classError("%s `%s` %s", msg
.ptr
);
313 Type
.typeinfoinvariant
= this;
315 if (id
== Id
.TypeInfo_Shared
)
318 classError("%s `%s` %s", msg
.ptr
);
319 Type
.typeinfoshared
= this;
321 if (id
== Id
.TypeInfo_Wild
)
324 classError("%s `%s` %s", msg
.ptr
);
325 Type
.typeinfowild
= this;
327 if (id
== Id
.TypeInfo_Vector
)
330 classError("%s `%s` %s", msg
.ptr
);
331 Type
.typeinfovector
= this;
338 classError("%s `%s` %s", msg
.ptr
);
342 if (id
== Id
.Throwable
)
345 classError("%s `%s` %s", msg
.ptr
);
348 if (id
== Id
.Exception
)
351 classError("%s `%s` %s", msg
.ptr
);
357 classError("%s `%s` %s", msg
.ptr
);
358 errorException
= this;
360 if (id
== Id
.cpp_type_info_ptr
)
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)
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
);
409 override Scope
* newScope(Scope
* sc
)
411 auto sc2
= super.newScope(sc
);
414 /* This enables us to use COM objects under Linux and
415 * work with things like XPCOM
417 sc2
.linkage
= target
.systemLinkage();
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
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
))
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());
453 assert(cd
.baseClass || cd
.semanticRun
>= PASS
.semanticdone || cd
.isInterfaceDeclaration());
454 if (this == cd
.baseClass
)
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.
476 * ident = identifier to search for
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
487 if (cdb
.ident
.equals(ident
))
489 auto result
= cdb
.searchBase(ident
);
496 final override void finalizeSize()
498 assert(sizeok
!= Sizeok
.done
);
500 // Set the offsets of the fields and determine the size of the class
503 assert(baseClass
.sizeok
== Sizeok
.done
);
505 alignsize
= baseClass
.alignsize
;
506 if (classKind
== ClassKind
.cpp
)
507 structsize
= target
.cpp
.derivedClassOffset(baseClass
);
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
523 alignsize
= target
.ptrsize
;
524 structsize
= target
.ptrsize
; // allow room for __vptr
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[]
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.
537 * cd = interface to look at
538 * baseOffset = offset of where cd will be placed
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);
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];
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
;
589 // FIXME: Currently setFieldOffset functions need to increase fields
590 // to calculate each variable offsets. It can be improved later.
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();
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
);
620 //printf("not found\n");
621 /* Because, due to a hack, if there are multiple definitions
622 * of fd.ident, NULL is returned.
627 if (auto os
= s
.isOverloadSet())
631 auto fm
= sm
.isFuncDeclaration();
632 if (overloadApply(fm
, s
=> fd
== s
.isFuncDeclaration()))
639 auto f
= s
.isFuncDeclaration();
640 //printf("%s fdstart = %p\n", s.kind(), fdstart);
641 if (overloadApply(f
, s
=> fd
== s
.isFuncDeclaration()))
643 return !fd
.parent
.isTemplateMixin();
648 * Find virtual function matching identifier and type.
649 * Used to build virtual function tables for interface implementations.
651 * ident = function's identifier
652 * tf = function's type
654 * function symbol if found, null if not
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
)
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
;
677 auto fd
= s
.isFuncDeclaration();
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));
689 //printf("fd.parent.isClassDeclaration() = %p\n", fd.parent.isClassDeclaration());
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;
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
;
728 MATCH m1
= (tf
.mod
== fd
.type
.mod
) ? MATCH
.exact
: MATCH
.nomatch
;
729 MATCH m2
= (tf
.mod
== fdmatch
.type
.mod
) ? MATCH
.exact
: MATCH
.nomatch
;
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
;
752 //printf("Lambig fdambig = %s %s [%s]\n", fdambig.toChars(), fdambig.type.toChars(), fdambig.loc.toChars());
757 for (auto cd
= this; cd
; cd
= cd
.baseClass
)
759 searchVtbl(cd
.vtblFinal
);
763 classError("%s `%s` ambiguous virtual function `%s`", fdambig
.toChars());
768 /****************************************
770 final bool isCOMclass() const
775 bool isCOMinterface() const
780 final bool isCPPclass() const
782 return classKind
== ClassKind
.cpp
;
785 bool isCPPinterface() const
790 /****************************************
792 final bool isAbstract()
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_
)
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();
818 if (fd
.storage_class
& STC
.static_
)
826 // opaque class is not abstract if it is not declared abstract
830 for (size_t i
= 0; i
< members
.length
; i
++)
832 auto s
= (*members
)[i
];
833 if (s
.apply(&func
, null))
839 /* If the base class is not abstract, then this class cannot
842 if (!isInterfaceDeclaration() && (!baseClass ||
!baseClass
.isAbstract()))
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);
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())
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.
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
911 /****************************************
913 override final void addObjcSymbols(ClassDeclarations
* classes
, ClassDeclarations
* categories
)
915 .objc
.addSymbols(this, classes
, categories
);
921 final Dsymbol
vtblSymbol()
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);
929 var
._linkage
= LINK
.d
;
930 var
.semanticRun
= PASS
.semanticdone
; // no more semantic wanted
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
946 override void accept(Visitor v
)
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
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
);
976 override Scope
* newScope(Scope
* sc
)
978 auto sc2
= super.newScope(sc
);
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
;
988 /*******************************************
989 * Determine if 'this' is a base class of cd.
990 * (Actually, if it is an interface supported by cd)
992 * *poffset offset to start of class
993 * OFFSET_RUNTIME must determine offset at runtime
998 override bool isBaseOf(ClassDeclaration cd
, int* poffset
) pure nothrow @nogc
1000 //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars());
1002 foreach (b
; cd
.interfaces
)
1004 //printf("\tX base %s\n", b.sym.toChars());
1007 //printf("\tfound at offset %d\n", b.offset);
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);
1017 if (baseClassImplementsInterface(this, b
, poffset
))
1020 if (cd
.baseClass
&& isBaseOf(cd
.baseClass
, poffset
))
1028 /*******************************************
1030 override const(char)* kind() const
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())
1048 override bool isCPPinterface() const
1050 return classKind
== ClassKind
.cpp
;
1053 override bool isCOMinterface() const
1058 override inout(InterfaceDeclaration
) isInterfaceDeclaration() inout
1063 override void accept(Visitor v
)
1070 * Returns whether `bc` implements `id`, including indirectly (`bc` implements an interfaces
1071 * that inherits from `id`)
1074 * id = the interface
1075 * bc = the base class
1076 * poffset = out parameter, offset of the interface in an object
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());
1090 //printf("\tfound at offset %d\n", b.offset);
1093 *poffset
= b
.offset
;
1097 if (baseClassImplementsInterface(id
, b
, poffset
))