]>
Commit | Line | Data |
---|---|---|
b4c522fa IB |
1 | |
2 | /* Compiler implementation of the D programming language | |
a3b38b77 | 3 | * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved |
b4c522fa IB |
4 | * written by Walter Bright |
5 | * http://www.digitalmars.com | |
6 | * Distributed under the Boost Software License, Version 1.0. | |
7 | * http://www.boost.org/LICENSE_1_0.txt | |
8 | * https://github.com/D-Programming-Language/dmd/blob/master/src/class.c | |
9 | */ | |
10 | ||
f9ab59ff | 11 | #include "root/dsystem.h" // mem{cpy|set}() |
b4c522fa IB |
12 | #include "root/root.h" |
13 | #include "root/rmem.h" | |
14 | ||
15 | #include "errors.h" | |
16 | #include "enum.h" | |
17 | #include "init.h" | |
18 | #include "attrib.h" | |
19 | #include "declaration.h" | |
20 | #include "aggregate.h" | |
21 | #include "id.h" | |
22 | #include "mtype.h" | |
23 | #include "scope.h" | |
24 | #include "module.h" | |
25 | #include "expression.h" | |
26 | #include "statement.h" | |
27 | #include "template.h" | |
28 | #include "target.h" | |
29 | #include "objc.h" | |
30 | ||
31 | bool symbolIsVisible(Dsymbol *origin, Dsymbol *s); | |
32 | Objc *objc(); | |
33 | ||
34 | ||
35 | /********************************* ClassDeclaration ****************************/ | |
36 | ||
37 | ClassDeclaration *ClassDeclaration::object; | |
38 | ClassDeclaration *ClassDeclaration::throwable; | |
39 | ClassDeclaration *ClassDeclaration::exception; | |
40 | ClassDeclaration *ClassDeclaration::errorException; | |
41 | ClassDeclaration *ClassDeclaration::cpp_type_info_ptr; // Object.__cpp_type_info_ptr | |
42 | ||
43 | ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject) | |
44 | : AggregateDeclaration(loc, id ? id : Identifier::generateId("__anonclass")) | |
45 | { | |
46 | static const char msg[] = "only object.d can define this reserved class name"; | |
47 | ||
48 | if (baseclasses) | |
49 | { | |
50 | // Actually, this is a transfer | |
51 | this->baseclasses = baseclasses; | |
52 | } | |
53 | else | |
54 | this->baseclasses = new BaseClasses(); | |
55 | ||
56 | this->members = members; | |
57 | ||
58 | baseClass = NULL; | |
59 | ||
60 | interfaces.length = 0; | |
61 | interfaces.ptr = NULL; | |
62 | ||
63 | vtblInterfaces = NULL; | |
64 | ||
2cbc99d1 | 65 | //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses->length); |
b4c522fa IB |
66 | |
67 | // For forward references | |
68 | type = new TypeClass(this); | |
69 | ||
70 | staticCtor = NULL; | |
71 | staticDtor = NULL; | |
72 | ||
73 | vtblsym = NULL; | |
74 | vclassinfo = NULL; | |
75 | ||
76 | if (id) | |
77 | { | |
78 | // Look for special class names | |
79 | ||
80 | if (id == Id::__sizeof || id == Id::__xalignof || id == Id::_mangleof) | |
81 | error("illegal class name"); | |
82 | ||
83 | // BUG: What if this is the wrong TypeInfo, i.e. it is nested? | |
84 | if (id->toChars()[0] == 'T') | |
85 | { | |
86 | if (id == Id::TypeInfo) | |
87 | { | |
88 | if (!inObject) | |
89 | error("%s", msg); | |
90 | Type::dtypeinfo = this; | |
91 | } | |
92 | ||
93 | if (id == Id::TypeInfo_Class) | |
94 | { | |
95 | if (!inObject) | |
96 | error("%s", msg); | |
97 | Type::typeinfoclass = this; | |
98 | } | |
99 | ||
100 | if (id == Id::TypeInfo_Interface) | |
101 | { | |
102 | if (!inObject) | |
103 | error("%s", msg); | |
104 | Type::typeinfointerface = this; | |
105 | } | |
106 | ||
107 | if (id == Id::TypeInfo_Struct) | |
108 | { | |
109 | if (!inObject) | |
110 | error("%s", msg); | |
111 | Type::typeinfostruct = this; | |
112 | } | |
113 | ||
114 | if (id == Id::TypeInfo_Pointer) | |
115 | { | |
116 | if (!inObject) | |
117 | error("%s", msg); | |
118 | Type::typeinfopointer = this; | |
119 | } | |
120 | ||
121 | if (id == Id::TypeInfo_Array) | |
122 | { | |
123 | if (!inObject) | |
124 | error("%s", msg); | |
125 | Type::typeinfoarray = this; | |
126 | } | |
127 | ||
128 | if (id == Id::TypeInfo_StaticArray) | |
129 | { | |
130 | //if (!inObject) | |
131 | // Type::typeinfostaticarray->error("%s", msg); | |
132 | Type::typeinfostaticarray = this; | |
133 | } | |
134 | ||
135 | if (id == Id::TypeInfo_AssociativeArray) | |
136 | { | |
137 | if (!inObject) | |
138 | error("%s", msg); | |
139 | Type::typeinfoassociativearray = this; | |
140 | } | |
141 | ||
142 | if (id == Id::TypeInfo_Enum) | |
143 | { | |
144 | if (!inObject) | |
145 | error("%s", msg); | |
146 | Type::typeinfoenum = this; | |
147 | } | |
148 | ||
149 | if (id == Id::TypeInfo_Function) | |
150 | { | |
151 | if (!inObject) | |
152 | error("%s", msg); | |
153 | Type::typeinfofunction = this; | |
154 | } | |
155 | ||
156 | if (id == Id::TypeInfo_Delegate) | |
157 | { | |
158 | if (!inObject) | |
159 | error("%s", msg); | |
160 | Type::typeinfodelegate = this; | |
161 | } | |
162 | ||
163 | if (id == Id::TypeInfo_Tuple) | |
164 | { | |
165 | if (!inObject) | |
166 | error("%s", msg); | |
167 | Type::typeinfotypelist = this; | |
168 | } | |
169 | ||
170 | if (id == Id::TypeInfo_Const) | |
171 | { | |
172 | if (!inObject) | |
173 | error("%s", msg); | |
174 | Type::typeinfoconst = this; | |
175 | } | |
176 | ||
177 | if (id == Id::TypeInfo_Invariant) | |
178 | { | |
179 | if (!inObject) | |
180 | error("%s", msg); | |
181 | Type::typeinfoinvariant = this; | |
182 | } | |
183 | ||
184 | if (id == Id::TypeInfo_Shared) | |
185 | { | |
186 | if (!inObject) | |
187 | error("%s", msg); | |
188 | Type::typeinfoshared = this; | |
189 | } | |
190 | ||
191 | if (id == Id::TypeInfo_Wild) | |
192 | { | |
193 | if (!inObject) | |
194 | error("%s", msg); | |
195 | Type::typeinfowild = this; | |
196 | } | |
197 | ||
198 | if (id == Id::TypeInfo_Vector) | |
199 | { | |
200 | if (!inObject) | |
201 | error("%s", msg); | |
202 | Type::typeinfovector = this; | |
203 | } | |
204 | } | |
205 | ||
206 | if (id == Id::Object) | |
207 | { | |
208 | if (!inObject) | |
209 | error("%s", msg); | |
210 | object = this; | |
211 | } | |
212 | ||
213 | if (id == Id::Throwable) | |
214 | { | |
215 | if (!inObject) | |
216 | error("%s", msg); | |
217 | throwable = this; | |
218 | } | |
219 | ||
220 | if (id == Id::Exception) | |
221 | { | |
222 | if (!inObject) | |
223 | error("%s", msg); | |
224 | exception = this; | |
225 | } | |
226 | ||
227 | if (id == Id::Error) | |
228 | { | |
229 | if (!inObject) | |
230 | error("%s", msg); | |
231 | errorException = this; | |
232 | } | |
233 | ||
234 | if (id == Id::cpp_type_info_ptr) | |
235 | { | |
236 | if (!inObject) | |
237 | error("%s", msg); | |
238 | cpp_type_info_ptr = this; | |
239 | } | |
240 | } | |
241 | ||
242 | com = false; | |
b4c522fa IB |
243 | isscope = false; |
244 | isabstract = ABSfwdref; | |
245 | inuse = 0; | |
246 | baseok = BASEOKnone; | |
b4c522fa IB |
247 | cpp_type_info_ptr_sym = NULL; |
248 | } | |
249 | ||
250 | ClassDeclaration *ClassDeclaration::create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject) | |
251 | { | |
252 | return new ClassDeclaration(loc, id, baseclasses, members, inObject); | |
253 | } | |
254 | ||
255 | Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) | |
256 | { | |
257 | //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars()); | |
258 | ClassDeclaration *cd = | |
259 | s ? (ClassDeclaration *)s | |
260 | : new ClassDeclaration(loc, ident, NULL, NULL, false); | |
261 | ||
262 | cd->storage_class |= storage_class; | |
263 | ||
2cbc99d1 IB |
264 | cd->baseclasses->setDim(this->baseclasses->length); |
265 | for (size_t i = 0; i < cd->baseclasses->length; i++) | |
b4c522fa IB |
266 | { |
267 | BaseClass *b = (*this->baseclasses)[i]; | |
268 | BaseClass *b2 = new BaseClass(b->type->syntaxCopy()); | |
269 | (*cd->baseclasses)[i] = b2; | |
270 | } | |
271 | ||
272 | return ScopeDsymbol::syntaxCopy(cd); | |
273 | } | |
274 | ||
275 | Scope *ClassDeclaration::newScope(Scope *sc) | |
276 | { | |
277 | Scope *sc2 = AggregateDeclaration::newScope(sc); | |
278 | if (isCOMclass()) | |
279 | { | |
280 | if (global.params.isWindows) | |
281 | sc2->linkage = LINKwindows; | |
282 | else | |
283 | { | |
284 | /* This enables us to use COM objects under Linux and | |
285 | * work with things like XPCOM | |
286 | */ | |
287 | sc2->linkage = LINKc; | |
288 | } | |
289 | } | |
290 | return sc2; | |
291 | } | |
292 | ||
b4c522fa IB |
293 | /********************************************* |
294 | * Determine if 'this' is a base class of cd. | |
295 | * This is used to detect circular inheritance only. | |
296 | */ | |
297 | ||
298 | bool ClassDeclaration::isBaseOf2(ClassDeclaration *cd) | |
299 | { | |
300 | if (!cd) | |
301 | return false; | |
302 | //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); | |
2cbc99d1 | 303 | for (size_t i = 0; i < cd->baseclasses->length; i++) |
b4c522fa IB |
304 | { |
305 | BaseClass *b = (*cd->baseclasses)[i]; | |
306 | if (b->sym == this || isBaseOf2(b->sym)) | |
307 | return true; | |
308 | } | |
309 | return false; | |
310 | } | |
311 | ||
312 | /******************************************* | |
313 | * Determine if 'this' is a base class of cd. | |
314 | */ | |
315 | ||
316 | bool ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) | |
317 | { | |
318 | //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); | |
319 | if (poffset) | |
320 | *poffset = 0; | |
321 | while (cd) | |
322 | { | |
323 | /* cd->baseClass might not be set if cd is forward referenced. | |
324 | */ | |
956fba45 | 325 | if (!cd->baseClass && cd->semanticRun < PASSsemanticdone && !cd->isInterfaceDeclaration()) |
b4c522fa | 326 | { |
a3b38b77 | 327 | dsymbolSemantic(cd, NULL); |
956fba45 | 328 | if (!cd->baseClass && cd->semanticRun < PASSsemanticdone) |
b4c522fa IB |
329 | cd->error("base class is forward referenced by %s", toChars()); |
330 | } | |
331 | ||
332 | if (this == cd->baseClass) | |
333 | return true; | |
334 | ||
335 | cd = cd->baseClass; | |
336 | } | |
337 | return false; | |
338 | } | |
339 | ||
340 | /********************************************* | |
341 | * Determine if 'this' has complete base class information. | |
342 | * This is used to detect forward references in covariant overloads. | |
343 | */ | |
344 | ||
345 | bool ClassDeclaration::isBaseInfoComplete() | |
346 | { | |
347 | return baseok >= BASEOKdone; | |
348 | } | |
349 | ||
350 | Dsymbol *ClassDeclaration::search(const Loc &loc, Identifier *ident, int flags) | |
351 | { | |
352 | //printf("%s.ClassDeclaration::search('%s', flags=x%x)\n", toChars(), ident->toChars(), flags); | |
353 | ||
354 | //if (_scope) printf("%s baseok = %d\n", toChars(), baseok); | |
355 | if (_scope && baseok < BASEOKdone) | |
356 | { | |
357 | if (!inuse) | |
358 | { | |
359 | // must semantic on base class/interfaces | |
360 | ++inuse; | |
a3b38b77 | 361 | dsymbolSemantic(this, NULL); |
b4c522fa IB |
362 | --inuse; |
363 | } | |
364 | } | |
365 | ||
366 | if (!members || !symtab) // opaque or addMember is not yet done | |
367 | { | |
a3b38b77 | 368 | error("is forward referenced when looking for `%s`", ident->toChars()); |
b4c522fa IB |
369 | //*(char*)0=0; |
370 | return NULL; | |
371 | } | |
372 | ||
373 | Dsymbol *s = ScopeDsymbol::search(loc, ident, flags); | |
374 | ||
375 | // don't search imports of base classes | |
376 | if (flags & SearchImportsOnly) | |
377 | return s; | |
378 | ||
379 | if (!s) | |
380 | { | |
381 | // Search bases classes in depth-first, left to right order | |
382 | ||
2cbc99d1 | 383 | for (size_t i = 0; i < baseclasses->length; i++) |
b4c522fa IB |
384 | { |
385 | BaseClass *b = (*baseclasses)[i]; | |
386 | ||
387 | if (b->sym) | |
388 | { | |
389 | if (!b->sym->symtab) | |
390 | error("base %s is forward referenced", b->sym->ident->toChars()); | |
391 | else | |
392 | { | |
393 | s = b->sym->search(loc, ident, flags); | |
394 | if (!s) | |
395 | continue; | |
396 | else if (s == this) // happens if s is nested in this and derives from this | |
397 | s = NULL; | |
0a2ee409 | 398 | else if (!(flags & IgnoreSymbolVisibility) && !(s->prot().kind == Prot::protected_) && !symbolIsVisible(this, s)) |
b4c522fa IB |
399 | s = NULL; |
400 | else | |
401 | break; | |
402 | } | |
403 | } | |
404 | } | |
405 | } | |
406 | return s; | |
407 | } | |
408 | ||
409 | /************************************ | |
410 | * Search base classes in depth-first, left-to-right order for | |
411 | * a class or interface named 'ident'. | |
412 | * Stops at first found. Does not look for additional matches. | |
413 | * Params: | |
414 | * ident = identifier to search for | |
415 | * Returns: | |
416 | * ClassDeclaration if found, null if not | |
417 | */ | |
418 | ClassDeclaration *ClassDeclaration::searchBase(Identifier *ident) | |
419 | { | |
2cbc99d1 | 420 | for (size_t i = 0; i < baseclasses->length; i++) |
b4c522fa IB |
421 | { |
422 | BaseClass *b = (*baseclasses)[i]; | |
423 | ClassDeclaration *cdb = b->type->isClassHandle(); | |
424 | if (!cdb) // Bugzilla 10616 | |
425 | return NULL; | |
426 | if (cdb->ident->equals(ident)) | |
427 | return cdb; | |
428 | cdb = cdb->searchBase(ident); | |
429 | if (cdb) | |
430 | return cdb; | |
431 | } | |
432 | return NULL; | |
433 | } | |
434 | ||
435 | /**** | |
436 | * Runs through the inheritance graph to set the BaseClass.offset fields. | |
437 | * Recursive in order to account for the size of the interface classes, if they are | |
438 | * more than just interfaces. | |
439 | * Params: | |
440 | * cd = interface to look at | |
441 | * baseOffset = offset of where cd will be placed | |
442 | * Returns: | |
443 | * subset of instantiated size used by cd for interfaces | |
444 | */ | |
445 | static unsigned membersPlace(BaseClasses *vtblInterfaces, size_t &bi, ClassDeclaration *cd, unsigned baseOffset) | |
446 | { | |
447 | //printf(" membersPlace(%s, %d)\n", cd->toChars(), baseOffset); | |
448 | unsigned offset = baseOffset; | |
449 | ||
450 | for (size_t i = 0; i < cd->interfaces.length; i++) | |
451 | { | |
452 | BaseClass *b = cd->interfaces.ptr[i]; | |
453 | if (b->sym->sizeok != SIZEOKdone) | |
454 | b->sym->finalizeSize(); | |
455 | assert(b->sym->sizeok == SIZEOKdone); | |
456 | ||
457 | if (!b->sym->alignsize) | |
5905cbdb | 458 | b->sym->alignsize = target.ptrsize; |
b4c522fa | 459 | cd->alignmember(b->sym->alignsize, b->sym->alignsize, &offset); |
2cbc99d1 | 460 | assert(bi < vtblInterfaces->length); |
b4c522fa IB |
461 | BaseClass *bv = (*vtblInterfaces)[bi]; |
462 | if (b->sym->interfaces.length == 0) | |
463 | { | |
464 | //printf("\tvtblInterfaces[%d] b=%p b->sym = %s, offset = %d\n", bi, bv, bv->sym->toChars(), offset); | |
465 | bv->offset = offset; | |
466 | ++bi; | |
467 | // All the base interfaces down the left side share the same offset | |
468 | for (BaseClass *b2 = bv; b2->baseInterfaces.length; ) | |
469 | { | |
470 | b2 = &b2->baseInterfaces.ptr[0]; | |
471 | b2->offset = offset; | |
472 | //printf("\tvtblInterfaces[%d] b=%p sym = %s, offset = %d\n", bi, b2, b2->sym->toChars(), b2->offset); | |
473 | } | |
474 | } | |
475 | membersPlace(vtblInterfaces, bi, b->sym, offset); | |
476 | //printf(" %s size = %d\n", b->sym->toChars(), b->sym->structsize); | |
477 | offset += b->sym->structsize; | |
478 | if (cd->alignsize < b->sym->alignsize) | |
479 | cd->alignsize = b->sym->alignsize; | |
480 | } | |
481 | return offset - baseOffset; | |
482 | } | |
483 | ||
484 | void ClassDeclaration::finalizeSize() | |
485 | { | |
486 | assert(sizeok != SIZEOKdone); | |
487 | ||
488 | // Set the offsets of the fields and determine the size of the class | |
489 | if (baseClass) | |
490 | { | |
491 | assert(baseClass->sizeok == SIZEOKdone); | |
492 | ||
493 | alignsize = baseClass->alignsize; | |
494 | structsize = baseClass->structsize; | |
75f758a7 | 495 | if (isCPPclass() && global.params.isWindows) |
b4c522fa IB |
496 | structsize = (structsize + alignsize - 1) & ~(alignsize - 1); |
497 | } | |
498 | else if (isInterfaceDeclaration()) | |
499 | { | |
500 | if (interfaces.length == 0) | |
501 | { | |
5905cbdb IB |
502 | alignsize = target.ptrsize; |
503 | structsize = target.ptrsize; // allow room for __vptr | |
b4c522fa IB |
504 | } |
505 | } | |
506 | else | |
507 | { | |
5905cbdb IB |
508 | alignsize = target.ptrsize; |
509 | structsize = target.ptrsize; // allow room for __vptr | |
98866120 | 510 | if (hasMonitor()) |
5905cbdb | 511 | structsize += target.ptrsize; // allow room for __monitor |
b4c522fa IB |
512 | } |
513 | ||
514 | //printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok); | |
515 | size_t bi = 0; // index into vtblInterfaces[] | |
516 | ||
517 | // Add vptr's for any interfaces implemented by this class | |
518 | structsize += membersPlace(vtblInterfaces, bi, this, structsize); | |
519 | ||
520 | if (isInterfaceDeclaration()) | |
521 | { | |
522 | sizeok = SIZEOKdone; | |
523 | return; | |
524 | } | |
525 | ||
526 | // FIXME: Currently setFieldOffset functions need to increase fields | |
527 | // to calculate each variable offsets. It can be improved later. | |
528 | fields.setDim(0); | |
529 | ||
530 | unsigned offset = structsize; | |
2cbc99d1 | 531 | for (size_t i = 0; i < members->length; i++) |
b4c522fa IB |
532 | { |
533 | Dsymbol *s = (*members)[i]; | |
534 | s->setFieldOffset(this, &offset, false); | |
535 | } | |
536 | ||
537 | sizeok = SIZEOKdone; | |
538 | ||
539 | // Calculate fields[i]->overlapped | |
540 | checkOverlappedFields(); | |
541 | } | |
542 | ||
98866120 IB |
543 | /************** |
544 | * Returns: true if there's a __monitor field | |
545 | */ | |
546 | bool ClassDeclaration::hasMonitor() | |
547 | { | |
548 | return classKind == ClassKind::d; | |
549 | } | |
550 | ||
b4c522fa IB |
551 | /********************************************************** |
552 | * fd is in the vtbl[] for this class. | |
553 | * Return 1 if function is hidden (not findable through search). | |
554 | */ | |
555 | ||
556 | int isf(void *param, Dsymbol *s) | |
557 | { | |
558 | FuncDeclaration *fd = s->isFuncDeclaration(); | |
559 | if (!fd) | |
560 | return 0; | |
561 | //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars()); | |
562 | return (RootObject *)param == fd; | |
563 | } | |
564 | ||
565 | bool ClassDeclaration::isFuncHidden(FuncDeclaration *fd) | |
566 | { | |
4d814b69 | 567 | //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toPrettyChars()); |
b4c522fa IB |
568 | Dsymbol *s = search(Loc(), fd->ident, IgnoreAmbiguous | IgnoreErrors); |
569 | if (!s) | |
570 | { | |
571 | //printf("not found\n"); | |
572 | /* Because, due to a hack, if there are multiple definitions | |
573 | * of fd->ident, NULL is returned. | |
574 | */ | |
575 | return false; | |
576 | } | |
577 | s = s->toAlias(); | |
578 | OverloadSet *os = s->isOverloadSet(); | |
579 | if (os) | |
580 | { | |
2cbc99d1 | 581 | for (size_t i = 0; i < os->a.length; i++) |
b4c522fa IB |
582 | { |
583 | Dsymbol *s2 = os->a[i]; | |
584 | FuncDeclaration *f2 = s2->isFuncDeclaration(); | |
585 | if (f2 && overloadApply(f2, (void *)fd, &isf)) | |
586 | return false; | |
587 | } | |
588 | return true; | |
589 | } | |
590 | else | |
591 | { | |
592 | FuncDeclaration *fdstart = s->isFuncDeclaration(); | |
593 | //printf("%s fdstart = %p\n", s->kind(), fdstart); | |
594 | if (overloadApply(fdstart, (void *)fd, &isf)) | |
595 | return false; | |
596 | ||
597 | return !fd->parent->isTemplateMixin(); | |
598 | } | |
599 | } | |
600 | ||
601 | /**************** | |
602 | * Find virtual function matching identifier and type. | |
603 | * Used to build virtual function tables for interface implementations. | |
604 | */ | |
605 | ||
606 | FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) | |
607 | { | |
608 | //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars()); | |
609 | FuncDeclaration *fdmatch = NULL; | |
610 | FuncDeclaration *fdambig = NULL; | |
611 | ||
612 | ClassDeclaration *cd = this; | |
613 | Dsymbols *vtbl = &cd->vtbl; | |
614 | while (1) | |
615 | { | |
2cbc99d1 | 616 | for (size_t i = 0; i < vtbl->length; i++) |
b4c522fa IB |
617 | { |
618 | FuncDeclaration *fd = (*vtbl)[i]->isFuncDeclaration(); | |
619 | if (!fd) | |
620 | continue; // the first entry might be a ClassInfo | |
621 | ||
622 | //printf("\t[%d] = %s\n", i, fd->toChars()); | |
623 | if (ident == fd->ident && | |
624 | fd->type->covariant(tf) == 1) | |
625 | { | |
626 | //printf("fd->parent->isClassDeclaration() = %p\n", fd->parent->isClassDeclaration()); | |
627 | if (!fdmatch) | |
628 | goto Lfd; | |
629 | if (fd == fdmatch) | |
630 | goto Lfdmatch; | |
631 | ||
632 | { | |
633 | // Function type matcing: exact > covariant | |
634 | MATCH m1 = tf->equals(fd ->type) ? MATCHexact : MATCHnomatch; | |
635 | MATCH m2 = tf->equals(fdmatch->type) ? MATCHexact : MATCHnomatch; | |
636 | if (m1 > m2) | |
637 | goto Lfd; | |
638 | else if (m1 < m2) | |
639 | goto Lfdmatch; | |
640 | } | |
641 | ||
642 | { | |
643 | MATCH m1 = (tf->mod == fd ->type->mod) ? MATCHexact : MATCHnomatch; | |
644 | MATCH m2 = (tf->mod == fdmatch->type->mod) ? MATCHexact : MATCHnomatch; | |
645 | if (m1 > m2) | |
646 | goto Lfd; | |
647 | else if (m1 < m2) | |
648 | goto Lfdmatch; | |
649 | } | |
650 | ||
651 | { | |
652 | // The way of definition: non-mixin > mixin | |
653 | MATCH m1 = fd ->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch; | |
654 | MATCH m2 = fdmatch->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch; | |
655 | if (m1 > m2) | |
656 | goto Lfd; | |
657 | else if (m1 < m2) | |
658 | goto Lfdmatch; | |
659 | } | |
660 | ||
661 | fdambig = fd; | |
662 | //printf("Lambig fdambig = %s %s [%s]\n", fdambig->toChars(), fdambig->type->toChars(), fdambig->loc.toChars()); | |
663 | continue; | |
664 | ||
665 | Lfd: | |
666 | fdmatch = fd; | |
667 | fdambig = NULL; | |
668 | //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch->toChars(), fdmatch->type->toChars(), fdmatch->loc.toChars()); | |
669 | continue; | |
670 | ||
671 | Lfdmatch: | |
672 | continue; | |
673 | } | |
674 | //else printf("\t\t%d\n", fd->type->covariant(tf)); | |
675 | } | |
676 | if (!cd) | |
677 | break; | |
678 | vtbl = &cd->vtblFinal; | |
679 | cd = cd->baseClass; | |
680 | } | |
681 | ||
682 | if (fdambig) | |
683 | error("ambiguous virtual function %s", fdambig->toChars()); | |
684 | return fdmatch; | |
685 | } | |
686 | ||
b4c522fa IB |
687 | /**************************************** |
688 | */ | |
689 | ||
690 | bool ClassDeclaration::isCOMclass() const | |
691 | { | |
692 | return com; | |
693 | } | |
694 | ||
695 | bool ClassDeclaration::isCOMinterface() const | |
696 | { | |
697 | return false; | |
698 | } | |
699 | ||
700 | bool ClassDeclaration::isCPPclass() const | |
701 | { | |
75f758a7 | 702 | return classKind == ClassKind::cpp; |
b4c522fa IB |
703 | } |
704 | ||
705 | bool ClassDeclaration::isCPPinterface() const | |
706 | { | |
707 | return false; | |
708 | } | |
709 | ||
710 | ||
711 | /**************************************** | |
712 | */ | |
713 | ||
714 | bool ClassDeclaration::isAbstract() | |
715 | { | |
716 | if (isabstract != ABSfwdref) | |
717 | return isabstract == ABSyes; | |
718 | ||
719 | /* Bugzilla 11169: Resolve forward references to all class member functions, | |
720 | * and determine whether this class is abstract. | |
721 | */ | |
722 | struct SearchAbstract | |
723 | { | |
724 | static int fp(Dsymbol *s, void *) | |
725 | { | |
726 | FuncDeclaration *fd = s->isFuncDeclaration(); | |
727 | if (!fd) | |
728 | return 0; | |
729 | if (fd->storage_class & STCstatic) | |
730 | return 0; | |
731 | ||
732 | if (fd->_scope) | |
a3b38b77 | 733 | dsymbolSemantic(fd, NULL); |
b4c522fa IB |
734 | |
735 | if (fd->isAbstract()) | |
736 | return 1; | |
737 | return 0; | |
738 | } | |
739 | }; | |
740 | ||
2cbc99d1 | 741 | for (size_t i = 0; i < members->length; i++) |
b4c522fa IB |
742 | { |
743 | Dsymbol *s = (*members)[i]; | |
744 | if (s->apply(&SearchAbstract::fp, this)) | |
745 | { | |
746 | isabstract = ABSyes; | |
747 | return true; | |
748 | } | |
749 | } | |
750 | ||
751 | /* Iterate inherited member functions and check their abstract attribute. | |
752 | */ | |
2cbc99d1 | 753 | for (size_t i = 1; i < vtbl.length; i++) |
b4c522fa IB |
754 | { |
755 | FuncDeclaration *fd = vtbl[i]->isFuncDeclaration(); | |
756 | //if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd->loc.toChars(), fd->toChars()); | |
757 | if (!fd || fd->isAbstract()) | |
758 | { | |
759 | isabstract = ABSyes; | |
760 | return true; | |
761 | } | |
762 | } | |
763 | ||
764 | isabstract = ABSno; | |
765 | return false; | |
766 | } | |
767 | ||
768 | ||
769 | /**************************************** | |
770 | * Determine if slot 0 of the vtbl[] is reserved for something else. | |
771 | * For class objects, yes, this is where the classinfo ptr goes. | |
772 | * For COM interfaces, no. | |
773 | * For non-COM interfaces, yes, this is where the Interface ptr goes. | |
774 | * Returns: | |
775 | * 0 vtbl[0] is first virtual function pointer | |
776 | * 1 vtbl[0] is classinfo/interfaceinfo pointer | |
777 | */ | |
778 | ||
779 | int ClassDeclaration::vtblOffset() const | |
780 | { | |
75f758a7 | 781 | return classKind == ClassKind::cpp ? 0 : 1; |
b4c522fa IB |
782 | } |
783 | ||
784 | /**************************************** | |
785 | */ | |
786 | ||
f9ab59ff | 787 | const char *ClassDeclaration::kind() const |
b4c522fa IB |
788 | { |
789 | return "class"; | |
790 | } | |
791 | ||
792 | /**************************************** | |
793 | */ | |
794 | ||
795 | void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses) | |
796 | { | |
797 | aclasses->push(this); | |
798 | } | |
799 | ||
800 | /********************************* InterfaceDeclaration ****************************/ | |
801 | ||
802 | InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) | |
803 | : ClassDeclaration(loc, id, baseclasses, NULL, false) | |
804 | { | |
805 | if (id == Id::IUnknown) // IUnknown is the root of all COM interfaces | |
806 | { | |
807 | com = true; | |
75f758a7 | 808 | classKind = ClassKind::cpp; // IUnknown is also a C++ interface |
b4c522fa IB |
809 | } |
810 | } | |
811 | ||
812 | Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s) | |
813 | { | |
814 | InterfaceDeclaration *id = | |
815 | s ? (InterfaceDeclaration *)s | |
816 | : new InterfaceDeclaration(loc, ident, NULL); | |
817 | return ClassDeclaration::syntaxCopy(id); | |
818 | } | |
819 | ||
820 | Scope *InterfaceDeclaration::newScope(Scope *sc) | |
821 | { | |
822 | Scope *sc2 = ClassDeclaration::newScope(sc); | |
823 | if (com) | |
824 | sc2->linkage = LINKwindows; | |
75f758a7 | 825 | else if (classKind == ClassKind::cpp) |
b4c522fa | 826 | sc2->linkage = LINKcpp; |
75f758a7 | 827 | else if (classKind == ClassKind::objc) |
b4c522fa IB |
828 | sc2->linkage = LINKobjc; |
829 | return sc2; | |
830 | } | |
831 | ||
b4c522fa IB |
832 | /******************************************* |
833 | * Determine if 'this' is a base class of cd. | |
834 | * (Actually, if it is an interface supported by cd) | |
835 | * Output: | |
836 | * *poffset offset to start of class | |
837 | * OFFSET_RUNTIME must determine offset at runtime | |
838 | * Returns: | |
839 | * false not a base | |
840 | * true is a base | |
841 | */ | |
842 | ||
843 | bool InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) | |
844 | { | |
845 | //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars()); | |
846 | assert(!baseClass); | |
847 | for (size_t j = 0; j < cd->interfaces.length; j++) | |
848 | { | |
849 | BaseClass *b = cd->interfaces.ptr[j]; | |
850 | ||
851 | //printf("\tX base %s\n", b->sym->toChars()); | |
852 | if (this == b->sym) | |
853 | { | |
4d814b69 | 854 | //printf("\tfound at offset %d\n", b->offset); |
b4c522fa IB |
855 | if (poffset) |
856 | { | |
857 | // don't return incorrect offsets https://issues.dlang.org/show_bug.cgi?id=16980 | |
858 | *poffset = cd->sizeok == SIZEOKdone ? b->offset : OFFSET_FWDREF; | |
859 | } | |
860 | //printf("\tfound at offset %d\n", b->offset); | |
861 | return true; | |
862 | } | |
863 | if (isBaseOf(b, poffset)) | |
864 | return true; | |
865 | } | |
866 | ||
867 | if (cd->baseClass && isBaseOf(cd->baseClass, poffset)) | |
868 | return true; | |
869 | ||
870 | if (poffset) | |
871 | *poffset = 0; | |
872 | return false; | |
873 | } | |
874 | ||
875 | bool InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset) | |
876 | { | |
877 | //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->sym->toChars()); | |
878 | for (size_t j = 0; j < bc->baseInterfaces.length; j++) | |
879 | { | |
880 | BaseClass *b = &bc->baseInterfaces.ptr[j]; | |
881 | ||
882 | //printf("\tY base %s\n", b->sym->toChars()); | |
883 | if (this == b->sym) | |
884 | { | |
885 | //printf("\tfound at offset %d\n", b->offset); | |
886 | if (poffset) | |
887 | { | |
888 | *poffset = b->offset; | |
889 | } | |
890 | return true; | |
891 | } | |
892 | if (isBaseOf(b, poffset)) | |
893 | { | |
894 | return true; | |
895 | } | |
896 | } | |
897 | if (poffset) | |
898 | *poffset = 0; | |
899 | return false; | |
900 | } | |
901 | ||
902 | /**************************************** | |
903 | * Determine if slot 0 of the vtbl[] is reserved for something else. | |
904 | * For class objects, yes, this is where the ClassInfo ptr goes. | |
905 | * For COM interfaces, no. | |
906 | * For non-COM interfaces, yes, this is where the Interface ptr goes. | |
907 | */ | |
908 | ||
909 | int InterfaceDeclaration::vtblOffset() const | |
910 | { | |
911 | if (isCOMinterface() || isCPPinterface()) | |
912 | return 0; | |
913 | return 1; | |
914 | } | |
915 | ||
916 | bool InterfaceDeclaration::isCOMinterface() const | |
917 | { | |
918 | return com; | |
919 | } | |
920 | ||
921 | bool InterfaceDeclaration::isCPPinterface() const | |
922 | { | |
75f758a7 | 923 | return classKind == ClassKind::cpp; |
b4c522fa IB |
924 | } |
925 | ||
926 | /******************************************* | |
927 | */ | |
928 | ||
f9ab59ff | 929 | const char *InterfaceDeclaration::kind() const |
b4c522fa IB |
930 | { |
931 | return "interface"; | |
932 | } | |
933 | ||
934 | ||
935 | /******************************** BaseClass *****************************/ | |
936 | ||
937 | BaseClass::BaseClass() | |
938 | { | |
939 | this->type = NULL; | |
940 | this->sym = NULL; | |
941 | this->offset = 0; | |
942 | ||
943 | this->baseInterfaces.length = 0; | |
944 | this->baseInterfaces.ptr = NULL; | |
945 | } | |
946 | ||
947 | BaseClass::BaseClass(Type *type) | |
948 | { | |
949 | //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); | |
950 | this->type = type; | |
951 | this->sym = NULL; | |
952 | this->offset = 0; | |
953 | ||
954 | this->baseInterfaces.length = 0; | |
955 | this->baseInterfaces.ptr = NULL; | |
956 | } | |
957 | ||
958 | /**************************************** | |
959 | * Fill in vtbl[] for base class based on member functions of class cd. | |
960 | * Input: | |
961 | * vtbl if !=NULL, fill it in | |
962 | * newinstance !=0 means all entries must be filled in by members | |
963 | * of cd, not members of any base classes of cd. | |
964 | * Returns: | |
965 | * true if any entries were filled in by members of cd (not exclusively | |
966 | * by base classes) | |
967 | */ | |
968 | ||
969 | bool BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance) | |
970 | { | |
971 | bool result = false; | |
972 | ||
973 | //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", sym->toChars(), cd->toChars()); | |
974 | if (vtbl) | |
2cbc99d1 | 975 | vtbl->setDim(sym->vtbl.length); |
b4c522fa IB |
976 | |
977 | // first entry is ClassInfo reference | |
2cbc99d1 | 978 | for (size_t j = sym->vtblOffset(); j < sym->vtbl.length; j++) |
b4c522fa IB |
979 | { |
980 | FuncDeclaration *ifd = sym->vtbl[j]->isFuncDeclaration(); | |
981 | FuncDeclaration *fd; | |
982 | TypeFunction *tf; | |
983 | ||
984 | //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null"); | |
985 | ||
986 | assert(ifd); | |
987 | // Find corresponding function in this class | |
4d814b69 | 988 | tf = ifd->type->toTypeFunction(); |
b4c522fa IB |
989 | fd = cd->findFunc(ifd->ident, tf); |
990 | if (fd && !fd->isAbstract()) | |
991 | { | |
992 | //printf(" found\n"); | |
993 | // Check that calling conventions match | |
994 | if (fd->linkage != ifd->linkage) | |
995 | fd->error("linkage doesn't match interface function"); | |
996 | ||
997 | // Check that it is current | |
998 | //printf("newinstance = %d fd->toParent() = %s ifd->toParent() = %s\n", | |
999 | //newinstance, fd->toParent()->toChars(), ifd->toParent()->toChars()); | |
1000 | if (newinstance && fd->toParent() != cd && ifd->toParent() == sym) | |
a3b38b77 | 1001 | cd->error("interface function `%s` is not implemented", ifd->toFullSignature()); |
b4c522fa IB |
1002 | |
1003 | if (fd->toParent() == cd) | |
1004 | result = true; | |
1005 | } | |
1006 | else | |
1007 | { | |
1008 | //printf(" not found %p\n", fd); | |
1009 | // BUG: should mark this class as abstract? | |
1010 | if (!cd->isAbstract()) | |
a3b38b77 | 1011 | cd->error("interface function `%s` is not implemented", ifd->toFullSignature()); |
b4c522fa IB |
1012 | |
1013 | fd = NULL; | |
1014 | } | |
1015 | if (vtbl) | |
1016 | (*vtbl)[j] = fd; | |
1017 | } | |
1018 | ||
1019 | return result; | |
1020 | } | |
1021 | ||
1022 | void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces) | |
1023 | { | |
1024 | //printf("+copyBaseInterfaces(), %s\n", sym->toChars()); | |
1025 | // if (baseInterfaces.length) | |
1026 | // return; | |
1027 | ||
1028 | baseInterfaces.length = sym->interfaces.length; | |
1029 | baseInterfaces.ptr = (BaseClass *)mem.xcalloc(baseInterfaces.length, sizeof(BaseClass)); | |
1030 | ||
1031 | //printf("%s.copyBaseInterfaces()\n", sym->toChars()); | |
1032 | for (size_t i = 0; i < baseInterfaces.length; i++) | |
1033 | { | |
1034 | void *pb = &baseInterfaces.ptr[i]; | |
1035 | BaseClass *b2 = sym->interfaces.ptr[i]; | |
1036 | ||
2cbc99d1 | 1037 | assert(b2->vtbl.length == 0); // should not be filled yet |
b4c522fa IB |
1038 | BaseClass *b = (BaseClass *)memcpy(pb, b2, sizeof(BaseClass)); |
1039 | ||
1040 | if (i) // single inheritance is i==0 | |
1041 | vtblInterfaces->push(b); // only need for M.I. | |
1042 | b->copyBaseInterfaces(vtblInterfaces); | |
1043 | } | |
1044 | //printf("-copyBaseInterfaces\n"); | |
1045 | } |