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