Mercurial > projects > ddmd
annotate dmd/TypeClass.d @ 178:e3afd1303184
Many small bugs fixed
Made all classes derive from TObject to detect memory leaks (functionality is disabled for now)
Began work on overriding backend memory allocations (to avoid memory leaks)
author | korDen |
---|---|
date | Sun, 17 Oct 2010 07:42:00 +0400 |
parents | fa9a71a9f5a8 |
children | b0d41ff5e0df |
rev | line source |
---|---|
0 | 1 module dmd.TypeClass; |
2 | |
114 | 3 import dmd.common; |
0 | 4 import dmd.Type; |
5 import dmd.ClassDeclaration; | |
64 | 6 import dmd.TypeInstance; |
0 | 7 import dmd.Loc; |
8 import dmd.Dsymbol; | |
9 import dmd.Scope; | |
10 import dmd.OutBuffer; | |
11 import dmd.HdrGenState; | |
12 import dmd.Expression; | |
13 import dmd.Identifier; | |
14 import dmd.MATCH; | |
64 | 15 import dmd.DYNCAST; |
0 | 16 import dmd.CppMangleState; |
17 import dmd.ArrayTypes; | |
18 import dmd.TypeInfoDeclaration; | |
19 import dmd.TY; | |
20 import dmd.MOD; | |
21 import dmd.Global; | |
22 import dmd.TypePointer; | |
23 import dmd.Declaration; | |
24 import dmd.VarDeclaration; | |
25 import dmd.TOK; | |
26 import dmd.DotExp; | |
27 import dmd.Id; | |
28 import dmd.ScopeExp; | |
29 import dmd.DotVarExp; | |
30 import dmd.VarExp; | |
31 import dmd.PtrExp; | |
32 import dmd.AddExp; | |
33 import dmd.IntegerExp; | |
34 import dmd.DotIdExp; | |
35 import dmd.EnumMember; | |
36 import dmd.TemplateMixin; | |
37 import dmd.TemplateDeclaration; | |
38 import dmd.TemplateInstance; | |
39 import dmd.OverloadSet; | |
40 import dmd.DotTypeExp; | |
41 import dmd.TupleExp; | |
42 import dmd.ClassInfoDeclaration; | |
43 import dmd.TypeInfoInterfaceDeclaration; | |
44 import dmd.TypeInfoClassDeclaration; | |
45 import dmd.Util; | |
46 import dmd.NullExp; | |
47 import dmd.TypeExp; | |
48 import dmd.DotTemplateExp; | |
49 import dmd.ErrorExp; | |
50 import dmd.ThisExp; | |
51 import dmd.CommaExp; | |
52 | |
53 import dmd.expression.Util; | |
54 import dmd.backend.Symbol; | |
55 import dmd.backend.TYPE; | |
56 import dmd.backend.Util; | |
57 import dmd.backend.SC; | |
58 import dmd.backend.STR; | |
59 import dmd.backend.TYM; | |
60 import dmd.backend.LIST; | |
61 import dmd.backend.Classsym; | |
62 | |
63 import std.string : toStringz; | |
64 | |
65 class TypeClass : Type | |
66 { | |
67 ClassDeclaration sym; | |
68 | |
69 this(ClassDeclaration sym) | |
70 { | |
178 | 71 register(); |
0 | 72 super(TY.Tclass); |
73 this.sym = sym; | |
74 } | |
75 | |
72 | 76 override ulong size(Loc loc) |
0 | 77 { |
78 return PTRSIZE; | |
79 } | |
80 | |
72 | 81 override string toChars() |
0 | 82 { |
83 if (mod) | |
84 return Type.toChars(); | |
85 return sym.toPrettyChars(); | |
86 } | |
87 | |
72 | 88 override Type syntaxCopy() |
0 | 89 { |
90 assert(false); | |
91 } | |
92 | |
72 | 93 override Type semantic(Loc loc, Scope sc) |
0 | 94 { |
95 //printf("TypeClass.semantic(%s)\n", sym.toChars()); | |
96 if (deco) | |
97 return this; | |
98 //printf("\t%s\n", merge().deco); | |
99 return merge(); | |
100 } | |
101 | |
72 | 102 override Dsymbol toDsymbol(Scope sc) |
0 | 103 { |
104 return sym; | |
105 } | |
106 | |
72 | 107 override void toDecoBuffer(OutBuffer buf, int flag) |
0 | 108 { |
109 string name = sym.mangle(); | |
110 //printf("TypeClass.toDecoBuffer('%s' flag=%d mod=%x) = '%s'\n", toChars(), flag, mod, name); | |
111 Type.toDecoBuffer(buf, flag); | |
112 buf.printf("%s", name); | |
113 } | |
114 | |
72 | 115 override void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod) |
0 | 116 { |
117 if (mod != this.mod) | |
118 { | |
119 toCBuffer3(buf, hgs, mod); | |
120 return; | |
121 } | |
122 buf.writestring(sym.toChars()); | |
123 } | |
124 | |
72 | 125 override Expression dotExp(Scope sc, Expression e, Identifier ident) |
0 | 126 { |
127 uint offset; | |
128 | |
129 Expression b; | |
130 VarDeclaration v; | |
131 Dsymbol s; | |
132 | |
133 version (LOGDOTEXP) { | |
134 printf("TypeClass.dotExp(e='%s', ident='%s')\n", e.toChars(), ident.toChars()); | |
135 } | |
136 | |
137 if (e.op == TOK.TOKdotexp) | |
138 { | |
139 DotExp de = cast(DotExp)e; | |
140 | |
141 if (de.e1.op == TOK.TOKimport) | |
142 { | |
143 ScopeExp se = cast(ScopeExp)de.e1; | |
144 | |
145 s = se.sds.search(e.loc, ident, 0); | |
146 e = de.e1; | |
147 goto L1; | |
148 } | |
149 } | |
150 | |
151 if (ident is Id.tupleof_) | |
152 { | |
153 /* Create a TupleExp | |
154 */ | |
155 e = e.semantic(sc); // do this before turning on noaccesscheck | |
156 Expressions exps = new Expressions; | |
157 exps.reserve(sym.fields.dim); | |
158 for (size_t i = 0; i < sym.fields.dim; i++) | |
159 { | |
79 | 160 VarDeclaration v2 = cast(VarDeclaration)sym.fields[i]; |
0 | 161 Expression fe = new DotVarExp(e.loc, e, v2); |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
162 exps.push(fe); |
0 | 163 } |
164 e = new TupleExp(e.loc, exps); | |
165 sc = sc.push(); | |
166 sc.noaccesscheck = 1; | |
167 e = e.semantic(sc); | |
168 sc.pop(); | |
169 return e; | |
170 } | |
171 | |
172 s = sym.search(e.loc, ident, 0); | |
173 L1: | |
174 if (!s) | |
175 { | |
176 // See if it's a base class | |
177 ClassDeclaration cbase; | |
178 for (cbase = sym.baseClass; cbase; cbase = cbase.baseClass) | |
179 { | |
180 if (cbase.ident.equals(ident)) | |
181 { | |
182 e = new DotTypeExp(Loc(0), e, cbase); | |
183 return e; | |
184 } | |
185 } | |
186 | |
187 if (ident is Id.classinfo_) | |
188 { | |
166
d8565fbd755c
Moved object and classinfo from ClassDeclaration to Global (as part of getting rid of the global state)
korDen
parents:
135
diff
changeset
|
189 assert(global.classinfo); |
d8565fbd755c
Moved object and classinfo from ClassDeclaration to Global (as part of getting rid of the global state)
korDen
parents:
135
diff
changeset
|
190 Type t = global.classinfo.type; |
0 | 191 if (e.op == TOK.TOKtype || e.op == TOK.TOKdottype) |
192 { | |
193 /* For type.classinfo, we know the classinfo | |
194 * at compile time. | |
195 */ | |
196 if (!sym.vclassinfo) | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
197 sym.vclassinfo = new TypeInfoClassDeclaration(sym.type); |
0 | 198 |
199 e = new VarExp(e.loc, sym.vclassinfo); | |
200 e = e.addressOf(sc); | |
201 e.type = t; // do this so we don't get redundant dereference | |
202 } | |
203 else | |
204 { | |
205 /* For class objects, the classinfo reference is the first | |
206 * entry in the vtbl[] | |
207 */ | |
208 e = new PtrExp(e.loc, e); | |
209 e.type = t.pointerTo(); | |
210 if (sym.isInterfaceDeclaration()) | |
211 { | |
212 if (sym.isCPPinterface()) | |
213 { | |
214 /* C++ interface vtbl[]s are different in that the | |
215 * first entry is always pointer to the first virtual | |
216 * function, not classinfo. | |
217 * We can't get a .classinfo for it. | |
218 */ | |
219 error(e.loc, "no .classinfo for C++ interface objects"); | |
220 } | |
221 /* For an interface, the first entry in the vtbl[] | |
222 * is actually a pointer to an instance of struct Interface. | |
223 * The first member of Interface is the .classinfo, | |
224 * so add an extra pointer indirection. | |
225 */ | |
226 e.type = e.type.pointerTo(); | |
227 e = new PtrExp(e.loc, e); | |
228 e.type = t.pointerTo(); | |
229 } | |
230 e = new PtrExp(e.loc, e, t); | |
231 } | |
232 return e; | |
233 } | |
234 | |
235 if (ident is Id.__vptr) | |
236 { | |
237 /* The pointer to the vtbl[] | |
238 * *cast(invariant(void*)**)e | |
239 */ | |
176 | 240 e = e.castTo(sc, global.tvoidptr.invariantOf().pointerTo().pointerTo()); |
0 | 241 e = new PtrExp(e.loc, e); |
242 e = e.semantic(sc); | |
243 return e; | |
244 } | |
245 | |
246 if (ident is Id.__monitor) | |
247 { /* The handle to the monitor (call it a void*) | |
248 * *(cast(void**)e + 1) | |
249 */ | |
176 | 250 e = e.castTo(sc, global.tvoidptr.pointerTo()); |
0 | 251 e = new AddExp(e.loc, e, new IntegerExp(1)); |
252 e = new PtrExp(e.loc, e); | |
253 e = e.semantic(sc); | |
254 return e; | |
255 } | |
256 | |
257 if (ident is Id.typeinfo_) | |
258 { | |
259 if (!global.params.useDeprecated) | |
260 error(e.loc, ".typeinfo deprecated, use typeid(type)"); | |
261 | |
262 return getTypeInfo(sc); | |
263 } | |
264 if (ident is Id.outer && sym.vthis) | |
265 { | |
266 s = sym.vthis; | |
267 } | |
268 else | |
269 { | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
270 return noMember(sc, e, ident); |
0 | 271 } |
272 } | |
273 | |
274 if (!s.isFuncDeclaration()) // because of overloading | |
275 s.checkDeprecated(e.loc, sc); | |
276 | |
277 s = s.toAlias(); | |
278 v = s.isVarDeclaration(); | |
279 | |
280 if (v && !v.isDataseg()) | |
281 { | |
282 Expression ei = v.getConstInitializer(); | |
283 | |
284 if (ei) | |
285 { | |
286 e = ei.copy(); // need to copy it if it's a StringExp | |
287 e = e.semantic(sc); | |
288 return e; | |
289 } | |
290 } | |
291 | |
292 if (s.getType()) | |
293 { | |
294 // if (e.op == TOKtype) | |
295 return new TypeExp(e.loc, s.getType()); | |
296 // return new DotTypeExp(e.loc, e, s); | |
297 } | |
298 | |
299 EnumMember em = s.isEnumMember(); | |
300 if (em) | |
301 { | |
302 assert(em.value); | |
303 return em.value.copy(); | |
304 } | |
305 | |
306 TemplateMixin tm = s.isTemplateMixin(); | |
307 if (tm) | |
308 { | |
309 Expression de = new DotExp(e.loc, e, new ScopeExp(e.loc, tm)); | |
310 de.type = e.type; | |
311 return de; | |
312 } | |
313 | |
314 TemplateDeclaration td = s.isTemplateDeclaration(); | |
315 if (td) | |
316 { | |
317 e = new DotTemplateExp(e.loc, e, td); | |
318 e.semantic(sc); | |
319 return e; | |
320 } | |
321 | |
322 TemplateInstance ti = s.isTemplateInstance(); | |
323 if (ti) | |
324 { | |
325 if (!ti.semanticRun) | |
326 ti.semantic(sc); | |
327 s = ti.inst.toAlias(); | |
328 if (!s.isTemplateInstance()) | |
329 goto L1; | |
330 Expression de = new DotExp(e.loc, e, new ScopeExp(e.loc, ti)); | |
331 de.type = e.type; | |
332 return de; | |
333 } | |
334 | |
335 OverloadSet o = s.isOverloadSet(); | |
336 if (o) | |
337 { | |
338 /* We really should allow this | |
339 */ | |
340 error(e.loc, "overload set for %s.%s not allowed in struct declaration", e.toChars(), ident.toChars()); | |
341 return new ErrorExp(); | |
342 } | |
343 | |
344 Declaration d = s.isDeclaration(); | |
345 if (!d) | |
346 { | |
347 e.error("%s.%s is not a declaration", e.toChars(), ident.toChars()); | |
348 return new ErrorExp(); | |
349 } | |
350 | |
351 if (e.op == TOK.TOKtype) | |
352 { | |
353 /* It's: | |
354 * Class.d | |
355 */ | |
356 if (d.isTupleDeclaration()) | |
357 { | |
358 e = new TupleExp(e.loc, d.isTupleDeclaration()); | |
359 e = e.semantic(sc); | |
360 return e; | |
361 } | |
73 | 362 else if (d.needThis() && (hasThis(sc) || !(sc.intypeof || d.isFuncDeclaration()))) |
0 | 363 { |
364 if (sc.func) | |
365 { | |
366 ClassDeclaration thiscd; | |
367 thiscd = sc.func.toParent().isClassDeclaration(); | |
368 | |
369 if (thiscd) | |
370 { | |
371 ClassDeclaration cd = e.type.isClassHandle(); | |
372 | |
373 if (cd is thiscd) | |
374 { | |
375 e = new ThisExp(e.loc); | |
376 e = new DotTypeExp(e.loc, e, cd); | |
377 DotVarExp de = new DotVarExp(e.loc, e, d); | |
378 e = de.semantic(sc); | |
379 return e; | |
380 } | |
381 else if ((!cd || !cd.isBaseOf(thiscd, null)) && !d.isFuncDeclaration()) | |
382 e.error("'this' is required, but %s is not a base class of %s", e.type.toChars(), thiscd.toChars()); | |
383 } | |
384 } | |
385 | |
386 /* Rewrite as: | |
387 * this.d | |
388 */ | |
389 DotVarExp de = new DotVarExp(e.loc, new ThisExp(e.loc), d); | |
390 e = de.semantic(sc); | |
391 return e; | |
392 } | |
393 else | |
394 { | |
395 VarExp ve = new VarExp(e.loc, d, 1); | |
396 return ve; | |
397 } | |
398 } | |
399 | |
400 if (d.isDataseg()) | |
401 { | |
402 // (e, d) | |
403 accessCheck(e.loc, sc, e, d); | |
404 VarExp ve = new VarExp(e.loc, d); | |
405 e = new CommaExp(e.loc, e, ve); | |
406 e.type = d.type; | |
407 return e; | |
408 } | |
409 | |
410 if (d.parent && d.toParent().isModule()) | |
411 { | |
412 // (e, d) | |
413 VarExp ve = new VarExp(e.loc, d, 1); | |
414 e = new CommaExp(e.loc, e, ve); | |
415 e.type = d.type; | |
416 return e; | |
417 } | |
418 | |
419 DotVarExp de = new DotVarExp(e.loc, e, d); | |
420 return de.semantic(sc); | |
421 } | |
422 | |
72 | 423 override ClassDeclaration isClassHandle() |
0 | 424 { |
425 return sym; | |
426 } | |
427 | |
72 | 428 override bool isBaseOf(Type t, int* poffset) |
0 | 429 { |
56 | 430 if (t.ty == Tclass) |
431 { | |
432 ClassDeclaration cd; | |
433 | |
434 cd = (cast(TypeClass)t).sym; | |
435 if (sym.isBaseOf(cd, poffset)) | |
436 return true; | |
437 } | |
438 | |
439 return false; | |
0 | 440 } |
441 | |
72 | 442 override MATCH implicitConvTo(Type to) |
0 | 443 { |
444 //printf("TypeClass.implicitConvTo(to = '%s') %s\n", to.toChars(), toChars()); | |
445 MATCH m = constConv(to); | |
446 if (m != MATCH.MATCHnomatch) | |
447 return m; | |
448 | |
449 ClassDeclaration cdto = to.isClassHandle(); | |
450 if (cdto && cdto.isBaseOf(sym, null)) | |
451 { | |
452 //printf("'to' is base\n"); | |
453 return MATCH.MATCHconvert; | |
454 } | |
455 | |
456 if (global.params.Dversion == 1) | |
457 { | |
458 // Allow conversion to (void *) | |
459 if (to.ty == TY.Tpointer && (cast(TypePointer)to).next.ty == TY.Tvoid) | |
460 return MATCH.MATCHconvert; | |
461 } | |
462 | |
463 m = MATCH.MATCHnomatch; | |
464 if (sym.aliasthis) | |
465 { | |
466 Declaration d = sym.aliasthis.isDeclaration(); | |
467 if (d) | |
468 { | |
469 assert(d.type); | |
470 Type t = d.type.addMod(mod); | |
471 m = t.implicitConvTo(to); | |
472 } | |
473 } | |
474 | |
475 return m; | |
476 } | |
477 | |
72 | 478 override Expression defaultInit(Loc loc) |
0 | 479 { |
480 version (LOGDEFAULTINIT) { | |
481 printf("TypeClass::defaultInit() '%s'\n", toChars()); | |
482 } | |
135 | 483 return new NullExp(loc, this); |
0 | 484 } |
485 | |
72 | 486 override bool isZeroInit(Loc loc) |
0 | 487 { |
488 return true; | |
489 } | |
490 | |
72 | 491 override MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) |
0 | 492 { |
64 | 493 //printf("TypeClass.deduceType(this = %s)\n", toChars()); |
494 | |
495 /* If this class is a template class, and we're matching | |
496 * it against a template instance, convert the class type | |
497 * to a template instance, too, and try again. | |
498 */ | |
499 TemplateInstance ti = sym.parent.isTemplateInstance(); | |
500 | |
501 if (tparam && tparam.ty == Tinstance) | |
502 { | |
503 if (ti && ti.toAlias() == sym) | |
504 { | |
505 TypeInstance t = new TypeInstance(Loc(0), ti); | |
506 return t.deduceType(sc, tparam, parameters, dedtypes); | |
507 } | |
508 | |
509 /* Match things like: | |
510 * S!(T).foo | |
511 */ | |
512 TypeInstance tpi = cast(TypeInstance)tparam; | |
513 if (tpi.idents.dim) | |
514 { Identifier id = cast(Identifier)tpi.idents.data[tpi.idents.dim - 1]; | |
515 if (id.dyncast() == DYNCAST.DYNCAST_IDENTIFIER && sym.ident.equals(id)) | |
516 { | |
517 Type tparent = sym.parent.getType(); | |
518 if (tparent) | |
519 { | |
520 /* Slice off the .foo in S!(T).foo | |
521 */ | |
522 tpi.idents.dim--; | |
523 MATCH m = tparent.deduceType(sc, tpi, parameters, dedtypes); | |
524 tpi.idents.dim++; | |
525 return m; | |
526 } | |
527 } | |
528 } | |
529 } | |
530 | |
531 // Extra check | |
532 if (tparam && tparam.ty == Tclass) | |
533 { | |
534 TypeClass tp = cast(TypeClass)tparam; | |
535 | |
536 //printf("\t%d\n", (MATCH) implicitConvTo(tp)); | |
537 return implicitConvTo(tp); | |
538 } | |
539 return Type.deduceType(sc, tparam, parameters, dedtypes); | |
0 | 540 } |
541 | |
72 | 542 override bool isauto() |
0 | 543 { |
544 return sym.isauto; | |
545 } | |
546 | |
72 | 547 override bool checkBoolean() |
0 | 548 { |
549 return true; | |
550 } | |
551 | |
72 | 552 override TypeInfoDeclaration getTypeInfoDeclaration() |
0 | 553 { |
554 if (sym.isInterfaceDeclaration()) | |
555 return new TypeInfoInterfaceDeclaration(this); | |
556 else | |
557 return new TypeInfoClassDeclaration(this); | |
558 } | |
559 | |
72 | 560 override bool hasPointers() |
0 | 561 { |
562 return true; | |
563 } | |
564 | |
72 | 565 override bool builtinTypeInfo() |
0 | 566 { |
567 /* This is statically put out with the ClassInfo, so | |
568 * claim it is built in so it isn't regenerated by each module. | |
569 */ | |
570 version (DMDV2) { | |
571 return mod ? false : true; | |
572 } else { | |
573 return true; | |
574 } | |
575 } | |
576 | |
577 version (DMDV2) { | |
72 | 578 override Type toHeadMutable() |
0 | 579 { |
580 assert(false); | |
581 } | |
582 | |
72 | 583 override MATCH constConv(Type to) |
0 | 584 { |
585 if (equals(to)) | |
586 return MATCH.MATCHexact; | |
587 | |
588 if (ty == to.ty && sym == (cast(TypeClass)to).sym && to.mod == MOD.MODconst) | |
589 return MATCH.MATCHconst; | |
590 | |
591 return MATCH.MATCHnomatch; | |
592 } | |
593 | |
594 version (CPP_MANGLE) { | |
595 void toCppMangle(OutBuffer buf, CppMangleState* cms) | |
596 { | |
597 assert(false); | |
598 } | |
599 } | |
600 } | |
601 | |
72 | 602 override type* toCtype() |
0 | 603 { |
604 type* t; | |
605 Symbol* s; | |
606 | |
607 //printf("TypeClass.toCtype() %s\n", toChars()); | |
608 if (ctype) | |
609 return ctype; | |
610 | |
611 /* Need this symbol to do C++ name mangling | |
612 */ | |
613 string name = sym.isCPPinterface() ? sym.ident.toChars() : sym.toPrettyChars(); | |
614 s = symbol_calloc(toStringz(name)); | |
615 s.Sclass = SC.SCstruct; | |
616 s.Sstruct = struct_calloc(); | |
617 s.Sstruct.Sflags |= STR.STRclass; | |
618 s.Sstruct.Salignsize = sym.alignsize; | |
619 s.Sstruct.Sstructalign = cast(ubyte)sym.structalign; | |
620 s.Sstruct.Sstructsize = sym.structsize; | |
621 | |
622 t = type_alloc(TYM.TYstruct); | |
623 t.Ttag = cast(Classsym*)s; // structure tag name | |
624 t.Tcount++; | |
625 s.Stype = t; | |
626 slist_add(s); | |
627 | |
628 t = type_allocn(TYM.TYnptr, t); | |
629 | |
630 t.Tcount++; | |
631 ctype = t; | |
632 | |
633 /* Add in fields of the class | |
634 * (after setting ctype to avoid infinite recursion) | |
635 */ | |
636 if (global.params.symdebug) | |
637 for (int i = 0; i < sym.fields.dim; i++) | |
638 { | |
79 | 639 VarDeclaration v = cast(VarDeclaration)sym.fields[i]; |
0 | 640 |
641 Symbol* s2 = symbol_name(toStringz(v.ident.toChars()), SC.SCmember, v.type.toCtype()); | |
642 s2.Smemoff = v.offset; | |
643 list_append(&s.Sstruct.Sfldlst, s2); | |
644 } | |
645 | |
646 return t; | |
647 } | |
648 | |
72 | 649 override Symbol* toSymbol() |
0 | 650 { |
651 return sym.toSymbol(); | |
652 } | |
72 | 653 } |