comparison dmd/NewExp.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children a8b50ff7f201
comparison
equal deleted inserted replaced
-1:000000000000 0:10317f0c89a5
1 module dmd.NewExp;
2
3 import dmd.Expression;
4 import dmd.NewDeclaration;
5 import dmd.CtorDeclaration;
6 import dmd.ClassDeclaration;
7 import dmd.Type;
8 import dmd.OutBuffer;
9 import dmd.Loc;
10 import dmd.Scope;
11 import dmd.IRState;
12 import dmd.InlineDoState;
13 import dmd.HdrGenState;
14 import dmd.ArrayTypes;
15 import dmd.TOK;
16 import dmd.TY;
17 import dmd.TypeFunction;
18 import dmd.TypeClass;
19 import dmd.TypeStruct;
20 import dmd.StructDeclaration;
21 import dmd.FuncDeclaration;
22 import dmd.TypeDArray;
23 import dmd.Dsymbol;
24 import dmd.ThisExp;
25 import dmd.DotIdExp;
26 import dmd.Id;
27 import dmd.WANT;
28 import dmd.Global;
29 import dmd.IntegerExp;
30 import dmd.TypePointer;
31
32 import dmd.backend.elem;
33 import dmd.backend.TYM;
34 import dmd.backend.SC;
35 import dmd.backend.TYPE;
36 import dmd.backend.TYM;
37 import dmd.backend.Symbol;
38 import dmd.backend.Classsym;
39 import dmd.backend.Util;
40 import dmd.backend.OPER;
41 import dmd.backend.RTLSYM;
42 import dmd.expression.Util;
43 import dmd.codegen.Util;
44
45 import std.string : toStringz;
46
47 class NewExp : Expression
48 {
49 /* thisexp.new(newargs) newtype(arguments)
50 */
51 Expression thisexp; // if !null, 'this' for class being allocated
52 Expressions newargs; // Array of Expression's to call new operator
53 Type newtype;
54 Expressions arguments; // Array of Expression's
55
56 CtorDeclaration member; // constructor function
57 NewDeclaration allocator; // allocator function
58 int onstack; // allocate on stack
59
60 this(Loc loc, Expression thisexp, Expressions newargs, Type newtype, Expressions arguments)
61 {
62 super(loc, TOK.TOKnew, NewExp.sizeof);
63 this.thisexp = thisexp;
64 this.newargs = newargs;
65 this.newtype = newtype;
66 this.arguments = arguments;
67 }
68
69 Expression syntaxCopy()
70 {
71 assert(false);
72 }
73
74 Expression semantic(Scope sc)
75 {
76 int i;
77 Type tb;
78 ClassDeclaration cdthis = null;
79
80 version (LOGSEMANTIC) {
81 printf("NewExp.semantic() %s\n", toChars());
82 if (thisexp)
83 printf("\tthisexp = %s\n", thisexp.toChars());
84 printf("\tnewtype: %s\n", newtype.toChars());
85 }
86 if (type) // if semantic() already run
87 return this;
88
89 Lagain:
90 if (thisexp)
91 {
92 thisexp = thisexp.semantic(sc);
93 cdthis = thisexp.type.isClassHandle();
94 if (cdthis)
95 {
96 sc = sc.push(cdthis);
97 type = newtype.semantic(loc, sc);
98 sc = sc.pop();
99 }
100 else
101 {
102 error("'this' for nested class must be a class type, not %s", thisexp.type.toChars());
103 type = newtype.semantic(loc, sc);
104 }
105 }
106 else
107 type = newtype.semantic(loc, sc);
108 newtype = type; // in case type gets cast to something else
109 tb = type.toBasetype();
110 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
111
112 arrayExpressionSemantic(newargs, sc);
113 preFunctionArguments(loc, sc, newargs);
114 arrayExpressionSemantic(arguments, sc);
115 preFunctionArguments(loc, sc, arguments);
116
117 if (thisexp && tb.ty != Tclass)
118 error("e.new is only for allocating nested classes, not %s", tb.toChars());
119
120 if (tb.ty == Tclass)
121 {
122 TypeFunction tf;
123
124 TypeClass tc = cast(TypeClass)tb;
125 ClassDeclaration cd = tc.sym.isClassDeclaration();
126 if (cd.isInterfaceDeclaration())
127 error("cannot create instance of interface %s", cd.toChars());
128 else if (cd.isAbstract())
129 {
130 error("cannot create instance of abstract class %s", cd.toChars());
131 for (int j = 0; j < cd.vtbl.dim; j++)
132 {
133 FuncDeclaration fd = (cast(Dsymbol)cd.vtbl.data[j]).isFuncDeclaration();
134 if (fd && fd.isAbstract())
135 error("function %s is abstract", fd.toChars());
136 }
137 }
138 checkDeprecated(sc, cd);
139 if (cd.isNested())
140 { /* We need a 'this' pointer for the nested class.
141 * Ensure we have the right one.
142 */
143 Dsymbol s = cd.toParent2();
144 ClassDeclaration cdn = s.isClassDeclaration();
145 FuncDeclaration fdn = s.isFuncDeclaration();
146
147 //printf("cd isNested, cdn = %s\n", cdn ? cdn.toChars() : "null");
148 if (cdn)
149 {
150 if (!cdthis)
151 {
152 // Supply an implicit 'this' and try again
153 thisexp = new ThisExp(loc);
154 for (Dsymbol sp = sc.parent; 1; sp = sp.parent)
155 {
156 if (!sp)
157 {
158 error("outer class %s 'this' needed to 'new' nested class %s", cdn.toChars(), cd.toChars());
159 break;
160 }
161 ClassDeclaration cdp = sp.isClassDeclaration();
162 if (!cdp)
163 continue;
164 if (cdp == cdn || cdn.isBaseOf(cdp, null))
165 break;
166 // Add a '.outer' and try again
167 thisexp = new DotIdExp(loc, thisexp, Id.outer);
168 }
169 if (!global.errors)
170 goto Lagain;
171 }
172 if (cdthis)
173 {
174 //printf("cdthis = %s\n", cdthis.toChars());
175 if (cdthis != cdn && !cdn.isBaseOf(cdthis, null))
176 error("'this' for nested class must be of type %s, not %s", cdn.toChars(), thisexp.type.toChars());
177 }
178 else
179 {
180 static if (false) {
181 for (Dsymbol *sf = sc.func; 1; sf= sf.toParent2().isFuncDeclaration())
182 {
183 if (!sf)
184 {
185 error("outer class %s 'this' needed to 'new' nested class %s", cdn.toChars(), cd.toChars());
186 break;
187 }
188 printf("sf = %s\n", sf.toChars());
189 AggregateDeclaration *ad = sf.isThis();
190 if (ad && (ad == cdn || cdn.isBaseOf(ad.isClassDeclaration(), null)))
191 break;
192 }
193 }
194 }
195 }
196 ///static if (true) {
197 else if (thisexp)
198 error("e.new is only for allocating nested classes");
199 else if (fdn)
200 {
201 // make sure the parent context fdn of cd is reachable from sc
202 for (Dsymbol sp = sc.parent; 1; sp = sp.parent)
203 {
204 if (fdn is sp)
205 break;
206 FuncDeclaration fsp = sp ? sp.isFuncDeclaration() : null;
207 if (!sp || (fsp && fsp.isStatic()))
208 {
209 error("outer function context of %s is needed to 'new' nested class %s", fdn.toPrettyChars(), cd.toPrettyChars());
210 break;
211 }
212 }
213 }
214 ///} else {
215 /// else if (fdn)
216 /// {
217 /// /* The nested class cd is nested inside a function,
218 /// * we'll let getEthis() look for errors.
219 /// */
220 /// //printf("nested class %s is nested inside function %s, we're in %s\n", cd.toChars(), fdn.toChars(), sc.func.toChars());
221 /// if (thisexp)
222 /// // Because thisexp cannot be a function frame pointer
223 /// error("e.new is only for allocating nested classes");
224 /// }
225 ///}
226 else
227 assert(0);
228 }
229 else if (thisexp)
230 error("e.new is only for allocating nested classes");
231
232 FuncDeclaration f = null;
233 if (cd.ctor)
234 f = resolveFuncCall(sc, loc, cd.ctor, null, null, arguments, 0);
235 if (f)
236 {
237 checkDeprecated(sc, f);
238 member = f.isCtorDeclaration();
239 assert(member);
240
241 cd.accessCheck(loc, sc, member);
242
243 tf = cast(TypeFunction)f.type;
244
245 if (!arguments)
246 arguments = new Expressions();
247 functionArguments(loc, sc, tf, arguments);
248 }
249 else
250 {
251 if (arguments && arguments.dim)
252 error("no constructor for %s", cd.toChars());
253 }
254
255 if (cd.aggNew)
256 {
257 // Prepend the size argument to newargs[]
258 Expression e = new IntegerExp(loc, cd.size(loc), Type.tsize_t);
259 if (!newargs)
260 newargs = new Expressions();
261 newargs.shift(cast(void*)e);
262
263 f = cd.aggNew.overloadResolve(loc, null, newargs);
264 allocator = f.isNewDeclaration();
265 assert(allocator);
266
267 tf = cast(TypeFunction)f.type;
268 functionArguments(loc, sc, tf, newargs);
269 }
270 else
271 {
272 if (newargs && newargs.dim)
273 error("no allocator for %s", cd.toChars());
274 }
275 }
276 else if (tb.ty == Tstruct)
277 {
278 TypeStruct ts = cast(TypeStruct)tb;
279 StructDeclaration sd = ts.sym;
280 TypeFunction tf;
281
282 FuncDeclaration f = null;
283 if (sd.ctor)
284 f = resolveFuncCall(sc, loc, sd.ctor, null, null, arguments, 0);
285 if (f)
286 {
287 checkDeprecated(sc, f);
288 member = f.isCtorDeclaration();
289 assert(member);
290
291 sd.accessCheck(loc, sc, member);
292
293 tf = cast(TypeFunction)f.type;
294 // type = tf.next;
295
296 if (!arguments)
297 arguments = new Expressions();
298 functionArguments(loc, sc, tf, arguments);
299 }
300 else
301 {
302 if (arguments && arguments.dim)
303 error("no constructor for %s", sd.toChars());
304 }
305
306 if (sd.aggNew)
307 {
308 // Prepend the uint size argument to newargs[]
309 Expression e = new IntegerExp(loc, sd.size(loc), Type.tuns32);
310 if (!newargs)
311 newargs = new Expressions();
312 newargs.shift(cast(void*)e);
313
314 f = sd.aggNew.overloadResolve(loc, null, newargs);
315 allocator = f.isNewDeclaration();
316 assert(allocator);
317
318 tf = cast(TypeFunction)f.type;
319 functionArguments(loc, sc, tf, newargs);
320 static if (false) {
321 e = new VarExp(loc, f);
322 e = new CallExp(loc, e, newargs);
323 e = e.semantic(sc);
324 e.type = type.pointerTo();
325 return e;
326 }
327 }
328 else
329 {
330 if (newargs && newargs.dim)
331 error("no allocator for %s", sd.toChars());
332 }
333
334 type = type.pointerTo();
335 }
336 else if (tb.ty == Tarray && (arguments && arguments.dim))
337 {
338 for (size_t j = 0; j < arguments.dim; j++)
339 {
340 if (tb.ty != Tarray)
341 {
342 error("too many arguments for array");
343 arguments.dim = i;
344 break;
345 }
346
347 Expression arg = cast(Expression)arguments.data[j];
348 arg = resolveProperties(sc, arg);
349 arg = arg.implicitCastTo(sc, Type.tsize_t);
350 arg = arg.optimize(WANTvalue);
351 if (arg.op == TOKint64 && cast(long)arg.toInteger() < 0)
352 error("negative array index %s", arg.toChars());
353 arguments.data[j] = cast(void*) arg;
354 tb = (cast(TypeDArray)tb).next.toBasetype();
355 }
356 }
357 else if (tb.isscalar())
358 {
359 if (arguments && arguments.dim)
360 error("no constructor for %s", type.toChars());
361
362 type = type.pointerTo();
363 }
364 else
365 {
366 error("new can only create structs, dynamic arrays or class objects, not %s's", type.toChars());
367 type = type.pointerTo();
368 }
369
370 //printf("NewExp: '%s'\n", toChars());
371 //printf("NewExp:type '%s'\n", type.toChars());
372
373 return this;
374 }
375
376 Expression optimize(int result)
377 {
378 if (thisexp)
379 thisexp = thisexp.optimize(WANTvalue);
380
381 // Optimize parameters
382 if (newargs)
383 {
384 for (size_t i = 0; i < newargs.dim; i++)
385 {
386 Expression e = cast(Expression)newargs.data[i];
387
388 e = e.optimize(WANTvalue);
389 newargs.data[i] = cast(void*)e;
390 }
391 }
392
393 if (arguments)
394 {
395 for (size_t i = 0; i < arguments.dim; i++)
396 {
397 Expression e = cast(Expression)arguments.data[i];
398
399 e = e.optimize(WANTvalue);
400 arguments.data[i] = cast(void*)e;
401 }
402 }
403 return this;
404 }
405
406 elem* toElem(IRState* irs)
407 {
408 elem* e;
409 Type t;
410 Type ectype;
411
412 //printf("NewExp.toElem() %s\n", toChars());
413 t = type.toBasetype();
414 //printf("\ttype = %s\n", t.toChars());
415 //if (member)
416 //printf("\tmember = %s\n", member.toChars());
417 if (t.ty == Tclass)
418 {
419 Symbol* csym;
420
421 t = newtype.toBasetype();
422 assert(t.ty == Tclass);
423 TypeClass tclass = cast(TypeClass)t;
424 ClassDeclaration cd = tclass.sym;
425
426 /* Things to do:
427 * 1) ex: call allocator
428 * 2) ey: set vthis for nested classes
429 * 3) ez: call constructor
430 */
431
432 elem *ex = null;
433 elem *ey = null;
434 elem *ez = null;
435
436 if (allocator || onstack)
437 {
438 elem *ei;
439 Symbol *si;
440
441 if (onstack)
442 {
443 /* Create an instance of the class on the stack,
444 * and call it stmp.
445 * Set ex to be the &stmp.
446 */
447 Symbol* s = symbol_calloc(toStringz(tclass.sym.toChars()));
448 s.Sclass = SCstruct;
449 s.Sstruct = struct_calloc();
450 s.Sstruct.Sflags |= 0;
451 s.Sstruct.Salignsize = tclass.sym.alignsize;
452 s.Sstruct.Sstructalign = cast(ubyte)tclass.sym.structalign;
453 s.Sstruct.Sstructsize = tclass.sym.structsize;
454
455 .type* tc = type_alloc(TYstruct);
456 tc.Ttag = cast(Classsym*)s; // structure tag name
457 tc.Tcount++;
458 s.Stype = tc;
459
460 Symbol *stmp = symbol_genauto(tc);
461 ex = el_ptr(stmp);
462 }
463 else
464 {
465 ex = el_var(allocator.toSymbol());
466 ex = callfunc(loc, irs, 1, type, ex, allocator.type,
467 allocator, allocator.type, null, newargs);
468 }
469
470 si = tclass.sym.toInitializer();
471 ei = el_var(si);
472
473 if (cd.isNested())
474 {
475 ey = el_same(&ex);
476 ez = el_copytree(ey);
477 }
478 else if (member)
479 ez = el_same(&ex);
480
481 ex = el_una(OPind, TYstruct, ex);
482 ex = el_bin(OPstreq, TYnptr, ex, ei);
483 ex.Enumbytes = cd.size(loc);
484 ex = el_una(OPaddr, TYnptr, ex);
485 ectype = tclass;
486 }
487 else
488 {
489 csym = cd.toSymbol();
490 ex = el_bin(OPcall,TYnptr,el_var(rtlsym[RTLSYM_NEWCLASS]),el_ptr(csym));
491 ectype = null;
492
493 if (cd.isNested())
494 {
495 ey = el_same(&ex);
496 ez = el_copytree(ey);
497 }
498 else if (member)
499 ez = el_same(&ex);
500 //elem_print(ex);
501 //elem_print(ey);
502 //elem_print(ez);
503 }
504
505 if (thisexp)
506 {
507 ClassDeclaration cdthis = thisexp.type.isClassHandle();
508 assert(cdthis);
509 //printf("cd = %s\n", cd.toChars());
510 //printf("cdthis = %s\n", cdthis.toChars());
511 assert(cd.isNested());
512 int offset = 0;
513 Dsymbol cdp = cd.toParent2(); // class we're nested in
514 elem* ethis;
515
516 //printf("member = %p\n", member);
517 //printf("cdp = %s\n", cdp.toChars());
518 //printf("cdthis = %s\n", cdthis.toChars());
519 if (cdp != cdthis)
520 {
521 int i = cdp.isClassDeclaration().isBaseOf(cdthis, &offset);
522 assert(i);
523 }
524 ethis = thisexp.toElem(irs);
525 if (offset)
526 ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYint, offset));
527
528 if (!cd.vthis)
529 {
530 error("forward reference to %s", cd.toChars());
531 }
532 else
533 {
534 ey = el_bin(OPadd, TYnptr, ey, el_long(TYint, cd.vthis.offset));
535 ey = el_una(OPind, TYnptr, ey);
536 ey = el_bin(OPeq, TYnptr, ey, ethis);
537 }
538 //printf("ex: "); elem_print(ex);
539 //printf("ey: "); elem_print(ey);
540 //printf("ez: "); elem_print(ez);
541 }
542 else if (cd.isNested())
543 {
544 /* Initialize cd.vthis:
545 * *(ey + cd.vthis.offset) = this;
546 */
547 ey = setEthis(loc, irs, ey, cd);
548 }
549
550 if (member)
551 // Call constructor
552 ez = callfunc(loc, irs, 1, type, ez, ectype, member, member.type, null, arguments);
553
554 e = el_combine(ex, ey);
555 e = el_combine(e, ez);
556 }
557 else if (t.ty == Tpointer && t.nextOf().toBasetype().ty == Tstruct)
558 {
559 Symbol* csym;
560
561 t = newtype.toBasetype();
562 assert(t.ty == Tstruct);
563 TypeStruct tclass = cast(TypeStruct)t;
564 StructDeclaration cd = tclass.sym;
565
566 /* Things to do:
567 * 1) ex: call allocator
568 * 2) ey: set vthis for nested classes
569 * 3) ez: call constructor
570 */
571
572 elem* ex = null;
573 elem* ey = null;
574 elem* ez = null;
575
576 if (allocator)
577 {
578 elem *ei;
579 Symbol *si;
580
581 ex = el_var(allocator.toSymbol());
582 ex = callfunc(loc, irs, 1, type, ex, allocator.type,
583 allocator, allocator.type, null, newargs);
584
585 si = tclass.sym.toInitializer();
586 ei = el_var(si);
587
588 if (cd.isNested())
589 {
590 ey = el_same(&ex);
591 ez = el_copytree(ey);
592 }
593 else if (member)
594 ez = el_same(&ex);
595
596 if (!member)
597 {
598 /* Statically intialize with default initializer
599 */
600 ex = el_una(OPind, TYstruct, ex);
601 ex = el_bin(OPstreq, TYnptr, ex, ei);
602 ex.Enumbytes = cd.size(loc);
603 ex = el_una(OPaddr, TYnptr, ex);
604 }
605 ectype = tclass;
606 }
607 else
608 {
609 ulong elemsize = cd.size(loc);
610
611 // call _d_newarrayT(ti, 1)
612 e = el_long(TYsize_t, 1);
613 e = el_param(e, type.getTypeInfo(null).toElem(irs));
614
615 int rtl = t.isZeroInit(Loc(0)) ? RTLSYM_NEWARRAYT : RTLSYM_NEWARRAYIT;
616 e = el_bin(OPcall,TYdarray,el_var(rtlsym[rtl]),e);
617
618 // The new functions return an array, so convert to a pointer
619 // ex . (unsigned)(e >> 32)
620 e = el_bin(OPshr, TYdarray, e, el_long(TYint, 32));
621 ex = el_una(OP64_32, TYnptr, e);
622
623 ectype = null;
624
625 if (cd.isNested())
626 {
627 ey = el_same(&ex);
628 ez = el_copytree(ey);
629 }
630 else if (member)
631 ez = el_same(&ex);
632 //elem_print(ex);
633 //elem_print(ey);
634 //elem_print(ez);
635 }
636
637 if (cd.isNested())
638 {
639 /* Initialize cd.vthis:
640 * *(ey + cd.vthis.offset) = this;
641 */
642 ey = setEthis(loc, irs, ey, cd);
643 }
644
645 if (member)
646 {
647 // Call constructor
648 ez = callfunc(loc, irs, 1, type, ez, ectype, member, member.type, null, arguments);
649 version (STRUCTTHISREF) {
650 /* Structs return a ref, which gets automatically dereferenced.
651 * But we want a pointer to the instance.
652 */
653 ez = el_una(OPaddr, TYnptr, ez);
654 }
655 }
656
657 e = el_combine(ex, ey);
658 e = el_combine(e, ez);
659 }
660 else if (t.ty == Tarray)
661 {
662 TypeDArray tda = cast(TypeDArray)t;
663
664 assert(arguments && arguments.dim >= 1);
665 if (arguments.dim == 1)
666 {
667 // Single dimension array allocations
668 Expression arg = cast(Expression)arguments.data[0]; // gives array length
669 e = arg.toElem(irs);
670 ulong elemsize = tda.next.size();
671
672 // call _d_newT(ti, arg)
673 e = el_param(e, type.getTypeInfo(null).toElem(irs));
674 int rtl = tda.next.isZeroInit(Loc(0)) ? RTLSYM_NEWARRAYT : RTLSYM_NEWARRAYIT;
675 e = el_bin(OPcall,TYdarray,el_var(rtlsym[rtl]),e);
676 }
677 else
678 {
679 // Multidimensional array allocations
680 e = el_long(TYint, arguments.dim);
681 for (size_t i = 0; i < arguments.dim; i++)
682 {
683 Expression arg = cast(Expression)arguments.data[i]; // gives array length
684 e = el_param(arg.toElem(irs), e);
685 assert(t.ty == Tarray);
686 t = t.nextOf();
687 assert(t);
688 }
689
690 e = el_param(e, type.getTypeInfo(null).toElem(irs));
691
692 int rtl = t.isZeroInit(Loc(0)) ? RTLSYM_NEWARRAYMT : RTLSYM_NEWARRAYMIT;
693 e = el_bin(OPcall,TYdarray,el_var(rtlsym[rtl]),e);
694 }
695 }
696 else if (t.ty == Tpointer)
697 {
698 TypePointer tp = cast(TypePointer)t;
699 ulong elemsize = tp.next.size();
700 Expression di = tp.next.defaultInit(Loc(0));
701 ulong disize = di.type.size();
702
703 // call _d_newarrayT(ti, 1)
704 e = el_long(TYsize_t, 1);
705 e = el_param(e, type.getTypeInfo(null).toElem(irs));
706
707 int rtl = tp.next.isZeroInit(Loc(0)) ? RTLSYM_NEWARRAYT : RTLSYM_NEWARRAYIT;
708 e = el_bin(OPcall,TYdarray,el_var(rtlsym[rtl]),e);
709
710 // The new functions return an array, so convert to a pointer
711 // e . (unsigned)(e >> 32)
712 e = el_bin(OPshr, TYdarray, e, el_long(TYint, 32));
713 e = el_una(OP64_32, t.totym(), e);
714 }
715 else
716 {
717 assert(0);
718 }
719
720 el_setLoc(e,loc);
721 return e;
722 }
723
724 bool checkSideEffect(int flag)
725 {
726 assert(false);
727 }
728
729 void toCBuffer(OutBuffer buf, HdrGenState* hgs)
730 {
731 assert(false);
732 }
733
734 void scanForNestedRef(Scope sc)
735 {
736 assert(false);
737 }
738
739 version (DMDV2) {
740 bool canThrow()
741 {
742 return 1;
743 }
744 }
745
746 //int inlineCost(InlineCostState *ics);
747
748 Expression doInline(InlineDoState ids)
749 {
750 //printf("NewExp.doInline(): %s\n", toChars());
751 NewExp ne = cast(NewExp)copy();
752
753 if (thisexp)
754 ne.thisexp = thisexp.doInline(ids);
755 ne.newargs = arrayExpressiondoInline(ne.newargs, ids);
756 ne.arguments = arrayExpressiondoInline(ne.arguments, ids);
757 return ne;
758 }
759
760 //Expression inlineScan(InlineScanState *iss);
761 }
762