Mercurial > projects > ldc
annotate dmd/class.c @ 1168:ab186e535e72
A different fix to #218 and DMD2682 that does not lead to constant folding regressions.
Fixes run/const_15, run/c/const_16_B.
The price is removing the lvalueness of struct literals. If it turns out too
much code depends on this behavior or we don't want to break with DMD, we
could keep struct literals as lvalues and instead convert struct literals used
as expression initializers into struct initializers.
author | Christian Kamm <kamm incasoftware de> |
---|---|
date | Sun, 29 Mar 2009 11:43:45 +0200 |
parents | 1860414bf3b7 |
children | e961851fb8be |
rev | line source |
---|---|
159 | 1 |
2 // Compiler implementation of the D programming language | |
3 // Copyright (c) 1999-2008 by Digital Mars | |
4 // All Rights Reserved | |
5 // written by Walter Bright | |
6 // http://www.digitalmars.com | |
7 // License for redistribution is by either the Artistic License | |
8 // in artistic.txt, or the GNU General Public License in gnu.txt. | |
9 // See the included readme.txt for details. | |
10 | |
11 #include <stdio.h> | |
12 #include <stdlib.h> | |
13 #include <assert.h> | |
14 | |
15 #include "root.h" | |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
875
diff
changeset
|
16 #include "rmem.h" |
159 | 17 |
18 #include "enum.h" | |
19 #include "init.h" | |
20 #include "attrib.h" | |
21 #include "declaration.h" | |
22 #include "aggregate.h" | |
23 #include "id.h" | |
24 #include "mtype.h" | |
25 #include "scope.h" | |
26 #include "module.h" | |
27 #include "expression.h" | |
28 #include "statement.h" | |
29 | |
30 /********************************* ClassDeclaration ****************************/ | |
31 | |
32 ClassDeclaration *ClassDeclaration::classinfo; | |
33 ClassDeclaration *ClassDeclaration::object; | |
34 | |
35 ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) | |
36 : AggregateDeclaration(loc, id) | |
37 { | |
38 static char msg[] = "only object.d can define this reserved class name"; | |
39 | |
40 if (baseclasses) | |
41 this->baseclasses = *baseclasses; | |
42 baseClass = NULL; | |
43 | |
44 interfaces_dim = 0; | |
45 interfaces = NULL; | |
46 | |
47 vtblInterfaces = NULL; | |
48 | |
49 //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses.dim); | |
50 | |
51 // For forward references | |
52 type = new TypeClass(this); | |
53 handle = type; | |
54 | |
55 ctor = NULL; | |
56 defaultCtor = NULL; | |
57 staticCtor = NULL; | |
58 staticDtor = NULL; | |
59 | |
1146
1860414bf3b7
* Moved ir/irsymbol.cpp/h into ir/irdsymbol.cpp/h.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
1103
diff
changeset
|
60 #if IN_DMD |
159 | 61 vtblsym = NULL; |
1146
1860414bf3b7
* Moved ir/irsymbol.cpp/h into ir/irdsymbol.cpp/h.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
1103
diff
changeset
|
62 #endif |
159 | 63 vclassinfo = NULL; |
64 | |
65 if (id) | |
66 { // Look for special class names | |
67 | |
68 if (id == Id::__sizeof || id == Id::alignof || id == Id::mangleof) | |
69 error("illegal class name"); | |
70 | |
71 // BUG: What if this is the wrong TypeInfo, i.e. it is nested? | |
72 if (id->toChars()[0] == 'T') | |
73 { | |
74 if (id == Id::TypeInfo) | |
75 { if (Type::typeinfo) | |
76 Type::typeinfo->error("%s", msg); | |
77 Type::typeinfo = this; | |
78 } | |
79 | |
80 if (id == Id::TypeInfo_Class) | |
81 { if (Type::typeinfoclass) | |
82 Type::typeinfoclass->error("%s", msg); | |
83 Type::typeinfoclass = this; | |
84 } | |
85 | |
86 if (id == Id::TypeInfo_Interface) | |
87 { if (Type::typeinfointerface) | |
88 Type::typeinfointerface->error("%s", msg); | |
89 Type::typeinfointerface = this; | |
90 } | |
91 | |
92 if (id == Id::TypeInfo_Struct) | |
93 { if (Type::typeinfostruct) | |
94 Type::typeinfostruct->error("%s", msg); | |
95 Type::typeinfostruct = this; | |
96 } | |
97 | |
98 if (id == Id::TypeInfo_Typedef) | |
99 { if (Type::typeinfotypedef) | |
100 Type::typeinfotypedef->error("%s", msg); | |
101 Type::typeinfotypedef = this; | |
102 } | |
103 | |
104 if (id == Id::TypeInfo_Pointer) | |
105 { if (Type::typeinfopointer) | |
106 Type::typeinfopointer->error("%s", msg); | |
107 Type::typeinfopointer = this; | |
108 } | |
109 | |
110 if (id == Id::TypeInfo_Array) | |
111 { if (Type::typeinfoarray) | |
112 Type::typeinfoarray->error("%s", msg); | |
113 Type::typeinfoarray = this; | |
114 } | |
115 | |
116 if (id == Id::TypeInfo_StaticArray) | |
117 { //if (Type::typeinfostaticarray) | |
118 //Type::typeinfostaticarray->error("%s", msg); | |
119 Type::typeinfostaticarray = this; | |
120 } | |
121 | |
122 if (id == Id::TypeInfo_AssociativeArray) | |
123 { if (Type::typeinfoassociativearray) | |
124 Type::typeinfoassociativearray->error("%s", msg); | |
125 Type::typeinfoassociativearray = this; | |
126 } | |
127 | |
128 if (id == Id::TypeInfo_Enum) | |
129 { if (Type::typeinfoenum) | |
130 Type::typeinfoenum->error("%s", msg); | |
131 Type::typeinfoenum = this; | |
132 } | |
133 | |
134 if (id == Id::TypeInfo_Function) | |
135 { if (Type::typeinfofunction) | |
136 Type::typeinfofunction->error("%s", msg); | |
137 Type::typeinfofunction = this; | |
138 } | |
139 | |
140 if (id == Id::TypeInfo_Delegate) | |
141 { if (Type::typeinfodelegate) | |
142 Type::typeinfodelegate->error("%s", msg); | |
143 Type::typeinfodelegate = this; | |
144 } | |
145 | |
146 if (id == Id::TypeInfo_Tuple) | |
147 { if (Type::typeinfotypelist) | |
148 Type::typeinfotypelist->error("%s", msg); | |
149 Type::typeinfotypelist = this; | |
150 } | |
151 | |
336 | 152 #if DMDV2 |
159 | 153 if (id == Id::TypeInfo_Const) |
154 { if (Type::typeinfoconst) | |
155 Type::typeinfoconst->error("%s", msg); | |
156 Type::typeinfoconst = this; | |
157 } | |
158 | |
159 if (id == Id::TypeInfo_Invariant) | |
160 { if (Type::typeinfoinvariant) | |
161 Type::typeinfoinvariant->error("%s", msg); | |
162 Type::typeinfoinvariant = this; | |
163 } | |
164 #endif | |
165 } | |
166 | |
167 if (id == Id::Object) | |
168 { if (object) | |
169 object->error("%s", msg); | |
170 object = this; | |
171 } | |
172 | |
173 if (id == Id::ClassInfo) | |
174 { if (classinfo) | |
175 classinfo->error("%s", msg); | |
176 classinfo = this; | |
177 } | |
178 | |
179 if (id == Id::ModuleInfo) | |
180 { if (Module::moduleinfo) | |
181 Module::moduleinfo->error("%s", msg); | |
182 Module::moduleinfo = this; | |
183 } | |
184 } | |
185 | |
186 com = 0; | |
187 isauto = 0; | |
188 isabstract = 0; | |
189 isnested = 0; | |
190 vthis = NULL; | |
191 inuse = 0; | |
192 } | |
193 | |
194 Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) | |
195 { | |
196 ClassDeclaration *cd; | |
197 | |
198 //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars()); | |
199 if (s) | |
200 cd = (ClassDeclaration *)s; | |
201 else | |
202 cd = new ClassDeclaration(loc, ident, NULL); | |
203 | |
204 cd->storage_class |= storage_class; | |
205 | |
206 cd->baseclasses.setDim(this->baseclasses.dim); | |
207 for (int i = 0; i < cd->baseclasses.dim; i++) | |
208 { | |
209 BaseClass *b = (BaseClass *)this->baseclasses.data[i]; | |
210 BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); | |
211 cd->baseclasses.data[i] = b2; | |
212 } | |
213 | |
214 ScopeDsymbol::syntaxCopy(cd); | |
215 return cd; | |
216 } | |
217 | |
218 void ClassDeclaration::semantic(Scope *sc) | |
219 { int i; | |
220 unsigned offset; | |
221 | |
222 //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); | |
223 //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : ""); | |
224 //printf("sc->stc = %x\n", sc->stc); | |
225 | |
226 //{ static int n; if (++n == 20) *(char*)0=0; } | |
227 | |
228 if (!ident) // if anonymous class | |
229 { char *id = "__anonclass"; | |
230 | |
231 ident = Identifier::generateId(id); | |
232 } | |
233 | |
234 if (!scope) | |
235 { | |
236 if (!parent && sc->parent && !sc->parent->isModule()) | |
237 parent = sc->parent; | |
238 | |
239 type = type->semantic(loc, sc); | |
240 handle = handle->semantic(loc, sc); | |
241 } | |
242 if (!members) // if forward reference | |
243 { //printf("\tclass '%s' is forward referenced\n", toChars()); | |
244 return; | |
245 } | |
246 if (symtab) | |
247 { if (!scope) | |
248 { //printf("\tsemantic for '%s' is already completed\n", toChars()); | |
249 return; // semantic() already completed | |
250 } | |
251 } | |
252 else | |
253 symtab = new DsymbolTable(); | |
254 | |
255 Scope *scx = NULL; | |
256 if (scope) | |
257 { sc = scope; | |
258 scx = scope; // save so we don't make redundant copies | |
259 scope = NULL; | |
260 } | |
261 #ifdef IN_GCC | |
262 methods.setDim(0); | |
263 #endif | |
264 | |
265 if (sc->stc & STCdeprecated) | |
336 | 266 { |
159 | 267 isdeprecated = 1; |
268 } | |
269 | |
270 // Expand any tuples in baseclasses[] | |
271 for (i = 0; i < baseclasses.dim; ) | |
272 { BaseClass *b = (BaseClass *)baseclasses.data[i]; | |
273 b->type = b->type->semantic(loc, sc); | |
274 Type *tb = b->type->toBasetype(); | |
275 | |
276 if (tb->ty == Ttuple) | |
277 { TypeTuple *tup = (TypeTuple *)tb; | |
278 enum PROT protection = b->protection; | |
279 baseclasses.remove(i); | |
280 size_t dim = Argument::dim(tup->arguments); | |
281 for (size_t j = 0; j < dim; j++) | |
282 { Argument *arg = Argument::getNth(tup->arguments, j); | |
283 b = new BaseClass(arg->type, protection); | |
284 baseclasses.insert(i + j, b); | |
285 } | |
286 } | |
287 else | |
288 i++; | |
289 } | |
290 | |
291 // See if there's a base class as first in baseclasses[] | |
292 if (baseclasses.dim) | |
293 { TypeClass *tc; | |
294 BaseClass *b; | |
295 Type *tb; | |
296 | |
297 b = (BaseClass *)baseclasses.data[0]; | |
298 //b->type = b->type->semantic(loc, sc); | |
299 tb = b->type->toBasetype(); | |
300 if (tb->ty != Tclass) | |
301 { error("base type must be class or interface, not %s", b->type->toChars()); | |
302 baseclasses.remove(0); | |
303 } | |
304 else | |
305 { | |
306 tc = (TypeClass *)(tb); | |
336 | 307 |
159 | 308 if (tc->sym->isDeprecated()) |
309 { | |
310 if (!isDeprecated()) | |
311 { | |
312 // Deriving from deprecated class makes this one deprecated too | |
313 isdeprecated = 1; | |
314 | |
315 tc->checkDeprecated(loc, sc); | |
316 } | |
317 } | |
318 | |
319 if (tc->sym->isInterfaceDeclaration()) | |
320 ; | |
321 else | |
322 { | |
323 for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass) | |
324 { | |
325 if (cdb == this) | |
326 { | |
327 error("circular inheritance"); | |
328 baseclasses.remove(0); | |
329 goto L7; | |
330 } | |
331 } | |
332 if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0) | |
333 { | |
334 //error("forward reference of base class %s", baseClass->toChars()); | |
335 // Forward reference of base class, try again later | |
336 //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars()); | |
337 scope = scx ? scx : new Scope(*sc); | |
338 scope->setNoFree(); | |
339 scope->module->addDeferredSemantic(this); | |
340 return; | |
341 } | |
342 else | |
343 { baseClass = tc->sym; | |
344 b->base = baseClass; | |
345 } | |
346 L7: ; | |
347 } | |
348 } | |
349 } | |
350 | |
351 // Treat the remaining entries in baseclasses as interfaces | |
352 // Check for errors, handle forward references | |
353 for (i = (baseClass ? 1 : 0); i < baseclasses.dim; ) | |
354 { TypeClass *tc; | |
355 BaseClass *b; | |
356 Type *tb; | |
357 | |
358 b = (BaseClass *)baseclasses.data[i]; | |
359 b->type = b->type->semantic(loc, sc); | |
360 tb = b->type->toBasetype(); | |
361 if (tb->ty == Tclass) | |
362 tc = (TypeClass *)tb; | |
363 else | |
364 tc = NULL; | |
365 if (!tc || !tc->sym->isInterfaceDeclaration()) | |
366 { | |
367 error("base type must be interface, not %s", b->type->toChars()); | |
368 baseclasses.remove(i); | |
369 continue; | |
370 } | |
371 else | |
372 { | |
373 if (tc->sym->isDeprecated()) | |
374 { | |
375 if (!isDeprecated()) | |
376 { | |
377 // Deriving from deprecated class makes this one deprecated too | |
378 isdeprecated = 1; | |
379 | |
380 tc->checkDeprecated(loc, sc); | |
381 } | |
382 } | |
383 | |
384 // Check for duplicate interfaces | |
385 for (size_t j = (baseClass ? 1 : 0); j < i; j++) | |
386 { | |
387 BaseClass *b2 = (BaseClass *)baseclasses.data[j]; | |
388 if (b2->base == tc->sym) | |
389 error("inherits from duplicate interface %s", b2->base->toChars()); | |
390 } | |
391 | |
392 b->base = tc->sym; | |
393 if (!b->base->symtab || b->base->scope) | |
394 { | |
395 //error("forward reference of base class %s", baseClass->toChars()); | |
396 // Forward reference of base, try again later | |
397 //printf("\ttry later, forward reference of base %s\n", baseClass->toChars()); | |
398 scope = scx ? scx : new Scope(*sc); | |
399 scope->setNoFree(); | |
400 scope->module->addDeferredSemantic(this); | |
401 return; | |
402 } | |
403 } | |
404 i++; | |
405 } | |
406 | |
407 | |
408 // If no base class, and this is not an Object, use Object as base class | |
409 if (!baseClass && ident != Id::Object) | |
410 { | |
411 // BUG: what if Object is redefined in an inner scope? | |
412 Type *tbase = new TypeIdentifier(0, Id::Object); | |
413 BaseClass *b; | |
414 TypeClass *tc; | |
415 Type *bt; | |
416 | |
417 if (!object) | |
418 { | |
419 error("missing or corrupt object.d"); | |
420 fatal(); | |
421 } | |
422 bt = tbase->semantic(loc, sc)->toBasetype(); | |
423 b = new BaseClass(bt, PROTpublic); | |
424 baseclasses.shift(b); | |
425 assert(b->type->ty == Tclass); | |
426 tc = (TypeClass *)(b->type); | |
427 baseClass = tc->sym; | |
428 assert(!baseClass->isInterfaceDeclaration()); | |
429 b->base = baseClass; | |
430 } | |
431 | |
432 interfaces_dim = baseclasses.dim; | |
433 interfaces = (BaseClass **)baseclasses.data; | |
434 | |
435 | |
436 if (baseClass) | |
437 { | |
438 if (baseClass->storage_class & STCfinal) | |
439 error("cannot inherit from final class %s", baseClass->toChars()); | |
440 | |
441 interfaces_dim--; | |
442 interfaces++; | |
443 | |
444 // Copy vtbl[] from base class | |
445 vtbl.setDim(baseClass->vtbl.dim); | |
446 memcpy(vtbl.data, baseClass->vtbl.data, sizeof(void *) * vtbl.dim); | |
447 | |
448 // Inherit properties from base class | |
449 com = baseClass->isCOMclass(); | |
450 isauto = baseClass->isauto; | |
451 vthis = baseClass->vthis; | |
452 } | |
453 else | |
454 { | |
455 // No base class, so this is the root of the class hierarchy | |
456 vtbl.setDim(0); | |
457 vtbl.push(this); // leave room for classinfo as first member | |
458 } | |
459 | |
460 protection = sc->protection; | |
461 storage_class |= sc->stc; | |
462 | |
463 if (sizeok == 0) | |
464 { | |
465 interfaceSemantic(sc); | |
466 | |
467 for (i = 0; i < members->dim; i++) | |
468 { | |
469 Dsymbol *s = (Dsymbol *)members->data[i]; | |
470 s->addMember(sc, this, 1); | |
471 } | |
472 | |
473 /* If this is a nested class, add the hidden 'this' | |
474 * member which is a pointer to the enclosing scope. | |
475 */ | |
476 if (vthis) // if inheriting from nested class | |
477 { // Use the base class's 'this' member | |
478 isnested = 1; | |
479 if (storage_class & STCstatic) | |
480 error("static class cannot inherit from nested class %s", baseClass->toChars()); | |
481 if (toParent2() != baseClass->toParent2()) | |
658
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
482 { |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
483 if (toParent2()) |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
484 { |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
485 error("is nested within %s, but super class %s is nested within %s", |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
486 toParent2()->toChars(), |
159 | 487 baseClass->toChars(), |
658
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
488 baseClass->toParent2()->toChars()); |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
489 } |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
490 else |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
491 { |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
492 error("is not nested, but super class %s is nested within %s", |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
493 baseClass->toChars(), |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
494 baseClass->toParent2()->toChars()); |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
495 } |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
496 isnested = 0; |
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
497 } |
159 | 498 } |
499 else if (!(storage_class & STCstatic)) | |
500 { Dsymbol *s = toParent2(); | |
501 if (s) | |
502 { | |
503 ClassDeclaration *cd = s->isClassDeclaration(); | |
504 FuncDeclaration *fd = s->isFuncDeclaration(); | |
505 | |
506 | |
507 if (cd || fd) | |
508 { isnested = 1; | |
509 Type *t; | |
510 if (cd) | |
511 t = cd->type; | |
512 else if (fd) | |
513 { AggregateDeclaration *ad = fd->isMember2(); | |
514 if (ad) | |
515 t = ad->handle; | |
516 else | |
517 { | |
518 t = new TypePointer(Type::tvoid); | |
519 t = t->semantic(0, sc); | |
520 } | |
521 } | |
522 else | |
523 assert(0); | |
524 assert(!vthis); | |
525 vthis = new ThisDeclaration(t); | |
526 members->push(vthis); | |
527 } | |
528 } | |
529 } | |
530 } | |
531 | |
532 if (storage_class & (STCauto | STCscope)) | |
533 isauto = 1; | |
534 if (storage_class & STCabstract) | |
535 isabstract = 1; | |
536 | |
537 sc = sc->push(this); | |
538 sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | | |
539 STCabstract | STCdeprecated); | |
540 sc->parent = this; | |
541 sc->inunion = 0; | |
542 | |
543 if (isCOMclass()) | |
875
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
809
diff
changeset
|
544 { |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
809
diff
changeset
|
545 #if _WIN32 |
159 | 546 sc->linkage = LINKwindows; |
875
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
809
diff
changeset
|
547 #else |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
809
diff
changeset
|
548 /* This enables us to use COM objects under Linux and |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
809
diff
changeset
|
549 * work with things like XPCOM |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
809
diff
changeset
|
550 */ |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
809
diff
changeset
|
551 sc->linkage = LINKc; |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
809
diff
changeset
|
552 #endif |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
809
diff
changeset
|
553 } |
159 | 554 sc->protection = PROTpublic; |
555 sc->explicitProtection = 0; | |
556 sc->structalign = 8; | |
557 structalign = sc->structalign; | |
558 if (baseClass) | |
559 { sc->offset = baseClass->structsize; | |
560 alignsize = baseClass->alignsize; | |
561 // if (isnested) | |
562 // sc->offset += PTRSIZE; // room for uplevel context pointer | |
563 } | |
564 else | |
809
69a5e4a6fc0f
Changed some hardcoded offset/alignment for classes in DMD, broke offsets for 64bits.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
658
diff
changeset
|
565 { sc->offset = 2*PTRSIZE; // allow room for vptr[] and monitor |
69a5e4a6fc0f
Changed some hardcoded offset/alignment for classes in DMD, broke offsets for 64bits.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
658
diff
changeset
|
566 alignsize = PTRSIZE; |
159 | 567 } |
568 structsize = sc->offset; | |
569 Scope scsave = *sc; | |
570 int members_dim = members->dim; | |
571 sizeok = 0; | |
572 for (i = 0; i < members_dim; i++) | |
573 { | |
574 Dsymbol *s = (Dsymbol *)members->data[i]; | |
575 s->semantic(sc); | |
576 } | |
577 | |
578 if (sizeok == 2) | |
579 { // semantic() failed because of forward references. | |
580 // Unwind what we did, and defer it for later | |
581 fields.setDim(0); | |
582 structsize = 0; | |
583 alignsize = 0; | |
584 structalign = 0; | |
585 | |
586 sc = sc->pop(); | |
587 | |
588 scope = scx ? scx : new Scope(*sc); | |
589 scope->setNoFree(); | |
590 scope->module->addDeferredSemantic(this); | |
591 | |
336 | 592 //printf("\tsemantic('%s') failed due to forward references\n", toChars()); |
159 | 593 return; |
594 } | |
595 | |
596 //printf("\tsemantic('%s') successful\n", toChars()); | |
597 | |
598 structsize = sc->offset; | |
599 //members->print(); | |
600 | |
601 /* Look for special member functions. | |
602 * They must be in this class, not in a base class. | |
603 */ | |
604 ctor = (CtorDeclaration *)search(0, Id::ctor, 0); | |
658
50383e476c7e
Upgraded frontend to DMD 1.035
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
605 if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration())) |
159 | 606 ctor = NULL; |
607 | |
608 // dtor = (DtorDeclaration *)search(Id::dtor, 0); | |
609 // if (dtor && dtor->toParent() != this) | |
610 // dtor = NULL; | |
611 | |
612 // inv = (InvariantDeclaration *)search(Id::classInvariant, 0); | |
613 // if (inv && inv->toParent() != this) | |
614 // inv = NULL; | |
615 | |
616 // Can be in base class | |
617 aggNew = (NewDeclaration *)search(0, Id::classNew, 0); | |
618 aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); | |
619 | |
620 // If this class has no constructor, but base class does, create | |
621 // a constructor: | |
622 // this() { } | |
623 if (!ctor && baseClass && baseClass->ctor) | |
624 { | |
625 //printf("Creating default this(){} for class %s\n", toChars()); | |
336 | 626 ctor = new CtorDeclaration(loc, 0, NULL, 0); |
159 | 627 ctor->fbody = new CompoundStatement(0, new Statements()); |
628 members->push(ctor); | |
629 ctor->addMember(sc, this, 1); | |
630 *sc = scsave; // why? What about sc->nofree? | |
631 sc->offset = structsize; | |
632 ctor->semantic(sc); | |
633 defaultCtor = ctor; | |
634 } | |
635 | |
636 #if 0 | |
637 if (baseClass) | |
638 { if (!aggDelete) | |
639 aggDelete = baseClass->aggDelete; | |
640 if (!aggNew) | |
641 aggNew = baseClass->aggNew; | |
642 } | |
643 #endif | |
644 | |
645 // Allocate instance of each new interface | |
646 for (i = 0; i < vtblInterfaces->dim; i++) | |
647 { | |
648 BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; | |
649 unsigned thissize = PTRSIZE; | |
650 | |
651 alignmember(structalign, thissize, &sc->offset); | |
652 assert(b->offset == 0); | |
653 b->offset = sc->offset; | |
654 | |
655 // Take care of single inheritance offsets | |
656 while (b->baseInterfaces_dim) | |
657 { | |
658 b = &b->baseInterfaces[0]; | |
659 b->offset = sc->offset; | |
660 } | |
661 | |
662 sc->offset += thissize; | |
663 if (alignsize < thissize) | |
664 alignsize = thissize; | |
665 } | |
666 structsize = sc->offset; | |
667 sizeok = 1; | |
668 Module::dprogress++; | |
669 | |
670 dtor = buildDtor(sc); | |
671 | |
672 sc->pop(); | |
673 | |
674 #if 0 // Do not call until toObjfile() because of forward references | |
675 // Fill in base class vtbl[]s | |
676 for (i = 0; i < vtblInterfaces->dim; i++) | |
677 { | |
678 BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; | |
679 | |
680 //b->fillVtbl(this, &b->vtbl, 1); | |
681 } | |
682 #endif | |
683 //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type); | |
684 } | |
685 | |
686 void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
687 { | |
688 if (!isAnonymous()) | |
689 { | |
690 buf->printf("%s ", kind()); | |
691 buf->writestring(toChars()); | |
692 if (baseclasses.dim) | |
693 buf->writestring(" : "); | |
694 } | |
695 for (int i = 0; i < baseclasses.dim; i++) | |
696 { | |
697 BaseClass *b = (BaseClass *)baseclasses.data[i]; | |
698 | |
699 if (i) | |
700 buf->writeByte(','); | |
701 //buf->writestring(b->base->ident->toChars()); | |
702 b->type->toCBuffer(buf, NULL, hgs); | |
703 } | |
704 buf->writenl(); | |
705 buf->writeByte('{'); | |
706 buf->writenl(); | |
707 for (int i = 0; i < members->dim; i++) | |
708 { | |
709 Dsymbol *s = (Dsymbol *)members->data[i]; | |
710 | |
711 buf->writestring(" "); | |
712 s->toCBuffer(buf, hgs); | |
713 } | |
714 buf->writestring("}"); | |
715 buf->writenl(); | |
716 } | |
717 | |
718 #if 0 | |
719 void ClassDeclaration::defineRef(Dsymbol *s) | |
720 { | |
721 ClassDeclaration *cd; | |
722 | |
723 AggregateDeclaration::defineRef(s); | |
724 cd = s->isClassDeclaration(); | |
725 baseType = cd->baseType; | |
726 cd->baseType = NULL; | |
727 } | |
728 #endif | |
729 | |
730 /********************************************* | |
731 * Determine if 'this' is a base class of cd. | |
732 * This is used to detect circular inheritance only. | |
733 */ | |
734 | |
735 int ClassDeclaration::isBaseOf2(ClassDeclaration *cd) | |
736 { | |
737 if (!cd) | |
738 return 0; | |
739 //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); | |
740 for (int i = 0; i < cd->baseclasses.dim; i++) | |
741 { BaseClass *b = (BaseClass *)cd->baseclasses.data[i]; | |
742 | |
743 if (b->base == this || isBaseOf2(b->base)) | |
744 return 1; | |
745 } | |
746 return 0; | |
747 } | |
748 | |
749 /******************************************* | |
750 * Determine if 'this' is a base class of cd. | |
751 */ | |
752 | |
753 int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) | |
754 { | |
755 //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); | |
756 if (poffset) | |
757 *poffset = 0; | |
758 while (cd) | |
759 { | |
760 if (this == cd->baseClass) | |
761 return 1; | |
762 | |
763 /* cd->baseClass might not be set if cd is forward referenced. | |
764 */ | |
765 if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration()) | |
766 { | |
767 cd->error("base class is forward referenced by %s", toChars()); | |
768 } | |
769 | |
770 cd = cd->baseClass; | |
771 } | |
772 return 0; | |
773 } | |
774 | |
775 Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) | |
776 { | |
777 Dsymbol *s; | |
778 | |
779 //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); | |
780 if (scope) | |
781 semantic(scope); | |
782 | |
783 if (!members || !symtab || scope) | |
784 { error("is forward referenced when looking for '%s'", ident->toChars()); | |
785 //*(char*)0=0; | |
786 return NULL; | |
787 } | |
788 | |
789 s = ScopeDsymbol::search(loc, ident, flags); | |
790 if (!s) | |
791 { | |
792 // Search bases classes in depth-first, left to right order | |
793 | |
794 int i; | |
795 | |
796 for (i = 0; i < baseclasses.dim; i++) | |
797 { | |
798 BaseClass *b = (BaseClass *)baseclasses.data[i]; | |
799 | |
800 if (b->base) | |
801 { | |
802 if (!b->base->symtab) | |
803 error("base %s is forward referenced", b->base->ident->toChars()); | |
804 else | |
805 { | |
806 s = b->base->search(loc, ident, flags); | |
807 if (s == this) // happens if s is nested in this and derives from this | |
808 s = NULL; | |
809 else if (s) | |
810 break; | |
811 } | |
812 } | |
813 } | |
814 } | |
815 return s; | |
816 } | |
817 | |
818 /********************************************************** | |
819 * fd is in the vtbl[] for this class. | |
820 * Return 1 if function is hidden (not findable through search). | |
821 */ | |
822 | |
336 | 823 #if DMDV2 |
159 | 824 int isf(void *param, FuncDeclaration *fd) |
825 { | |
826 //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars()); | |
827 return param == fd; | |
828 } | |
829 | |
830 int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) | |
831 { | |
832 //printf("ClassDeclaration::isFuncHidden(%s)\n", fd->toChars()); | |
833 Dsymbol *s = search(0, fd->ident, 4|2); | |
834 if (!s) | |
835 { //printf("not found\n"); | |
836 /* Because, due to a hack, if there are multiple definitions | |
837 * of fd->ident, NULL is returned. | |
838 */ | |
839 return 0; | |
840 } | |
841 FuncDeclaration *fdstart = s->toAlias()->isFuncDeclaration(); | |
842 //printf("%s fdstart = %p\n", s->kind(), fdstart); | |
843 return !overloadApply(fdstart, &isf, fd); | |
844 } | |
845 #endif | |
846 | |
847 /**************** | |
848 * Find virtual function matching identifier and type. | |
849 * Used to build virtual function tables for interface implementations. | |
850 */ | |
851 | |
852 FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) | |
853 { | |
854 //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars()); | |
855 | |
856 ClassDeclaration *cd = this; | |
857 Array *vtbl = &cd->vtbl; | |
858 while (1) | |
859 { | |
860 for (size_t i = 0; i < vtbl->dim; i++) | |
861 { | |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
875
diff
changeset
|
862 FuncDeclaration *fd = ((Dsymbol*)vtbl->data[i])->isFuncDeclaration(); |
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
875
diff
changeset
|
863 if (!fd) |
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
875
diff
changeset
|
864 continue; // the first entry might be a ClassInfo |
159 | 865 |
866 //printf("\t[%d] = %s\n", i, fd->toChars()); | |
867 if (ident == fd->ident && | |
868 //tf->equals(fd->type) | |
869 fd->type->covariant(tf) == 1 | |
870 ) | |
871 { //printf("\t\tfound\n"); | |
872 return fd; | |
873 } | |
874 //else printf("\t\t%d\n", fd->type->covariant(tf)); | |
875 } | |
876 if (!cd) | |
877 break; | |
878 vtbl = &cd->vtblFinal; | |
879 cd = cd->baseClass; | |
880 } | |
881 | |
882 return NULL; | |
883 } | |
884 | |
885 void ClassDeclaration::interfaceSemantic(Scope *sc) | |
336 | 886 { |
159 | 887 vtblInterfaces = new BaseClasses(); |
888 vtblInterfaces->reserve(interfaces_dim); | |
889 | |
336 | 890 for (size_t i = 0; i < interfaces_dim; i++) |
159 | 891 { |
892 BaseClass *b = interfaces[i]; | |
893 | |
894 // If this is an interface, and it derives from a COM interface, | |
895 // then this is a COM interface too. | |
896 if (b->base->isCOMinterface()) | |
897 com = 1; | |
898 | |
899 vtblInterfaces->push(b); | |
900 b->copyBaseInterfaces(vtblInterfaces); | |
901 } | |
902 } | |
903 | |
904 /**************************************** | |
905 */ | |
906 | |
907 int ClassDeclaration::isCOMclass() | |
908 { | |
909 return com; | |
910 } | |
911 | |
912 int ClassDeclaration::isCOMinterface() | |
913 { | |
914 return 0; | |
915 } | |
916 | |
917 | |
918 /**************************************** | |
919 */ | |
920 | |
921 int ClassDeclaration::isAbstract() | |
922 { | |
923 if (isabstract) | |
924 return TRUE; | |
925 for (int i = 1; i < vtbl.dim; i++) | |
926 { | |
927 FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration(); | |
928 | |
929 //printf("\tvtbl[%d] = %p\n", i, fd); | |
930 if (!fd || fd->isAbstract()) | |
931 { | |
932 isabstract |= 1; | |
933 return TRUE; | |
934 } | |
935 } | |
936 return FALSE; | |
937 } | |
938 | |
336 | 939 |
159 | 940 /**************************************** |
941 * Returns !=0 if there's an extra member which is the 'this' | |
942 * pointer to the enclosing context (enclosing class or function) | |
943 */ | |
944 | |
945 int ClassDeclaration::isNested() | |
946 { | |
947 return isnested; | |
948 } | |
949 | |
950 /**************************************** | |
951 * Determine if slot 0 of the vtbl[] is reserved for something else. | |
952 * For class objects, yes, this is where the classinfo ptr goes. | |
953 * For COM interfaces, no. | |
954 * For non-COM interfaces, yes, this is where the Interface ptr goes. | |
955 */ | |
956 | |
957 int ClassDeclaration::vtblOffset() | |
958 { | |
959 return 1; | |
960 } | |
961 | |
962 /**************************************** | |
963 */ | |
964 | |
336 | 965 const char *ClassDeclaration::kind() |
159 | 966 { |
967 return "class"; | |
968 } | |
969 | |
970 /**************************************** | |
971 */ | |
972 | |
973 void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses) | |
974 { | |
975 aclasses->push(this); | |
976 } | |
977 | |
978 /********************************* InterfaceDeclaration ****************************/ | |
979 | |
980 InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) | |
981 : ClassDeclaration(loc, id, baseclasses) | |
982 { | |
983 com = 0; | |
984 if (id == Id::IUnknown) // IUnknown is the root of all COM objects | |
985 com = 1; | |
986 } | |
987 | |
988 Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s) | |
989 { | |
990 InterfaceDeclaration *id; | |
991 | |
992 if (s) | |
993 id = (InterfaceDeclaration *)s; | |
994 else | |
995 id = new InterfaceDeclaration(loc, ident, NULL); | |
996 | |
997 ClassDeclaration::syntaxCopy(id); | |
998 return id; | |
999 } | |
1000 | |
1001 void InterfaceDeclaration::semantic(Scope *sc) | |
1002 { int i; | |
1003 | |
1004 //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); | |
1005 if (inuse) | |
1006 return; | |
1007 if (!scope) | |
1008 { type = type->semantic(loc, sc); | |
1009 handle = handle->semantic(loc, sc); | |
1010 } | |
1011 if (!members) // if forward reference | |
1012 { //printf("\tinterface '%s' is forward referenced\n", toChars()); | |
1013 return; | |
1014 } | |
1015 if (symtab) // if already done | |
1016 { if (!scope) | |
1017 return; | |
1018 } | |
1019 else | |
1020 symtab = new DsymbolTable(); | |
1021 | |
1022 Scope *scx = NULL; | |
1023 if (scope) | |
1024 { sc = scope; | |
1025 scx = scope; // save so we don't make redundant copies | |
1026 scope = NULL; | |
1027 } | |
1028 | |
1029 if (sc->stc & STCdeprecated) | |
1030 { | |
1031 isdeprecated = 1; | |
1032 } | |
1033 | |
1034 // Expand any tuples in baseclasses[] | |
1035 for (i = 0; i < baseclasses.dim; ) | |
1036 { BaseClass *b = (BaseClass *)baseclasses.data[0]; | |
1037 b->type = b->type->semantic(loc, sc); | |
1038 Type *tb = b->type->toBasetype(); | |
1039 | |
1040 if (tb->ty == Ttuple) | |
1041 { TypeTuple *tup = (TypeTuple *)tb; | |
1042 enum PROT protection = b->protection; | |
1043 baseclasses.remove(i); | |
1044 size_t dim = Argument::dim(tup->arguments); | |
1045 for (size_t j = 0; j < dim; j++) | |
1046 { Argument *arg = Argument::getNth(tup->arguments, j); | |
1047 b = new BaseClass(arg->type, protection); | |
1048 baseclasses.insert(i + j, b); | |
1049 } | |
1050 } | |
1051 else | |
1052 i++; | |
1053 } | |
1054 | |
1055 // Check for errors, handle forward references | |
1056 for (i = 0; i < baseclasses.dim; ) | |
1057 { TypeClass *tc; | |
1058 BaseClass *b; | |
1059 Type *tb; | |
1060 | |
1061 b = (BaseClass *)baseclasses.data[i]; | |
1062 b->type = b->type->semantic(loc, sc); | |
1063 tb = b->type->toBasetype(); | |
1064 if (tb->ty == Tclass) | |
1065 tc = (TypeClass *)tb; | |
1066 else | |
1067 tc = NULL; | |
1068 if (!tc || !tc->sym->isInterfaceDeclaration()) | |
1069 { | |
1070 error("base type must be interface, not %s", b->type->toChars()); | |
1071 baseclasses.remove(i); | |
1072 continue; | |
1073 } | |
1074 else | |
1075 { | |
1076 // Check for duplicate interfaces | |
1077 for (size_t j = 0; j < i; j++) | |
1078 { | |
1079 BaseClass *b2 = (BaseClass *)baseclasses.data[j]; | |
1080 if (b2->base == tc->sym) | |
1081 error("inherits from duplicate interface %s", b2->base->toChars()); | |
1082 } | |
1083 | |
1084 b->base = tc->sym; | |
1085 if (b->base == this || isBaseOf2(b->base)) | |
1086 { | |
1087 error("circular inheritance of interface"); | |
1088 baseclasses.remove(i); | |
1089 continue; | |
1090 } | |
1091 if (!b->base->symtab || b->base->scope || b->base->inuse) | |
1092 { | |
1093 //error("forward reference of base class %s", baseClass->toChars()); | |
1094 // Forward reference of base, try again later | |
1095 //printf("\ttry later, forward reference of base %s\n", b->base->toChars()); | |
1096 scope = scx ? scx : new Scope(*sc); | |
1097 scope->setNoFree(); | |
1098 scope->module->addDeferredSemantic(this); | |
1099 return; | |
1100 } | |
1101 } | |
1102 i++; | |
1103 } | |
1104 | |
1105 interfaces_dim = baseclasses.dim; | |
1106 interfaces = (BaseClass **)baseclasses.data; | |
1107 | |
1108 interfaceSemantic(sc); | |
1109 | |
1110 if (vtblOffset()) | |
1111 vtbl.push(this); // leave room at vtbl[0] for classinfo | |
1112 | |
1113 // Cat together the vtbl[]'s from base interfaces | |
1114 for (i = 0; i < interfaces_dim; i++) | |
1115 { BaseClass *b = interfaces[i]; | |
1116 | |
1117 // Skip if b has already appeared | |
1118 for (int k = 0; k < i; k++) | |
1119 { | |
1120 if (b == interfaces[i]) | |
1121 goto Lcontinue; | |
1122 } | |
1123 | |
1124 // Copy vtbl[] from base class | |
1125 if (b->base->vtblOffset()) | |
1126 { int d = b->base->vtbl.dim; | |
1127 if (d > 1) | |
1128 { | |
1129 vtbl.reserve(d - 1); | |
1130 for (int j = 1; j < d; j++) | |
1131 vtbl.push(b->base->vtbl.data[j]); | |
1132 } | |
1133 } | |
1134 else | |
1135 { | |
1136 vtbl.append(&b->base->vtbl); | |
1137 } | |
1138 | |
1139 Lcontinue: | |
1140 ; | |
1141 } | |
1142 | |
1143 for (i = 0; i < members->dim; i++) | |
1144 { | |
1145 Dsymbol *s = (Dsymbol *)members->data[i]; | |
1146 s->addMember(sc, this, 1); | |
1147 } | |
1148 | |
1149 sc = sc->push(this); | |
1150 sc->parent = this; | |
1151 if (isCOMinterface()) | |
1152 sc->linkage = LINKwindows; | |
1153 sc->structalign = 8; | |
1154 structalign = sc->structalign; | |
809
69a5e4a6fc0f
Changed some hardcoded offset/alignment for classes in DMD, broke offsets for 64bits.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
658
diff
changeset
|
1155 sc->offset = 2*PTRSIZE; |
159 | 1156 inuse++; |
1157 for (i = 0; i < members->dim; i++) | |
1158 { | |
1159 Dsymbol *s = (Dsymbol *)members->data[i]; | |
1160 s->semantic(sc); | |
1161 } | |
1162 inuse--; | |
1163 //members->print(); | |
1164 sc->pop(); | |
1165 //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); | |
1166 } | |
1167 | |
1168 | |
1169 /******************************************* | |
1170 * Determine if 'this' is a base class of cd. | |
1171 * (Actually, if it is an interface supported by cd) | |
1172 * Output: | |
1173 * *poffset offset to start of class | |
1174 * OFFSET_RUNTIME must determine offset at runtime | |
1175 * Returns: | |
1176 * 0 not a base | |
1177 * 1 is a base | |
1178 */ | |
1179 | |
1180 int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) | |
1181 { | |
1182 unsigned j; | |
1183 | |
1184 //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars()); | |
1185 assert(!baseClass); | |
1186 for (j = 0; j < cd->interfaces_dim; j++) | |
1187 { | |
1188 BaseClass *b = cd->interfaces[j]; | |
1189 | |
1190 //printf("\tbase %s\n", b->base->toChars()); | |
1191 if (this == b->base) | |
1192 { | |
1193 //printf("\tfound at offset %d\n", b->offset); | |
1194 if (poffset) | |
1195 { *poffset = b->offset; | |
1196 if (j && cd->isInterfaceDeclaration()) | |
1197 *poffset = OFFSET_RUNTIME; | |
1198 } | |
1199 return 1; | |
1200 } | |
1201 if (isBaseOf(b, poffset)) | |
1202 { if (j && poffset && cd->isInterfaceDeclaration()) | |
1203 *poffset = OFFSET_RUNTIME; | |
1204 return 1; | |
1205 } | |
1206 } | |
1207 | |
1208 if (cd->baseClass && isBaseOf(cd->baseClass, poffset)) | |
1209 return 1; | |
1210 | |
1211 if (poffset) | |
1212 *poffset = 0; | |
1213 return 0; | |
1214 } | |
1215 | |
1216 | |
1217 int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset) | |
1218 { | |
1219 //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars()); | |
1220 for (unsigned j = 0; j < bc->baseInterfaces_dim; j++) | |
1221 { | |
1222 BaseClass *b = &bc->baseInterfaces[j]; | |
1223 | |
1224 if (this == b->base) | |
1225 { | |
1226 if (poffset) | |
1227 { *poffset = b->offset; | |
1228 } | |
1229 return 1; | |
1230 } | |
1231 if (isBaseOf(b, poffset)) | |
1232 { | |
1233 return 1; | |
1234 } | |
1235 } | |
1236 if (poffset) | |
1237 *poffset = 0; | |
1238 return 0; | |
1239 } | |
1240 | |
1241 /**************************************** | |
1242 * Determine if slot 0 of the vtbl[] is reserved for something else. | |
1243 * For class objects, yes, this is where the ClassInfo ptr goes. | |
1244 * For COM interfaces, no. | |
1245 * For non-COM interfaces, yes, this is where the Interface ptr goes. | |
1246 */ | |
1247 | |
1248 int InterfaceDeclaration::vtblOffset() | |
1249 { | |
1250 if (isCOMinterface()) | |
1251 return 0; | |
1252 return 1; | |
1253 } | |
1254 | |
1255 int InterfaceDeclaration::isCOMinterface() | |
1256 { | |
1257 return com; | |
1258 } | |
1259 | |
1260 /******************************************* | |
1261 */ | |
1262 | |
336 | 1263 const char *InterfaceDeclaration::kind() |
159 | 1264 { |
1265 return "interface"; | |
1266 } | |
1267 | |
1268 | |
1269 /******************************** BaseClass *****************************/ | |
1270 | |
1271 BaseClass::BaseClass() | |
1272 { | |
1273 memset(this, 0, sizeof(BaseClass)); | |
1274 } | |
1275 | |
1276 BaseClass::BaseClass(Type *type, enum PROT protection) | |
1277 { | |
1278 //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); | |
1279 this->type = type; | |
1280 this->protection = protection; | |
1281 base = NULL; | |
1282 offset = 0; | |
1283 | |
1284 baseInterfaces_dim = 0; | |
1285 baseInterfaces = NULL; | |
1286 } | |
1287 | |
1288 /**************************************** | |
1289 * Fill in vtbl[] for base class based on member functions of class cd. | |
1290 * Input: | |
1291 * vtbl if !=NULL, fill it in | |
1292 * newinstance !=0 means all entries must be filled in by members | |
1293 * of cd, not members of any base classes of cd. | |
1294 * Returns: | |
1295 * !=0 if any entries were filled in by members of cd (not exclusively | |
1296 * by base classes) | |
1297 */ | |
1298 | |
1299 int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance) | |
1300 { | |
1301 ClassDeclaration *id = base; | |
1302 int j; | |
1303 int result = 0; | |
1304 | |
1305 //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars()); | |
1306 if (vtbl) | |
1307 vtbl->setDim(base->vtbl.dim); | |
1308 | |
1309 // first entry is ClassInfo reference | |
1310 for (j = base->vtblOffset(); j < base->vtbl.dim; j++) | |
1311 { | |
1312 FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration(); | |
1313 FuncDeclaration *fd; | |
1314 TypeFunction *tf; | |
1315 | |
1316 //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null"); | |
1317 | |
1318 assert(ifd); | |
1319 // Find corresponding function in this class | |
1320 tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL; | |
1321 fd = cd->findFunc(ifd->ident, tf); | |
1322 if (fd && !fd->isAbstract()) | |
1323 { | |
1324 //printf(" found\n"); | |
1325 // Check that calling conventions match | |
1326 if (fd->linkage != ifd->linkage) | |
1327 fd->error("linkage doesn't match interface function"); | |
1328 | |
1329 // Check that it is current | |
1330 if (newinstance && | |
1331 fd->toParent() != cd && | |
1332 ifd->toParent() == base) | |
1333 cd->error("interface function %s.%s is not implemented", | |
1334 id->toChars(), ifd->ident->toChars()); | |
1335 | |
1336 if (fd->toParent() == cd) | |
1337 result = 1; | |
1338 } | |
1339 else | |
1340 { | |
1341 //printf(" not found\n"); | |
1342 // BUG: should mark this class as abstract? | |
1343 if (!cd->isAbstract()) | |
1344 cd->error("interface function %s.%s isn't implemented", | |
1345 id->toChars(), ifd->ident->toChars()); | |
1346 fd = NULL; | |
1347 } | |
1348 if (vtbl) | |
1349 vtbl->data[j] = fd; | |
1350 } | |
1351 | |
1352 return result; | |
1353 } | |
1354 | |
1355 void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces) | |
1356 { | |
1357 //printf("+copyBaseInterfaces(), %s\n", base->toChars()); | |
1358 // if (baseInterfaces_dim) | |
1359 // return; | |
1360 | |
1361 baseInterfaces_dim = base->interfaces_dim; | |
1362 baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass)); | |
1363 | |
1364 //printf("%s.copyBaseInterfaces()\n", base->toChars()); | |
1365 for (int i = 0; i < baseInterfaces_dim; i++) | |
1366 { | |
1367 BaseClass *b = &baseInterfaces[i]; | |
1368 BaseClass *b2 = base->interfaces[i]; | |
1369 | |
1370 assert(b2->vtbl.dim == 0); // should not be filled yet | |
1371 memcpy(b, b2, sizeof(BaseClass)); | |
1372 | |
1373 if (i) // single inheritance is i==0 | |
1374 vtblInterfaces->push(b); // only need for M.I. | |
1375 b->copyBaseInterfaces(vtblInterfaces); | |
1376 } | |
1377 //printf("-copyBaseInterfaces\n"); | |
1378 } |